package curve;

import curve.*;
import java.awt.*;

//Parametric draw curve will draw lines out from current point to
//sides of screen when animating the curve, to link with a
//(y,t)  and (x,t) parametricdrawcurve
public class ParametricDrawCurve extends DrawCurve {
  protected int tAxis; //tAxis 0=neither 1=x 2=y
  protected int tAxisPos; //Screen coordinate of t Axis
  //Constants for tAxisPos
  public static final int tNeitherAxis=0;
  public static final int tXAxis=1;
  public static final int tYAxis=2;

  protected boolean lineToLeft,lineToRight,lineToTop,lineToBottom,lineToTAxis;
  //line constructs to draw during animation
  
  //When this instance is asked to draw its curve, animate etc, it tells
  //these friends to do so too.
  protected ParametricDrawCurve friend1,friend2;
    
//--------------------------------------------------------------------  
// Initialisation  
//--------------------------------------------------------------------    
  //Initialisation requires where the t axis is, two friends (or null),
  //and 5 parameters for construction lines to be drawn
  public ParametricDrawCurve(int aTAxis,
    ParametricDrawCurve aFriend1, ParametricDrawCurve aFriend2,
    boolean aLineToLeft,boolean aLineToRight,boolean aLineToTop,
    boolean aLineToBottom,boolean aLineToTAxis) {
    super(); //Normal drawCurve set up
    System.out.println("Version"+version);
    friend1=aFriend1;
    friend2=aFriend2;
    tAxis=aTAxis;
    lineToLeft=aLineToLeft;
    lineToRight=aLineToRight;
    lineToTop=aLineToTop;
    lineToBottom=aLineToBottom;
    lineToTAxis=aLineToTAxis;
  }

//--------------------------------------------------------------------  
// Drawing Curve  
//--------------------------------------------------------------------    
  //Paint routine draws curves from data received from Curve object
  public void paint(Graphics newG) {
    Rectangle graphicsBounds;
    g=getGraphics();//newG //Set global graphics to newG
    graphicsBounds=getBounds();
    g.setPaintMode();
    if(animateOn) { //Not really neccessary, as no cleaning up needed for
      animateOn=false; //these parametrics
      cleanAnimate();
    };
    g.setColor(Color.white);
    g.clearRect(0,0,graphicsBounds.width-1,graphicsBounds.height-1);
    g.setColor(Color.lightGray);
    g.drawRect(0,0,graphicsBounds.width-1,graphicsBounds.height-1);

    if(curves.getFirstCurve()!=null) {
      g.setXORMode(Color.white);
      g.setColor(Color.black);
      setForeground(new Color(0));
      //Get min max values of curve
      getMinMax();
    
      //if curve is wider than 0 pixels in boths directions
      if(curveRect.width>0 && curveRect.height>0) {
        getGraphBounds(); //Get graph drawing area to clipBounds
        rescaleXYAxes(); //Make X,Y axes same scale
  
        //For t axes, range is 0 to 1.  Same other range applies
        if(tAxis==tXAxis) {
          curveRect.x=0;
          curveRect.width=1;
        };
        if(tAxis==tYAxis) {
          curveRect.y=0;
          curveRect.height=1;
        };
    
        //Draw axes
        drawAxes();

        //Draw Curves
        drawCurves();
      };
      //Request repaint for friends
      if(friend1!=null) friend1.repaint();
      if(friend2!=null) friend2.repaint();
    };
    //Set text location
    animateTextX=clipBounds.x;
    animateTextY=clipBounds.y+clipBounds.height+37;
    animateRight=getBounds().width-1;
    animateBottom=getBounds().height-1;
  };

  //Draws the curve
  protected void drawCurve(Curve curve) {
    Coordinate point;
    double param; //Parameter, between 0 and 1, to pass to Curve
    int ctr;
    int x[],y[];
    
    x=new int[numPoints+1];
    y=new int[numPoints+1];
    
    if(curve!=null) {
      g.setColor(curve.color);
      param=0;
      for(ctr=0;ctr<=numPoints;ctr++) {
        point=curve.getValue(param);
        if(tAxis==tXAxis) x[ctr]=curveToClipX(param);
          else x[ctr]=curveToClipX(point.x);
        if(tAxis==tYAxis) y[ctr]=curveToClipY(param);
          else y[ctr]=curveToClipY(point.y);
        param+=pointStep;
      };
      g.drawPolyline(x,y,numPoints+1);
    };
    curves.setCurveXY(curve,x,y);
  };

