package simulator;

import java.util.*;
import java.awt.*; 
import java.awt.event.*; 
import javax.swing.*; 
import java.awt.geom.*;

public class SimViewer extends JPanel {
  
  Hashtable nodes;
  Hashtable links;
  boolean showLinks = true;
  NodeColorModel colormodel = null;
  int flysize = 4;

  public SimViewer() {
    nodes = new Hashtable();
    links = new Hashtable();
    setOpaque(true);
    setBackground(Color.black);
  }

  // accessors
  public void setFlySize(int s) { flysize = s; }
  public int getFlySize() { return flysize; }
  public void setShowLinks(boolean s) { showLinks = s; }
  public void setColorModel(NodeColorModel cm) { colormodel = cm; }
  public void addLink(Object a, Object b) {
    Vector nbrs;

    nbrs = (Vector)links.get(a);
    if(nbrs == null) { nbrs = new Vector(); links.put(a,nbrs); }
    nbrs.add(b);
    
    nbrs = (Vector)links.get(b);
    if(nbrs == null) { nbrs = new Vector(); links.put(b,nbrs); }
    nbrs.add(a);
  }
  public void addNode(Object o,Point2D loc) {
    nodes.put(o,loc);
    links.put(o,new Vector());
  }
  public void removeNode(Object o) {
    nodes.remove(o); // purge node
    Vector v = (Vector)links.remove(o); // purge links
    Iterator i = v.iterator();
    while(i.hasNext()) {
      Vector nbrs = (Vector)links.get(i.next());
      if(nbrs != null)
        nbrs.remove(o); // purge from reciprocal links
    }
  }

  // the paint function, and helpers
  public void paintComponent(Graphics g) {
    setOpaque(true);
    setBackground(Color.black);
    super.paintComponent(g);  //paint background
    if(colormodel != null) {
      if(showLinks) paintLinks(g);
      paintNodes(g);
    }
  }
  // this will doublepaint, but who's counting?
  private void paintLinks(Graphics g) {
    Iterator i = links.keySet().iterator();
    while(i.hasNext()) {
      Object n1 = i.next();
      Iterator j = ((Vector)links.get(n1)).iterator();
      while(j.hasNext()) {
        Object n2 = j.next();
        paintLink(n1,n2,g);
      }
    }
  }
  private void paintNodes(Graphics g) {
    Iterator i = nodes.keySet().iterator();
    while(i.hasNext()) {
      Object n = i.next();
      paintNode(n,g);
    }
  }

  public int getCanvasWidth() { return super.getWidth()-flysize; }
  public int getCanvasHeight() { return super.getHeight()-flysize; }

  // painting callins for partial updates
  public void paintLink(Object a, Object b) {
    if(!showLinks) return;
    Graphics g = getGraphics();
    if(g != null && colormodel != null) paintLink(a,b,g);
  }
  public void paintNode(Object n) {
    Graphics g = getGraphics();
    if(g != null && colormodel != null) paintNode(n,g);
  }
  // at long last, the actual painting procedures!
  private void paintLink(Object a, Object b,Graphics g) {
    int canvasHeight = getCanvasHeight();
    int canvasWidth = getCanvasWidth();
    Point2D loc1 = (Point2D)nodes.get(a);
    Point2D loc2 = (Point2D)nodes.get(b);
    if(loc1==null || loc2==null) return;
    int x1 = (int)(loc1.getX()*canvasWidth+flysize/2.0);
    int y1 = (int)(loc1.getY()*canvasHeight+flysize/2.0);
    int x2 = (int)(loc2.getX()*canvasWidth+flysize/2.0);
    int y2 = (int)(loc2.getY()*canvasHeight+flysize/2.0);
    
    g.setColor(colormodel.getLinkColor(a,b));
    g.drawLine(x1,y1,x2,y2);
  }
  public void paintNode(Object n,Graphics g) {
    int canvasHeight = getCanvasHeight();
    int canvasWidth = getCanvasWidth();
    Point2D loc = (Point2D)nodes.get(n);
    int x = (int)(loc.getX()*canvasWidth);
    int y = (int)(loc.getY()*canvasHeight);

    NodeImage ni = colormodel.getNodeImage(n);
    g.setColor(ni.core);
    g.fillRect(x,y,flysize,flysize);
    g.setColor(ni.rim);
    g.drawRect(x,y,flysize,flysize);
    if(ni.ring != null) {
      g.setColor(ni.ring);
      g.drawRect(x-1,y-1,flysize+2,flysize+2);
    }
    if(ni.hasRays()) {
      int cx = x+flysize/2;
      int cy = y+flysize/2;
      Iterator i = ni.getRays();
      while(i.hasNext()) {
        NodeImageRay r = (NodeImageRay)i.next();
        double xp = Math.cos(2*Math.PI*r.phase);
        double yp = Math.sin(2*Math.PI*r.phase);
        double length = 2*flysize;
        g.setColor(r.color);
        g.drawLine(cx,cy,(int)(cx+(xp*length)),(int)(cy+(yp*length)));
      }
    }
  }
}
