package testprocs;

import simulator.*;
import modules.color.*;
import modules.broadcast.*;
import modules.region.*;
import utils.*;
import java.awt.*;
import java.util.*;

// broadcast testing

public class BCTestProc implements ProcessorModule {
  Broadcast bc; RegionManager rm;
  public Symbol getName() { return Symbol.GetSymbol("BCTestProc"); }
  public void link(PortedProcessor p) {
    pp = p;
    pp.addClockListener(this);
    pp.openNetworkPort(this,uiPort);
    bc = (Broadcast)p.getModule("Broadcast");
    bc.openBroadcastPort(this,port);
    rm = (RegionManager)p.getModule("RegionManager");
    cm = (ColorModule)p.getModule("Color");
  }

  PortedProcessor pp; ColorModule cm;

  static final Symbol uiPort = Symbol.GetSymbol("UI");
  static final Symbol port = Symbol.GetSymbol("testPort");

  public void init() {
  }

  Object value="";
  Hashtable pending = new Hashtable();
  public boolean signalEvent(Symbol name,Object data) {
    boolean dirty = false;
    if(name==uiPort) {
      StringTokenizer tok = new StringTokenizer(data.toString());
      if(tok.hasMoreTokens()) { 
        String cmd=tok.nextToken();
        if(cmd.equals("broadcast")) {
          Symbol s = Symbol.GetSymbol("default");
          Symbol r = RegionManager.rootID;
          value=s;
          if(tok.hasMoreTokens()) {
            s = Symbol.GetSymbol(tok.nextToken());
            if(s.equals("area")) {
              value=new AreaQuery();
            } else {
              value=s;
            }
            if(tok.hasMoreTokens()) { r=Symbol.GetSymbol(tok.nextToken()); }
          }
          pending.put(bc.broadcast(port,value,r),value);
          System.out.println("Node "+pp.getUID()+" Broadcasting "+value);
        } else if(cmd.equals("region")) {
          // "region A" means turn on A. "region A kill" means turn off A
          Symbol s = Symbol.GetSymbol("default");
          if(tok.hasMoreTokens()) {
            s = Symbol.GetSymbol(tok.nextToken());
            if(tok.hasMoreTokens()) {
              String type = tok.nextToken();
              if(type.equals("kill")) {
                rm.killRegion(s);
              } else if(type.equals("fill")) {
                rm.addRegion(s,"test",new UnlimitedRegion());
              }
            } else {
              rm.addRegion(s,"test",new LatchedRegion(s));
            }
          }
        }
      }
    } else if(name==port) {
      value=data;
    } else if(name==PortedProcessor.kTransmit) {
      Pair p = (Pair)((Pair)data).cdr();
      Object key = p.car(); Object ack = p.cdr();
      if(pending.containsKey(key)) {
        System.out.println("Broadcast Ack at Node "+pp.getUID()+" for message "
                           +pending.get(key)+": "+ack);
        //if(pending.get(key) instanceof AreaQuery)
        //  pending.put(bc.broadcast(port,ack),ack);
        pending.remove(key);
      }
    } else if(name==PortedProcessor.kClock) {
      int t = ((Integer)data).intValue();

      // coloring: state
      int state=bc.debugState();
      switch(state) {
      case -1: {
        if(rm.numRegions()>1) {
          cm.setColor(Color.gray);
        } else { 
          cm.setColor(Color.blue); 
        } break;
      }
      case 0: cm.setColor(Color.magenta); break;
      case 1: cm.setColor(Color.red); break;
      case 2: cm.setColor(dkGreen); break;
      case 3: cm.setColor(Color.green); break;
      case 4: cm.setColor(Color.yellow); break;
      case 5: cm.setColor(Color.cyan); break;
      case 6: cm.setColor(Color.orange); break;
      }
    }
    return dirty;
  }
  static Color dkGreen = Color.green.darker().darker();
  static Color ltBlue = Color.blue.brighter().brighter();

  public String toString() {
    return "BCTestProc "+value+"   (pending sends: "+pending+")";
  }
}

