/* DiagramPanel class for Y hang applet */
/* Simeon Warner - 20May96 */

import java.awt.*;

public class DiagramPanel extends Canvas {
  final boolean _debug_ = false;

  Dimension mySize;

  //Stuff for grabbing and shifting an anchor or knot
  final int gotNothing = 0, gotLeft = 1, gotRight = 2, gotKnot = 3;
  int gotSomething = gotNothing ;

  //double-buffering
  private Image image2;
  private Graphics g2;
  
  Simulation simulation;

  DiagramPanel() {
    // nothing;
  }

  public void init(Simulation s) {
    simulation = s;
    repaint();

    /* this.size() doesn't work here */
    //mySize=this.size();
    /* Hence, it is not possible to create the second image space */
    //image2 = createImage(mySize.width,mySize.height);
    //g2=image2.getGraphics();

    this.setBackground(Color.gray);
    this.repaint();
  }


  public boolean handleEvent(Event evt) {
    switch (evt.id) {

    case Event.MOUSE_DOWN:
      // see about picking up an anchor
      if (onAnchor(evt.x, evt.y, simulation.xLeft, simulation.yLeft)) { 
        gotSomething = gotLeft; 
      } else {
        if (onAnchor(evt.x, evt.y, simulation.xRight, simulation.yRight)) { 
          gotSomething = gotRight;
        } else {
          if (onAnchor(evt.x, evt.y, simulation.xKnot, simulation.yKnot)) { 
            gotSomething = gotKnot;
          } else {
            gotSomething = gotNothing;
          }
        }
        //stop simulation if we have picked something up
        if (gotSomething != gotNothing) simulation.suspend();
      }
      return true;
  
    case Event.MOUSE_DRAG:
      /* drop item if we move outside the drawing area! */
      if ((evt.x<1) || (evt.x>(mySize.width-1)) ||
          (evt.y<1) || (evt.y>(mySize.height-1))) {
        gotSomething=gotNothing;
        simulation.checkSlack();
        simulation.resume();
      } else {
        switch (gotSomething) {
        case gotLeft:
          simulation.xLeft=evt.x; simulation.yLeft=evt.y;
          break;
        case gotRight:
          simulation.setRight(evt.x,evt.y);
          break;
        case gotKnot:
          simulation.setKnot(evt.x, evt.y);
          break;
        case gotNothing:
          break;
        default:
          System.out.println("Program error - bad case in Event.MOUSE_DRAG.");
         }
      } 
      repaint();
      return true;

    case Event.MOUSE_UP:
      switch (gotSomething) {
      case gotLeft:
      case gotRight:
      case gotKnot:
        simulation.checkSlack();
        simulation.resume();
        break;
      case gotNothing:
        break;
      default:
        System.out.println("Program error - bad case in Event.MOUSE_UP.");
      } 
      gotSomething = gotNothing;
      return true;

    case Event.MOUSE_MOVE:
      // do nothing
      return true;

   default:
      if (_debug_) System.out.println("Event not handled (" + evt.id + ").");      
      return false;
    }
  }
 
  
  private boolean onAnchor(int x1, int y1, int x2, int y2) {
    int aRadiusSqd = simulation.aradius*simulation.aradius;
    if (((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)) <= aRadiusSqd) return true;
    else return false;
  }


  public void update(Graphics g) {
    paint(g);
  }


  public void paint(Graphics g) {
    int xl,yl,xr,yr,xk,yk,r,d;
    boolean stable,slackLeft,slackRight;
    String sl,sr;
    float w,fl,fr,al,ar,tmp;
    /* If the second image doesn't exist then we must now create it, the
       size method will now give sensible answers so we may also set the
       default positions based on panel size.  It would be nicer to put 
        this bit of code elsewhere */
    if (g2 == null) paintSetup();
    /* grab data from the simulation */
    /* this could (and maybe should) be done using synchronized methods of simulation */
    synchronized(simulation) {
      xl=simulation.xLeft;  yl=simulation.yLeft;
      xr=simulation.xRight; yr=simulation.yRight;
      xk=simulation.xKnot;  yk=simulation.yKnot;
      r=(int)simulation.aradius; d=r+r;
      stable=simulation.stable;
      slackLeft=simulation.slackLeft; slackRight=simulation.slackRight;
    }
    w=simulation.getWeight();
    /* now lets paint a picture to the second buffer (g2) and then copy */
    g2.setColor(this.getBackground());
    mySize=this.size();
    g2.fillRect(0,0,mySize.width,mySize.height);
    g2.setColor(Color.blue);
    g2.fillOval(xl-r, yl-r, d, d);
    g2.fillOval(xr-r, yr-r, d, d);
    g2.drawLine(xl,yl,xk,yk);
    g2.drawLine(xk,yk,xr,yr);
    g2.drawLine(xk,yk,xk,mySize.height);
    /* Annotate */
    if (yk<=mySize.height) {
      g2.drawLine(xk,mySize.height,xk+r,mySize.height-r);
      g2.drawLine(xk,mySize.height,xk-r,mySize.height-r);
      g2.drawString(String.valueOf(w),xk+r,mySize.height-r);
    }
    if ( (((xk-xr)*(xk-xl))>0) || 
         (((xk-xl)*(yl-yr))<((xr-xl)*(yl-yk))) ||
         (!stable) ) {
      fl=Float.NaN; fr=Float.NaN;
    } else {
      if ((xk==xr) && (xk==xl) ) {
        if (slackLeft) { fl=Float.NaN; fr=w; }
        else if (slackRight) { fl=w; fr=Float.NaN; }
        else { fl=w/(float)2.0; fr=fl; }
      } else if (xk==xr) {
        fr=w; fl=(float)0.0;
        if (slackLeft) fl=Float.NaN;
      } else if (xk==xl) {
        fr=(float)0.0; fl=w;
        if (slackRight) fr=Float.NaN;
      } else {
        al=(float)(Math.atan2(yk-yl,xl-xk)-Math.PI/2.0);
        ar=(float)(Math.PI/2.0-Math.atan2(yk-yr,xr-xk));
        if ((float)Math.abs(tmp=(float)Math.sin(Math.PI-al-ar))<(float)0.02) {
          fl=Float.POSITIVE_INFINITY; fr=Float.POSITIVE_INFINITY;
        } else if (tmp<(float)0.0) {
          fl=Float.NaN; fr=Float.NaN;
        } else {
          fl=w/tmp*(float)Math.sin(ar);
          fr=w/tmp*(float)Math.sin(al);
        }
      }
    }
    if (Float.isInfinite(fl)) sl="!!!"; 
    else if (Float.isNaN(fl)) sl="?";
    else sl=String.valueOf((int)fl);
    if (Float.isInfinite(fr)) sr="!!!"; 
    else if (Float.isNaN(fr)) sr="?";
    else sr=String.valueOf((int)fr);
    g2.drawString(sl,xl+r,yl-r);
    g2.drawString(sr,xr+r,yr-r);
    /* Copy image to live version */
    g.drawImage(image2,0,0,this); 
  }
 

  private void paintSetup() {
    int min;
    mySize=this.size();
    /* Set initial positions of anchors and knot */
    if (mySize.width<mySize.height) min=mySize.width; else min=mySize.height;
    simulation.setLeft((5*mySize.width-3*min)/10,(5*mySize.height-3*min)/10);
    simulation.setRight((5*mySize.width+3*min)/10,(5*mySize.height-3*min)/10);
    simulation.setKnot(mySize.width/2,1);
    simulation.setAngle((float)90.0);
    /* Create second image space */
    image2 = createImage(mySize.width,mySize.height);
    g2=image2.getGraphics();
  }

}













