/*========================================================
 Pieces: by Eduardo Sanchez Velasco. 03/09/98
 A Java Applet to move pieces around.
 This applet uses antiflikering tricks in method update(). 
 Like any applet with Runnable threads, it implements:
  init()
  start()
  run() -> repaint() -> update() -> myPaint()
  stop()
  
 Call the applet from a HTML file with the line:
 <applet code="pieces.class" width=400 height=300></applet>
 A width=400 and height=300 work well.
==========================================================*/

import java.util.*;
import java.awt.*;
import java.applet.*;

  
public class pieces extends Applet implements Runnable
{
   Thread timer = null;
   int Width, Height;        // Canvas size (from html file)
   final Color Bgd = Color.white;
   final int Delay = 200;    // Milliseconds of delay
   
   final int RN_T = 4;       // Number of Red triangles
   final int N_T = 8*RN_T;   // Number of triangles
   Color Tcolor[];           // Triangles color
   Polygon T[];              // Triangles
   
   int anchor;               // Anchored polygon
   int x_anchor, y_anchor;   // Anchor point
   int mouse_x, mouse_y;     // mouse location
   
   // Private variables used in update() to avoid flikering
   private Image     offScreenImage;
   private Graphics  offScreenGraphics;
      
   // ----------------- METHODS ----------------------------
    
   public void init()
   {  
     // Set background color 
     setBackground(Bgd);

     // Get the dimensions of plot areas (without buttons)
     Width  = size().width; 
     Height = size().height; 
     
     // Create and init the off-screen image 
     offScreenImage = createImage(Width, Height);
     offScreenGraphics = offScreenImage.getGraphics();
     // Clear the board (do not use g.clearRect!)
     offScreenGraphics.setColor(Bgd);
     offScreenGraphics.fillRect(0,0,Width,Height);
     
     // Init triangles
     int n;
     
     anchor = -1;  // no triangles anchored
     
     int x[] = new int[3], y[] = new int[3];
     Tcolor  = new Color[N_T];
     T = new Polygon[N_T];
     
     for(n=0; n<RN_T; n++)
     {
        Tcolor[n]=Color.red;
        x[0]=n*41+1;     y[0]= 1;
        x[1]=(n+1)*41+1; y[1]= 1;
        x[2]=n*41+1;     y[2]=41+1;
        T[n] = new Polygon(x,y,3);
        
        Tcolor[n+RN_T]=Color.blue;
        x[0]=n*41+1;     y[0]=41+1;
        x[1]=(n+1)*41+1; y[1]= 1;
        x[2]=(n+1)*41+1; y[2]=41+1;
        T[n+RN_T] = new Polygon(x,y,3);
        
        Tcolor[n+2*RN_T]=new Color(255,182,0);  // Orange
        x[0]=n*41+1;     y[0]=41+1;
        x[1]=(n+1)*41+1; y[1]=41+1;
        x[2]=(n+1)*41+1; y[2]=82+1;
        T[n+2*RN_T] = new Polygon(x,y,3);  
        
        Tcolor[n+3*RN_T]=new Color(38,229,0);    // Green
        x[0]=n*41+1;     y[0]=41+1;
        x[1]=(n+1)*41+1; y[1]=82+1;
        x[2]=n*41+1;     y[2]=82+1;
        T[n+3*RN_T] = new Polygon(x,y,3);
        
        Tcolor[n+4*RN_T]=new Color(255,255,0);  // Yellow
        x[0]=n*58+1;     y[0]=82+1;
        x[1]=(n+1)*58+1; y[1]=82+1;
        x[2]=n*58+29+1;  y[2]=82+29+1;
        T[n+4*RN_T] = new Polygon(x,y,3); 
        
        Tcolor[n+5*RN_T]=new Color(250,0,250);  // Magenta
        x[0]=n*58+1;     y[0]=82+58+1;
        x[1]=(n+1)*58+1; y[1]=82+58+1;
        x[2]=n*58+29+1;  y[2]=82+29+1;
        T[n+5*RN_T] = new Polygon(x,y,3);
        
        Tcolor[n+6*RN_T]=new Color(0,250,250);  // Cyan
        x[0]=n*58+1;     y[0]=82+1;
        x[1]=n*58+1;     y[1]=82+58+1;
        x[2]=n*58+29+1;  y[2]=82+29+1;
        T[n+6*RN_T] = new Polygon(x,y,3);
        
        Tcolor[n+7*RN_T]=new Color(0,0,50);     // Black
        x[0]=(n+1)*58+1; y[0]=82+1;
        x[1]=(n+1)*58+1; y[1]=82+58+1;
        x[2]=n*58+29+1;  y[2]=82+29+1;
        T[n+7*RN_T] = new Polygon(x,y,3);
                                                               
     }
     
   } //--------- End of init() -------------- 
   
