package simulator;

import utils.*;
import java.util.*;
import java.awt.*;

public class ProcessorDisplayManager implements Observer, NodeColorModel {
  // this is an observer of processors and manager of the display output
  // it records all the images of the processors and, when they change,
  // makes sure they get redrawn properly
  SimViewer view;
  Simulator sim;
  NodeColorModel colormodel;
  Hashtable cache = new Hashtable();

  public ProcessorDisplayManager(SimViewer view, Simulator sim) {
    this.view = view; this.sim = sim;
    sim.addObserver(this);
    EmbeddedNetwork net = sim.getNet();
    Enumeration e = net.getNodes();
    while(e.hasMoreElements()) {
      Processor p = (Processor)e.nextElement();
      // hook processor into viewer
      addProcToViewer(p);
    }
    view.setColorModel(this);
  }

  private void addProcToViewer(Processor p) {
    EmbeddedNetwork net = sim.getNet();
    p.addObserver(this);
    view.addNode(p,net.getLocation(p));
    Enumeration e2 = net.getNeighbors(p);
    while(e2.hasMoreElements()) {
      Processor nbr = (Processor)e2.nextElement();
      view.addLink(p,nbr);
    }
  }

  public void setColorModel(NodeColorModel cm) { colormodel = cm; }

  public void update(Observable o, Object arg) {
    if(o instanceof Processor) {
      Processor p = (Processor)o;
      updateDisplay(p);
    } else if(o instanceof Simulator) {
      if(arg instanceof Pair) {
        Processor oldp = (Processor)((Pair)arg).car();
        Processor newp = (Processor)((Pair)arg).cdr();
        view.removeNode(oldp);
        addProcToViewer(newp);
      } // else do nothing
    } else {
      System.out.println("What the hell am I observing?");
    }
  }

  synchronized void updateDisplay(Processor p) {
    // show the links first
    EmbeddedNetwork net = sim.getNet();
    Enumeration e = net.getNeighbors(p);
    while(e.hasMoreElements()) {
      Processor nbr = (Processor)e.nextElement();
      Color c = defaultLink;
      if(colormodel!=null) c = colormodel.getLinkColor(p,nbr);
      if(!c.equals(getLinkColor(p,nbr))) {
        cache.put(new Pair(p,nbr),c);
        view.paintLink(p,nbr);
      }
    }

    // show the node second 
    NodeImage ni = defaultNode;
    if(colormodel!=null) ni = colormodel.getNodeImage(p);
    if(!ni.equals(getNodeImage(p))) {
      cache.put(p,ni);
      view.paintNode(p);
    }
  }

  static Color defaultLink = Color.darkGray;
  static NodeImage defaultNode = new NodeImage();
  public Color getLinkColor(Object a,Object b) {
    Color c = (Color)cache.get(new Pair(a,b));
    if(c!=null) return c; else return defaultLink;
  }
  public NodeImage getNodeImage(Object o) {
    NodeImage ni = (NodeImage)cache.get(o);
    if(ni!=null) return ni; else return defaultNode;
  }
}