  //Draw Curves
  protected void drawCurves() {
    Curve currentCurve;
    g=getGraphics();
    g.setXORMode(Color.white);

    //Hide animation if that's on; hide constructs too
    if(animateOn==true) {
      drawAnimateCurves();
      hideWriting();
      currentCurve=curves.getFirstCurve();
      if(currentCurve!=null)
      do {
        g.setColor(currentCurve.color);
        //Draw construction
        if(tAxis==tNeitherAxis) currentCurve.drawConstructs();
      } while((currentCurve=curves.getNextCurve(currentCurve))!=null);
      animateOn=false;
    } else {
      currentCurve=curves.getFirstCurve();
      if(animatePanel!=null) animatePanel.reset();

      currentCurve=curves.getFirstCurve();
      if(currentCurve!=null)
      do {
        g.setColor(currentCurve.color);
        drawCurve(currentCurve);
        //Draw construction
        if(tAxis==tNeitherAxis) currentCurve.drawConstructs();
      } while((currentCurve=curves.getNextCurve(currentCurve))!=null);
    };
  };

  
  //Override to show t instead of x
  protected void makeXLabel(int xAxis,Font font,Font largerFont,
    AxisCalculator axis) {
    String sStart,s;
    int textX,textY;
    FontMetrics fontMetrics,largerFontMetrics;
    //Get two fontmetrics, one larger than the other
    fontMetrics=g.getFontMetrics(font);
    largerFontMetrics=g.getFontMetrics(largerFont);

    g.setPaintMode();
    //Make Power and x label
    if(tAxis==tXAxis) {
      tAxisPos=xAxis;
      sStart="t";
    } else sStart="X";
    textX=clipBounds.x+clipBounds.width;
    textY=xAxis+2*fontMetrics.getAscent();
    textY+=largerFontMetrics.getAscent();
    if(axis.labelPower==0) {
      //Draw "X" only
      s=sStart;
      textX-=largerFontMetrics.stringWidth(s);
      g.setFont(largerFont);
      g.drawChars(s.toCharArray(),0,s.length(),
      textX,textY);
    } else {
      g.setFont(font);

      s=new Long(axis.labelPower).toString();
      textX-=fontMetrics.stringWidth(s);
      //Draw power number
      g.drawChars(s.toCharArray(),0,s.length(),
      textX,textY-fontMetrics.getAscent());

      //Draw rest of string
      s=sStart+", *10";
      textX-=largerFontMetrics.stringWidth(s);
      g.setFont(largerFont);
      g.drawChars(s.toCharArray(),0,s.length(),
      textX,textY);
    };
    g.setFont(font);
    g.setXORMode(Color.white);
  };

  //Override to show t instead of y
  protected void makeYLabel(int yAxis,Font font,Font largerFont,
    AxisCalculator axis) {
    String sStart,s;
    int textX,textY;
    FontMetrics fontMetrics,largerFontMetrics;
    //Get two fontmetrics, one larger than the other
    fontMetrics=g.getFontMetrics(font);
    largerFontMetrics=g.getFontMetrics(largerFont);

    g.setPaintMode();
    //Make Power and y label
    if(tAxis==tYAxis) {
      tAxisPos=yAxis;
      sStart="t";
    }  else sStart="Y";
    textX=yAxis;
    textY=2*fontMetrics.getAscent();
    if(axis.labelPower==0) {
      //Draw "Y" only
      s=sStart;
      g.setFont(largerFont);
      g.drawChars(s.toCharArray(),0,s.length(),
      textX,textY);
    } else {
      //Draw start of string
      s=sStart+", *10";
      //Change textX if neccessary
      if(clipBounds.x+clipBounds.width-textX<largerFontMetrics.stringWidth(s)+
      fontMetrics.stringWidth(new Long(axis.labelPower).toString()))
      textX=clipBounds.x+clipBounds.width-largerFontMetrics.stringWidth(s)+
      fontMetrics.stringWidth(new Long(axis.labelPower).toString());

      g.setFont(largerFont);
      g.drawChars(s.toCharArray(),0,s.length(),
      textX,textY);

      textX+=largerFontMetrics.stringWidth(s);
      s=new Long(axis.labelPower).toString();
      //Draw power number
      g.setFont(font);
      g.drawChars(s.toCharArray(),0,s.length(),
      textX,textY-fontMetrics.getAscent());
    };
    g.setFont(font);
    g.setXORMode(Color.white);
  };
  
//--------------------------------------------------------------------  
// Animate curve  
//--------------------------------------------------------------------    
  private final double version=1.6;

  //For storing right and bottom of canvas, construction lines
  private int animateRight,animateBottom;
  
  //Draw special construction lines between canvases
  private synchronized void drawFrame(Curve curve,int x,int y) {
    g.setColor(curve.color);
    if(lineToLeft) g.drawLine(0,y,x,y);
    if(lineToRight) g.drawLine(x,y,animateRight,y);
    if(lineToTop) g.drawLine(x,0,x,y);
    if(lineToBottom) g.drawLine(x,y,x,animateBottom);
    if(lineToTAxis) {
      switch(tAxis) {
        case tXAxis:
          g.drawLine(x,tAxisPos,x,y);
          break;
        case tYAxis:
          g.drawLine(tAxisPos,y,x,y);
          break;
      };
    };
  };    
  
  protected synchronized void showWriting() {
    if(tAxis==tNeitherAxis) super.showWriting();
  };
  
  protected synchronized void hideWriting() {
    if(tAxis==tNeitherAxis) super.hideWriting();
  };

  protected synchronized void drawAnimateCurve(Curve curve,int x[],int y[]) {
    g.setColor(curve.color);
    g.drawPolyline(x,y,animateCtr+1);
    drawFrame(curve,x[animateCtr],y[animateCtr]);
  };    

  //Shows animation frames on friends too
  public synchronized void showAnimate(int newFrameNumber) {
    if(friend1!=null) friend1.showAnimate(newFrameNumber);
    if(friend2!=null) friend2.showAnimate(newFrameNumber);
    g=getGraphics();
    g.setXORMode(Color.white);
    //hide whatever's already there
    if(animateOn) {
      drawAnimateCurves();
      hideWriting();
    } else {
      drawCurvesOnly();//Hide curve
      animateOn=true;
    };
      
    //Show new image
    if(newFrameNumber==numPoints) {
      drawCurvesOnly();
      cleanAnimate();//Still cleaning up      
      animateOn=false;
      animateCtr=newFrameNumber;
    } else {
      animateCtr=newFrameNumber;
      drawAnimateCurves();
      showWriting();
    };
  };
  
}