   public void start() 
   { 
     if(timer == null)
     {
        timer = new Thread(this);
        timer.start();
     }
      
   } //--------- End of start() ------------ 
    
   // In run() we wait Delay ms and repaint 
   public void run() 
   {  
      while (timer != null) 
      {        
         try {Thread.sleep(Delay);} 
         catch (InterruptedException e){}

         repaint(); 
      }
      timer = null;
      
   } //--------- End of run() -------------- 

   // Override update() with tricks to avoid flikering 
   public final synchronized void update(Graphics g)
   {
      myPaint(offScreenGraphics);
      g.drawImage(offScreenImage, 0, 0, null);
              
   } //--------- End of update() --------------  

   public void stop() 
   { 
       if( timer != null )
       {
           timer.stop();
           timer = null;
       }
   
    } //--------- End of stop() -------------- 
   
   // myPaint() Repaints the off-screen canvas
   public void myPaint(Graphics g) 
   {  
      int n;
      
      // Clear the board (do not use g.clearRect!)
      g.setColor(Bgd);
      g.fillRect(0,0,Width,Height);
      g.setColor(Color.black);
      g.drawRect(0,0,Width-1,Height-1);
      
      // Draw Triangles with T[0] on top 
      for(n=N_T-1; n>=0; n--)
      {g.setColor(Tcolor[n]); g.fillPolygon(T[n]);}
      
         
   } //--------- End of Mypaint() --------------
   
   // Handle a key pressed in the mouse
   public boolean mouseDown(Event click, int x, int y) 
   {
       int n,m;
       
       //Check if (x,y) is inside a triangle
       for(n=0; n<N_T; n++)
       if( InsideT(T[n],x,y) )
       { 
          anchor=n;         // Triangle n is anchored
          x_anchor = x;     // at (x,y)
          y_anchor = y;   
          return true;
       }

       anchor = -1;         // No triangle anchored
       return true;
       
   }//--------- End of mouseDown() -------------
   
   // Handle a mouse drag of the Polygon
   public boolean mouseDrag(Event click, int x, int y) 
   {
     int n, D_x, D_y;
       
     if(anchor<0)            // No triangle anchored
     return true;
     
     n=anchor;               // Update triangle n

     D_x = x-x_anchor;       // Increase in x
     D_y = y-y_anchor;       // Increase in y
       
     T[n].xpoints[0] += D_x; T[n].ypoints[0] += D_y;
     T[n].xpoints[1] += D_x; T[n].ypoints[1] += D_y;
     T[n].xpoints[2] += D_x; T[n].ypoints[2] += D_y; 
     
     x_anchor = x;           // Make (x,y) the new
     y_anchor = y;           // anchor point
          
     repaint(); 
     return true;
       
   }//--------- End of mouseDrag() -------------
   
   // Handle a lifting of the mouse (mouse up)
   public boolean mouseUp(Event click, int x, int y) 
   {
       anchor = -1;          // cancel anchor point
       
       return true;
       
   }//--------- End of mouseUp() -------------
   
   // Checks if A=(x,y) is inside the TRIANGLE P
   public boolean InsideT(Polygon P, int x, int y)
   {
        int x1 = P.xpoints[0], y1 = P.ypoints[0],
            x2 = P.xpoints[1], y2 = P.ypoints[1],
            x3 = P.xpoints[2], y3 = P.ypoints[2];
        int D,G;
        
        // Chek if line 3-A intersects
        // line 1->2 between 1 and 2
        D=(x1-x2)*(y3-y)-(y1-y2)*(x3-x);
        G=(x1-x3)*(y3-y)-(y1-y3)*(x3-x);
        if(D>0&&(G<=0||G>=D)) return false;
        if(D<0&&(G>=0||G<=D)) return false;
        if(D==0)              return false;
        
        // Check if line 1-A intersects 
        // line 2-3  between 2 and 3
        D=(x2-x3)*(y1-y)-(y2-y3)*(x1-x);
        G=(x2-x1)*(y1-y)-(y2-y1)*(x1-x);
        if(D>0&&(G<=0||G>=D)) return false;
        if(D<0&&(G>=0||G<=D)) return false;
        if(D==0)              return false;
        
        // Point is inside triangle 
        return true;    
        
   }//--------- End of InsideT() ------------- 
 
}
