import java.awt.*;
//import javax.swing.*;

// Module 1 Exercise 3
public class Mod3Plot extends Panel {

    Mod3State state;

    int[] xList, yList;
    int[] yList2, yList3, yList4;
    int[] xList2;
    int yMin, yMax, xMin, xMax, yMid;
    int yBorder, yOffset;

    //private static final Color bgColor = Color.gray;
    private static final Color bgColor = new Color(236,236,236);

    static int degreesPerX = 5;
    static int ncycles = 3;
    static int npts = ncycles*(360/degreesPerX);

    static double piOver4 = Math.PI/4;
    double deltaY, deltaX;
    FontMetrics fm;
    int fontHeight,ticLength;
    //static Font boldFont = new Font("Serif",Font.BOLD, 18);
    

    public Mod3Plot(Mod3State state) {
        super();
        this.state = state;
    }

    public void initialPlot() {
        setBackground(bgColor);
        getPoints();
        deltaY = (yMax - yMin)/10.0;
        deltaX = (xMax - xMin)/6.0;
        // Get font sizes:
        //setFont(boldFont);
        setFont(TheFonts.sanSerif12);
        fm = getFontMetrics(getFont());
        fontHeight = fm.getHeight();
        ticLength  = fm.stringWidth("w"); // just a wide letter.
        
        xList2 = new int[xList.length];
        for (int i = 0; i < xList.length; i++)
            xList2[i] = xList[i]+1;
        
        repaint();
    }


    
    private void getPoints() {
        double xPoint, yPoint, xInRadians;
        xList = new int[npts];
        yList = new int[npts];
        yList2 = new int[npts];
        yList3 = new int[npts];
        yList4 = new int[npts];
        
        // create a wave with y in (-100,100), x in (0,600)
        for (int i = 0; i < xList.length; i++) {
            xPoint = ((double)i*degreesPerX)/180;
            xList[i] = (int) (xPoint*state.s100); // scale x so 360 degress spans 200
            // each x point == 'degreesPerX' degrees; 180 degrees = pi(radians)
            xInRadians = xPoint * 3.1415927;
            yPoint = Math.cos(xInRadians);
            //yList[i] = (int) (yPoint*100); // scale y from -100 to 100
            yList[i] = (int) (yPoint*state.s150); // scale y from -100 to 100
            yPoint = Math.cos(xInRadians+piOver4);
            //yList2[i] = (int) (yPoint*100); // scale y from -100 to 100
            yList2[i] = (int) (yPoint*state.s150); // scale y from -100 to 100
            yPoint = Math.sin(xInRadians);
            //yList3[i] = (int) (yPoint*100); // scale y from -100 to 100
            yList3[i] = (int) (yPoint*state.s150); // scale y from -100 to 100
            yPoint = -1.0 * Math.cos(xInRadians-piOver4);
            //yList4[i] = (int) (yPoint*100); // scale y from -100 to 100
            yList4[i] = (int) (yPoint*state.s150); // scale y from -100 to 100
        }
        
        // where to draw on the screen:
        yOffset = state.s15;
        //yBorder = 15;
        yBorder = state.s5;
        //xMin = 35; xMax = (200 * ncycles) + xMin;
        xMin = state.s85; xMax = (state.s200 * ncycles) + xMin;
        yMin = yBorder+yOffset; 
        //yMax = 200+yBorder+yOffset; 
        yMax = state.s300+yBorder+yOffset; 
        yMid = (int)(0.5*(yMax+yMin));
        
        // NOW push the sine wave DOWN on the Y-axis, so that the sine
        //  wave appears in the middle of the screen, rather that at the TOP
        for (int i = 0; i < yList.length; i++) {
            yList[i] += yMid;
            yList2[i] += yMid;
            yList3[i] += yMid;
            yList4[i] += yMid;
        }
        flipCoordinates(yList,yMid);
        flipCoordinates(yList2,yMid);
        flipCoordinates(yList3,yMid);
        flipCoordinates(yList4,yMid);
        // NOW shift the X-axis over by xMin to make room for the vertical
        //  axis line.
        for (int i = 0; i < xList.length; i++)
            xList[i] += xMin;
    }
    

  private void flipCoordinates(int[] coords, int flipAround) {
    int delta;
    for (int i = 0; i < coords.length; i++) {
      delta = coords[i] - flipAround;
      coords[i] = flipAround - delta;
    }
  }

  public void paint(Graphics g) {
        Graphics2D g2d = (Graphics2D)g;
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                             RenderingHints.VALUE_ANTIALIAS_ON);
        
