import java.awt.*;
import java.awt.event.*;
import java.awt.geom.Line2D;
import java.awt.geom.RoundRectangle2D;
import javax.swing.*;
import javax.swing.event.*;

public class Mod2Plot extends Panel implements MouseListener, Runnable,
                                               ChangeListener {

    Mod2State state;

    Point[] topOuter;
    Color[] currentIntensity;
    int[] arrowDirection;
    static int ARROW_UP = 1;
    static int ARROW_DOWN = 2;
    
    int current = 0;
    Point xAxisEndpt;
    Image main;
    Graphics imG;
    int mainWidth, mainHeight;
    
    // Need 2 different delta thetas because much shorter screen 
    // difference for the wire rectangle to travel through the 
    // y and x axis, than the x and -ve y axis, EVEN THOUGH the 
    // real-world distance is the same.  The solution is to use a small
    // delta theta for the short screen distances, and (3 times) larger
    // delta theta for the long screen distances.
    //
    // use short for 0 <= theta <= PI and PI <= theta < 3PI/2
    // use long for PI/2 <= theta < PI and 3PI/2 <= theta < 0
    private double deltaTheta = 0.5;
    private int xAxisAngle = 75;  // degrees
    int halfway;
    
    private int wireRectWidth = 125;
    private int wireRectHeight = 90;
    //static Point origin = new Point(150,220);
    private Point origin = new Point(370,220);
    private int zAxisLength = 125;
    private int yAxisLength = 150;
    private int xAxisLength = 150;
    private double PIOverOneEighty = Math.PI/180.0;
    private double PIhalf = Math.PI/2.0;

    //static Point graphOrigin = new Point(70,330);
    private Point graphOrigin = new Point(30,330);
    int[] ix, iy;
    int iLabelX, iLabelY;
    static Color iColor = Color.red;    
    int icurrent = 0;

    
    private Font boldFont = new Font("Serif",Font.BOLD, 18);
    
    int yBorder, yOffset;
    
    //AnimationTimer timer = new AnimationTimer(this, 50);
    
    
    private Thread tron;
    public boolean IsTronRunning;
    public boolean ThreadStarted;
    private int SleepTime = 50;  // was 25

    private double amplitudeScaler = 100.0;
    
    //static Color bgColor = new Color(194,235,255);
    private final Color bgColor = new Color(236,236,236);
    static Color axisColor = Color.black;
    static Color wireColor = Color.green.darker();
    
    FontMetrics fm;
    int fontHeight;
    Graphics2D g2d;
    
    
    public StartStopClock ssc;
    
    private Label fast, slow;   
    private static final Color maroon = new Color(185,50,50);
    public JSlider slider;
    private int SCROLLMIN=0, SCROLLMAX=250;
    
    public Mod2Plot(Mod2State state) {
           super();
           this.state = state;
           IsTronRunning = false;
           ThreadStarted = false;
           setLayout(null);
           setBackground(bgColor);

            wireRectWidth = state.s125;
            wireRectHeight = state.s90;
            //origin = new Point(state.s370,state.s220);
            origin = new Point(state.s275,state.s145);
            zAxisLength = state.s125;
            yAxisLength = state.s150;
            xAxisLength = state.s150;
            PIOverOneEighty = Math.PI/180.0;
            PIhalf = Math.PI/2.0;
            //graphOrigin = new Point(state.s30,state.s330);
            graphOrigin = new Point(state.s190,state.s340);
           getPoints();
           getGraphPoints();
           icurrent = ix.length/4;


           ssc  = new StartStopClock(state);
           ssc.button1.setEnabled(true);
           ssc.button2.setEnabled(true);
           add(ssc);

           //start stop clock
           ssc.setBounds(state.s318,state.s480,state.s194,state.s60); 
           ssc.button1.addMouseListener(this);
           ssc.button2.addMouseListener(this);


           setupSpeedAdjust();


           IsTronRunning = false;
           ThreadStarted = false;


           // Get font sizes:
           setFont(boldFont);
           fm = getFontMetrics(getFont());
           fontHeight = fm.getHeight();
    }

   public synchronized void initialPlot() {
       state.reset();
       ssc.clockcanvas.setStatus(0,state.NTime,state.dtime);
       ssc.clockcanvas.reset();


       //mainWidth = origin.x+yAxisLength+40;
       //mainHeight = xAxisEndpt.y+60+fontHeight+10;
       mainWidth = state.s540;
       mainHeight = state.s530 - state.s80;
       //main = createImage(mainWidth, mainHeight);
       //imG = main.getGraphics();

        GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
        GraphicsDevice gs = ge.getDefaultScreenDevice(); 
        GraphicsConfiguration gc = gs.getDefaultConfiguration();
        main = gc.createCompatibleImage(mainWidth, mainHeight, Transparency.TRANSLUCENT);
        imG = main.getGraphics();

       g2d = (Graphics2D)imG;
       g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                            RenderingHints.VALUE_ANTIALIAS_ON);

       paintImage(imG);
       paintAnimationStuff(imG);
       repaint();
   }


   
    private void setupSpeedAdjust() {
        	
	fast = new Label("faster",Label.RIGHT);
	fast.setFont(TheFonts.sanSerif11);
	fast.setBackground(bgColor);
	fast.setForeground(maroon);
	add(fast);
	
	slow = new Label("slower",Label.LEFT);
	slow.setFont(TheFonts.sanSerif11);
	slow.setBackground(bgColor);
	slow.setForeground(Color.blue);
	add(slow);
        
        int shiftx, shifty;
        // To control positioning of slider to
        // draw the faster/slower arrow tips
        //On top of clock
        shiftx = 0; 
        shifty = 0; 
    
        // On Left of cloack
        shiftx = state.s250;
        shifty = state.s62;

	slider = new JSlider(SCROLLMIN,SCROLLMAX);
        //slider = new Scrollbar(Scrollbar.HORIZONTAL,200,1,SCROLLMIN,SCROLLMAX);
	add(slider);

	//slider to change animation speed
	slider.setBounds(state.s290-shiftx,state.s440+shifty,state.s250,state.s15);
	fast.setBounds(state.s479-shiftx,state.s458+shifty,state.s40,state.s15);
	slow.setBounds(state.s313-shiftx,state.s458+shifty,state.s100,state.s15);
	/*
	slider.setBackground(Color.white);
        
	//panels for slider
	Panel slide0 = new Panel();
	    slide0.setBackground(Color.cyan);
	    add(slide0);
	    slide0.setBounds(state.s290-shiftx-1,state.s440+shifty-1,state.s250+2,state.s15+2);	
	Panel slide1 = new Panel();
	    slide1.setBackground(Color.black);
	    add(slide1);
	    slide1.setBounds(state.s290-shiftx-2,state.s440+shifty-2,state.s250+4,state.s15+4);
	*/

	slider.addChangeListener(this);
    }
 

   
    public synchronized void stateChanged(ChangeEvent evt){
	  if(evt.getSource()==slider){
              boolean repaint = !IsTronRunning;
              IsTronRunning = false;

              SleepTime = SCROLLMAX - slider.getValue();
              if (SleepTime < 5) SleepTime = 5;
              //amplitudeScaler = 100 * (50/SleepTime);
              amplitudeScaler = 100 * (250.0/(SleepTime+200));
              getGraphPoints();

              if (repaint) {
                  paintImage(imG);
                  repaint();
              } else IsTronRunning = true;
	  }
    }



   public void mouseClicked(MouseEvent evt){mouseHandler(evt);}
   public void mouseEntered(MouseEvent evt){;}
   public void mouseExited(MouseEvent evt){;}
   public void mousePressed(MouseEvent evt){;}
   public void mouseReleased(MouseEvent evt){;}

   private synchronized void mouseHandler(MouseEvent evt){
       if(evt.getSource() == ssc.button1){
           IsTronRunning = true;
           if(!ThreadStarted){
               start();
               ThreadStarted = true;
               ssc.button1.setEnabled(false);
               ssc.button2.setEnabled(true);
           }
           else{
               ssc.button1.setEnabled(false);
               ssc.button2.setEnabled(true);
               notify();
           }
           //c1.setEnabled(false);
           repaint();
       }
       if(evt.getSource() == ssc.button2){
           IsTronRunning = false;
           ssc.button2.setEnabled(false);
           ssc.button1.setEnabled(true);
           //c1.setEnabled(true);
           repaint();
       }
   }



   public void start(){
       if(tron == null){
           tron = new Thread(this);
           tron.start();
       }
   }


   public void run(){

       while(true){
           if(IsTronRunning){
               animate();
               ssc.clockcanvas.increment();
               state.increment();
           }
           try{
               Thread.sleep(SleepTime);
               synchronized(this){
                   while(!IsTronRunning){wait();}
               }
           }
           catch(InterruptedException e){e.printStackTrace();}
       }
   }


  private synchronized void getPoints() {
    // Get the endpoint for the x-axis:
    int xComp = (int) (Math.cos(xAxisAngle*Math.PI/180.0)*xAxisLength);
    int yComp = (int) (Math.sin(xAxisAngle*Math.PI/180.0)*xAxisLength);
    xAxisEndpt = new Point(origin.x - xComp, origin.y + yComp);
    // get the top-outer points of the moving rectangle
    int npts = (int) (360/deltaTheta);
    current = npts/4;
    halfway = npts/2;
    topOuter = new Point[npts];
    currentIntensity = new Color[npts];
    arrowDirection = new int[npts];

    double thetaInRadians;
    Point circleOrigin = new Point(origin.x, origin.y - wireRectHeight);
    double theta = 0.0;
    for (int i = 0; i < npts; i++, theta+=deltaTheta) {
      thetaInRadians = theta * PIOverOneEighty;
      //xComp = (int) (wireRectWidth * Math.cos(thetaInRadians));
      //yComp = (int) (wireRectWidth * Math.sin(thetaInRadians));
      xComp = (int) (wireRectWidth * Math.cos(thetaInRadians-PIhalf));
      // CHANGE - MAKE LOOP DESCRIBE AN ELLIPTICAL TRAJECTORY TO GIVE ILLUSION OF 3D
      //yComp = (int) (wireRectWidth * Math.sin(thetaInRadians-PIhalf));
      yComp = (int) (wireRectWidth * Math.sin(thetaInRadians-PIhalf) - 0.66*wireRectWidth * Math.sin(thetaInRadians-PIhalf));
      
      topOuter[i] = new Point(circleOrigin.x+xComp, circleOrigin.y-yComp);

      if (theta >= 0.0 && theta < 90.0) {
          currentIntensity[i] = RedColors.getSinLevel(1.0-((90.0-theta)/90.0));
          arrowDirection[i] = ARROW_UP;
      } else if (theta >= 90.0 && theta < 180.0) {
          currentIntensity[i] = 
              RedColors.getSinLevel(1.0-((theta-90.0)/90.0));
          arrowDirection[i] = ARROW_UP;
      } else if (theta >= 180.0 && theta < 270.0) {
          currentIntensity[i] = 
              RedColors.getSinLevel(1.0-((270-theta)/90.0));
          arrowDirection[i] = ARROW_DOWN;
      } else {
          currentIntensity[i] = 
              RedColors.getSinLevel(1.0-((theta-270)/90.0));
          arrowDirection[i] = ARROW_DOWN;
      }
    }
  }



  private synchronized void getGraphPoints() {
    int iForILabel = 0;
    //int npts = (360/deltaTheta) + 1;
    int npts = (int) (360/deltaTheta);
    //icurrent = npts/4;
    ix = new int[npts];
    iy = new int[npts];
    double thetaInRadians, xPoint;
    double oneOverOneEighty = 1.0/180.0;
    double theta = 0.0;
    for (int i = 0; i < npts; i++, theta+=deltaTheta) {
      if (theta == 90.0) iForILabel = i;
      thetaInRadians = theta * PIOverOneEighty;
      //iy[i] = (int) (100 * Math.sin(thetaInRadians));
      iy[i] = (int) (amplitudeScaler * Math.sin(thetaInRadians));
      xPoint = i*deltaTheta*oneOverOneEighty;
      ix[i] = (int) (xPoint*100); // scale x so 360 degress spans 200;
    }

    // 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 < iy.length; i++) {
      iy[i] += graphOrigin.y;
    }
    flipCoordinates(iy,graphOrigin.y);

    // NOW shift the X-axis over by xMin to make room for the vertical
    //  axis line.
    for (int i = 0; i < ix.length; i++) {
      ix[i] += graphOrigin.x;
    }
    iLabelX = ix[iForILabel] + state.s20;
    iLabelY = iy[iForILabel];
  }

  

  private synchronized 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 synchronized void paintImage(Graphics g) {
      g.clearRect(0,0,mainWidth,mainHeight);

      g.setColor(bgColor);
      g.fillRect(0,0,mainWidth,mainHeight);
      
      g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                             RenderingHints.VALUE_ANTIALIAS_ON);

    // Draw x and y axis:
    drawAxis(g);
    g.setColor(wireColor);
    drawLine(g,origin.x,origin.y,origin.x, origin.y - wireRectHeight);

    drawGraphAxis(g);
    g2d.setStroke(new BasicStroke(state.s2,BasicStroke.CAP_ROUND,
                                  BasicStroke.JOIN_ROUND));

    g.setFont(new Font("Serif",Font.BOLD + Font.ITALIC, state.font20));
    g.setColor(iColor);
    g.drawString("I",iLabelX,iLabelY);
    g2d.drawPolyline(ix,iy,ix.length);

    g2d.setStroke(new BasicStroke(1));


    int shiftx, shifty;
        // To control positioning of slider to
        // draw the faster/slower arrow tips
        //On top of clock
        shiftx = 0; 
        shifty = 0; 
    
        // On Left of cloack
        shiftx = state.s250;
        shifty = state.s62;
    
    g.setColor(Color.blue);
    MaestroG.drawArrowtip(state.s297-shiftx,state.s465+shifty,8,g);
    MaestroG.drawArrowtip(state.s305-shiftx,state.s465+shifty,8,g);
    
    g.setColor(maroon);
    MaestroG.drawArrowtip(state.s525-shiftx,state.s465+shifty,7,g);
    MaestroG.drawArrowtip(state.s533-shiftx,state.s465+shifty,7,g);
  }



  private void drawGraphAxis(Graphics g) {
    // Draw x and y axis:
    g.setColor(axisColor);
    // draw y-axis
    drawLineThick(g,(double)graphOrigin.x, (double)(graphOrigin.y-state.s105),(double)graphOrigin.x, (double)(graphOrigin.y + state.s105), state.s1, axisColor);
    // draw x-axis
    drawLineThick(g,(double)graphOrigin.x, (double)(graphOrigin.y),(double)(graphOrigin.x+state.s218), (double)(graphOrigin.y), state.s1, axisColor);
    
    g.setFont(new Font("Serif",Font.BOLD, state.font18));
    g.drawString("time",graphOrigin.x + state.s230,
                 graphOrigin.y + (int)(0.5*fontHeight));
    
    Arrows.drawDblUpArrow(g,graphOrigin.x,graphOrigin.y - state.s107, state.sfactor);
    Arrows.drawDblDownArrow(g,graphOrigin.x,graphOrigin.y + state.s107, state.sfactor);
    Arrows.drawDblRightArrow(g,graphOrigin.x + state.s220,graphOrigin.y, state.sfactor);
    //g.drawString("time",graphOrigin.x + state.s230,
    //             graphOrigin.y + (int)(0.5*fontHeight));
  }



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

  public void paint(Graphics g) {
    g.drawImage(main,0,0,this);
    slider.requestFocusInWindow();
  }

  public synchronized void paintAnimationStuff(Graphics g) {
     
      g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                             RenderingHints.VALUE_ANTIALIAS_ON); 
      
    int thick = state.s5;
    g.setColor(wireColor);
    g2d.setPaint(wireColor);
        g2d.setStroke(new BasicStroke(thick,BasicStroke.CAP_BUTT,BasicStroke.JOIN_ROUND));
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
     
        float alpha;
        int rule = AlphaComposite.SRC_OVER;
        g2d.setComposite(AlphaComposite.getInstance(rule, 0.5f));
        
        
    g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
    //DRAW THE CURRENT LOOP 
        
                Polygon pH = new Polygon();
		pH.addPoint(origin.x, origin.y);
		pH.addPoint(origin.x, origin.y - wireRectHeight);
		pH.addPoint(topOuter[current].x, topOuter[current].y);
                pH.addPoint(topOuter[current].x, topOuter[current].y+wireRectHeight);
		g.drawPolygon(pH);
		//g.fillPolygon(pH);
    
    g2d.setComposite(AlphaComposite.getInstance(rule, 1.0f));            
    g2d.setStroke(new BasicStroke(1));
    /*
    //Vertical Wire along z-axis
    drawLineThick(g,(double)origin.x, (double)(origin.y),(double)origin.x, (double)(origin.y - wireRectHeight), state.s5, wireColor);
    //Top Wire parallel to x-y plane
    drawLineThick(g,(double)origin.x, (double)(origin.y - wireRectHeight),(double)topOuter[current].x, (double)(topOuter[current].y), state.s5, wireColor);
    //Vertical Wire parallel to z-axis 
    drawLineThick(g,(double)topOuter[current].x, (double)(topOuter[current].y),(double)topOuter[current].x, (double)(topOuter[current].y+wireRectHeight), state.s5, wireColor);
    //Bottom wire on x-y plane
    drawLineThick(g,(double)topOuter[current].x, (double)(topOuter[current].y+wireRectHeight),(double)origin.x, (double)origin.y, state.s5, wireColor);
    */
    // draw the current vector:
    g.setFont(new Font("Serif",Font.BOLD + Font.ITALIC, state.font20));
    g.setColor(Color.red);
    g.drawString("I",origin.x+state.s20,origin.y-state.s35);
    if (currentIntensity[current] != RedColors.levels[10]) {
      //g.setColor(currentIntensity[current]);
      //drawLine(g,origin.x+state.s10,origin.y-state.s27,origin.x+state.s10,
      //         origin.y-wireRectHeight+state.s35);
      
      drawLineThick(g,(double)(origin.x+state.s10), (double)(origin.y-state.s27),(double)(origin.x+state.s10), (double)(origin.y-wireRectHeight+state.s35), state.s1, currentIntensity[current]);

      //if (current <= halfway)
      //  Arrows.drawDblDownArrow(g,origin.x,origin.y-7);
      //else
      //  Arrows.drawDblUpArrow(g,origin.x,origin.y-wireRectHeight+7);
      
      if (arrowDirection[current] == ARROW_UP) 
          Arrows.drawDblUpArrow(g,origin.x+state.s10,origin.y-wireRectHeight+state.s33, state.sfactor);
      else
          Arrows.drawDblDownArrow(g,origin.x+state.s10,origin.y-state.s25, state.sfactor);
    }

    //if (!ssc.IsStop) {
    //    //g.setColor(Color.black);
    //    g.setColor(Color.orange);
    //    g.fillOval(ix[icurrent]-3,iy[icurrent]-3,6,6);
    //}
    
    if (!ssc.IsStop) {g.setColor(Color.yellow);
        g.fillOval(ix[current]-state.s4,iy[current]-state.s4,state.s9,state.s8);
        g.setColor(Color.black);
        g.drawOval(ix[current]-state.s4,iy[current]-state.s4,state.s9,state.s8);
    }
  }

  private void drawAxis(Graphics g) {
    // Draw x and y axis:
    g.setColor(axisColor);
    //drawLine(g,origin.x,origin.y,origin.x,origin.y-zAxisLength); //z-axis
    drawLineThick(g,(double)origin.x, (double)(origin.y),(double)origin.x, (double)(origin.y-zAxisLength+state.s2), state.s1, axisColor);
    
    //drawLine(g,origin.x,origin.y,origin.x+yAxisLength,origin.y); // y-axis
    drawLineThick(g,(double)origin.x, (double)(origin.y),(double)(origin.x+yAxisLength-state.s2), (double)(origin.y), state.s1, axisColor);
    
    //drawLine(g,origin.x,origin.y,xAxisEndpt.x,xAxisEndpt.y); // x-axis
    //drawLineThick(g,(double)origin.x, (double)(origin.y),(double)(xAxisEndpt.x), (double)(xAxisEndpt.y), state.s1, axisColor);
    drawLineThick(g,(double)origin.x, (double)(origin.y),(double)(origin.x - state.s15), 0.7*(double)(xAxisEndpt.y), state.s1, axisColor);
    
    // Draw arrow heads for axes
    Arrows.drawDblUpArrow(g,origin.x,origin.y-zAxisLength, state.sfactor);
    g.setFont(new Font("Serif",Font.BOLD, state.font18));
    g.drawString("z",origin.x-(int)(0.5*fm.stringWidth("z")),
                 origin.y-zAxisLength-5);
    
    Arrows.drawDblRightArrow(g,origin.x+yAxisLength,origin.y, state.sfactor);
    g.drawString("y",origin.x+yAxisLength+5,origin.y+(fontHeight/2));
    
    Point[] xArrow =
        Arrows.getDblArrowHeadPts(origin.x - state.s15,(int)(0.7*xAxisEndpt.y),
                                  origin.x, origin.y, state.sfactor);
    g.drawString("x",origin.x - state.s25-fm.stringWidth("x"),
                 (int)(0.7*xAxisEndpt.y));
    Arrows.drawArrowHead(g,xArrow);
    
    // Draw B field
    g.setColor(Color.blue);
    //drawLine(g,xAxisEndpt.x-40,origin.y+20,origin.x+yAxisLength-20,origin.y+20);
    drawLineThick(g,(double)(xAxisEndpt.x-state.s40), (double)(origin.y+state.s20),(double)(origin.x+yAxisLength-state.s10), (double)(origin.y+state.s20), state.s1, Color.blue);
    
    //drawLine(g,xAxisEndpt.x-40,origin.y-20,origin.x+yAxisLength-20,origin.y-20);
    drawLineThick(g,(double)(xAxisEndpt.x-state.s40), (double)(origin.y-state.s20),(double)(origin.x+yAxisLength-state.s10), (double)(origin.y-state.s20), state.s1, Color.blue);
    
    //drawLine(g,xAxisEndpt.x-40,origin.y-60,origin.x+yAxisLength-20,origin.y-60);
    drawLineThick(g,(double)(xAxisEndpt.x-state.s40), (double)(origin.y-state.s60),(double)(origin.x+yAxisLength-state.s10), (double)(origin.y-state.s60), state.s1, Color.blue);
    
    Arrows.drawDblRightArrow(g,origin.x+yAxisLength-state.s8,origin.y+state.s20, state.sfactor);
    Arrows.drawDblRightArrow(g,origin.x+yAxisLength-state.s8,origin.y-state.s20, state.sfactor);
    Arrows.drawDblRightArrow(g,origin.x+yAxisLength-state.s8,origin.y-state.s60, state.sfactor);
    g.drawString("B",origin.x+yAxisLength,origin.y-state.s60);
    //
    g.setColor(axisColor);
  }

  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);
      }
  }
  
  public static void drawLineThick(Graphics g, double x1, double y1, double x2, double y2, int thick, Color color){
	
        Graphics2D g2d = (Graphics2D)g;
        g2d.setPaint(color);
        g2d.setStroke(new BasicStroke(thick,BasicStroke.CAP_BUTT,BasicStroke.JOIN_ROUND));
        
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
        
        Line2D.Double line = new Line2D.Double(x1,y1,x2,y2);
        g2d.draw(line);
  
        g2d.setStroke(new BasicStroke(1));
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_OFF);
    }
    
    public static void drawLineThickB(Graphics g, double x1, double y1, double x2, double y2, int thick, int pat1, int pat2, Color color){
	
        Graphics2D g2d = (Graphics2D)g;
        g2d.setPaint(color);
        float[] dashPattern = {pat1,pat2};
        g2d.setStroke(new BasicStroke(thick,BasicStroke.CAP_BUTT,BasicStroke.JOIN_MITER,10.0F,dashPattern,0));
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
        
        Line2D.Double line = new Line2D.Double(x1,y1,x2,y2);
        g2d.draw(line);
 
        g2d.setStroke(new BasicStroke(1.0F,BasicStroke.CAP_BUTT,BasicStroke.JOIN_MITER));
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_OFF);
    }

  public synchronized void animate() {
    current+=4;
    icurrent+=4;
    if (current >= topOuter.length) current = 0;
    if (icurrent >= ix.length) icurrent = 0;
    paintImage(imG);
    paintAnimationStuff(imG);
    repaint();
  }
  
}