    // Draw x and y axis:
    drawAxis(g);
    // Draw axis tick marks:
    drawAxisTicks(g);
    // calculate the sine points first:
    //  by getting bounds, and scaling x to get about 5 up-and-down
    //  curves
    //....
    

      g2d.setStroke(new BasicStroke(3,BasicStroke.CAP_ROUND,
                                    BasicStroke.JOIN_ROUND));

    g.setColor(state.yListColor);
    g.drawPolyline(xList,yList,yList.length);
    g.drawPolyline(xList2,yList,xList2.length);
    if (yList2 != null) {
      g.setColor(state.yList2Color);
      g.drawPolyline(xList,yList2,yList2.length);
      g.drawPolyline(xList2,yList2,xList2.length);
    }
    if (yList3 != null) {
      g.setColor(state.yList3Color);
      g.drawPolyline(xList,yList3,yList3.length);
      g.drawPolyline(xList2,yList3,xList2.length);
    }
    if (yList4 != null) {
      g.setColor(state.yList4Color);
      g.drawPolyline(xList,yList4,yList4.length);
      g.drawPolyline(xList2,yList4,xList2.length);
    }

    g2d.setStroke(new BasicStroke(1));
  }
  

  private void drawAxis(Graphics g) {
    Graphics2D g2d = (Graphics2D)g;
    g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                           RenderingHints.VALUE_ANTIALIAS_ON);     
    // Draw x and y axis:
    g.setColor(state.axisColor);
    
    g2d.setStroke(new BasicStroke(state.s0,BasicStroke.CAP_BUTT,
                                    BasicStroke.JOIN_ROUND));
        
    drawLine(g,xMin,yOffset,xMin,yMax+yBorder); // the y-axis
    drawLine(g,xMin,yMid,xMax+yBorder-state.s3,yMid); // the x-axis
    
    g2d.setStroke(new BasicStroke(state.s0,BasicStroke.CAP_BUTT,
                                    BasicStroke.JOIN_ROUND));
    MyArrows.drawDblUpArrow(g,xMin,yOffset-state.s7,state.sfactor);
    MyArrows.drawDblDownArrow(g,xMin,yMax+yBorder+state.s7,state.sfactor);
    MyArrows.drawDblRightArrow(g,xMax+yBorder,yMid,state.sfactor);
  }

  private void drawLine(Graphics g, int x1, int y1, int x2, int y2) {
      if (y1 != y2) {
          g.drawLine(x1,y1,x2,y2);
          //g.drawLine(x1+1,y1,x2+1,y2);
      } else {
          g.drawLine(x1,y1,x2,y2);
          //g.drawLine(x1,y1+1,x2,y2+1);
      }
  }

  private void drawAxisTicks(Graphics g) {
        Graphics2D g2d = (Graphics2D)g;
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                           RenderingHints.VALUE_ANTIALIAS_ON);  
        
        g2d.setStroke(new BasicStroke(state.s0,BasicStroke.CAP_ROUND,
                                    BasicStroke.JOIN_ROUND));
        
    // Draw x and y axis:
    g.setColor(state.axisColor);
    
    g.setFont(new Font("SanSerif",Font.BOLD,state.font14));
    FontMetrics fm;
    fm = g.getFontMetrics();

    for(int i=0;i<11;i++){
      int y = (int)(i*deltaY)+yOffset+yBorder;
      g.drawLine(xMin-ticLength,y,xMin,y);
      int v = 5-i;
      if (v == 5 || v == -5) {
        String vs = String.valueOf(v);
        g.drawString(vs,xMin-ticLength-fm.stringWidth(vs)-5,
                        y+(int)(0.5*fontHeight));
      }
    }
    //g.drawString("[Volts]",xMin+ticLength,(int)(1.5*fontHeight)+yOffset-10);
    g.drawString("[Volts]",xMin+ticLength,(int)(1.5*fontHeight)+yOffset-state.s18);


    // On the x-axis:
    // dots per cm:
    int screenRes = (int) (getToolkit().getScreenResolution()/2.54);
    for(int i=1;i<50;i++){
      int x = (int)(i*screenRes) +xMin;
      if( x > xMax) break;
      g.drawLine(x,yMid+ticLength,x,yMid);
      String xs = String.valueOf(i);
      g.drawString(xs,x-(int)(0.5*fm.stringWidth(xs)),
                      yMid+ticLength+fontHeight);
    }
    //g.drawString("t[sec]",xMax+yBorder-fm.stringWidth("t[sec]"),yMid+fontHeight+5);
    g.drawString("t [sec]",xMax-fm.stringWidth("t[sec]")+state.s15,yMid-state.s10);

  }
}
