import java.awt.event.*;
import java.awt.geom.*;
import java.awt.*;
import javax.swing.*;
import java.util.*;

/**
 * Panel que se encarga de dibujar la representacion grafica del cubo rubik.
 */
class Panel extends JPanel
{
   /**
    * CuboRubik asociado a este Panel.
    */
   private CuboRubik rubik;
   
   /**
    * Temporizador de animaciones, para que los movimientos del cubo se vean
    * suaves.
    */
   private javax.swing.Timer timer;
   
   /**
    * Milisegundos de retardo entre imagenes (lo que da unos 50 fps)
    */
   private int delay = 20;
   
   /**
    * Total de imagenes mostradas para una movida del cubo.
    */
   private int totalFrame = 50;
   
   /**
    * Lleva la cuenta de las imagenes ya mostradas.
    */
   private int curreFrame = 50;
   
   /**
    * Usado para determinar que tipo de giro hara el cubo.
    */
   private String SMOV;
   private ArrayList<Polygon> atrapaClick; //dice como mover el cubo
   
   public Panel()
   {
      setBackground(Color.darkGray);
      rubik = new CuboRubik();
      rubik.pintar();
      
      addMouseListener(new MouseHandler());
      //atrapaClickInit();
      
      TimerHandler taskPerformer = new TimerHandler();
      timer = new javax.swing.Timer(delay, taskPerformer);
      
   }
   
   private class TimerHandler implements ActionListener
   {
      public TimerHandler() {};
      
      public void actionPerformed(ActionEvent evt)
      {
         curreFrame++;
         rubik.moverFig(SMOV, 90f/totalFrame*curreFrame);
         repaint();
         
         if (curreFrame >= totalFrame)
         {
            timer.stop();
            rubik.ajustar();
            rubik.moverMod(SMOV);
            rubik.pintar(); // IMPORTANTE cuando se mueva el ModRubik
         }
      }
   }
   
   private class MouseHandler extends MouseAdapter
   {
      public void mousePressed(MouseEvent event)
      {
         if (curreFrame < totalFrame)
            return; // ignora los click hasta que termine la animacion
         
         int boton = event.getButton();
         Point pos = event.getPoint();
         String mov = null;
         String smov = null;
         
         if (atrapaClick.get(0).contains(pos))
            mov = "A";
         else
         if (atrapaClick.get(1).contains(pos))
            mov = "I";
         else
         if (atrapaClick.get(2).contains(pos))
            mov = "F";
         else
         if (atrapaClick.get(3).contains(pos))
            mov = "D";
         else
         if (atrapaClick.get(4).contains(pos))
            mov = "T";
         else
         if (atrapaClick.get(5).contains(pos))
            mov = "B";
         
         
         if (boton == MouseEvent.BUTTON1)
            smov = mov + "' ";
         else
         if (boton == MouseEvent.BUTTON3)
            smov = mov + " ";
         else
         if (boton == MouseEvent.BUTTON2)
            smov = "Y ";
         
         
         giroAnimado(smov);
         //curreFrame = 0;
         //timer.start();
      }
      
      public void mouseReleased(MouseEvent event)
      {}
   }
   
   public void giroAnimado(String comando)
   {
      if (curreFrame < totalFrame)
            return; // ignora los comandos hasta que termine la animacion
      
      SMOV = comando;
      
      curreFrame = 0;
      timer.start();
   }
   
   public void nuevoCubo()
   {
      rubik.nuevo();
   }
   
   public void mezclarCubo()
   {
      rubik.mezclar();
   }
   /*
   private Point getScreenPos(Point3D p)
   {
      Point2D.Float pt = rubik.getFigura().getPos2D(p);
      
      int alto = getHeight();
      int ancho = getWidth();
      int zoom = Math.min(alto, ancho);
      int centroX = ancho / 2;
      int centroY = alto / 2;
      
      int x = (int)(pt.getX() * zoom + centroX);
      int y = (int)(pt.getY() * zoom + centroY);
      
      return new Point(x, y);
   }
   */
   public void paintComponent(Graphics g)
   {
      super.paintComponent(g);
      Graphics2D g2 = (Graphics2D)g;
      
      int alto = getHeight();
      int ancho = getWidth();
      int zoom = Math.min(alto, ancho);
      int centroX = ancho / 2;
      int centroY = alto / 2;
      
      atrapaClickInit();
      
      ArrayList<Triangulo> trianList = rubik.getTrianList();
      for (int i=0; i<trianList.size(); i++)
      //for (int i=0; i<count; i++)
      {
         float[] array_X = trianList.get(i).getArrayX();
         float[] array_Y = trianList.get(i).getArrayY();
         Color color   = trianList.get(i).getColor();
         
         int[] array_Xi = {0,0,0};
         int[] array_Yi = {0,0,0};
         for (int j=0; j<3; j++)
         {
            array_Xi[j] = (int)(array_X[j] * zoom + centroX);
            array_Yi[j] = (int)(array_Y[j] * zoom + centroY);
         }
         
         
         g2.setColor(color);
         g2.fillPolygon(array_Xi, array_Yi, 3);
         
         //TEST
         /*for (int k=0; k<6; k++)
         {
            g2.setColor(Color.CYAN);
            g2.drawPolygon(atrapaClick.get(k));
         }*/
      }
      //dibujado de las letras que identifican las caras
      g2.setColor(Color.BLACK);
      g2.drawString("F", (int)(-0.034f*zoom+centroX), (int)(0.103f*zoom+centroY));
      g2.drawString("A", (int)(0.078f*zoom+centroX), (int)(-0.156f*zoom+centroY));
      g2.drawString("D", (int)(0.247f*zoom+centroX), (int)(0.089f*zoom+centroY));
      g2.drawString("B", (int)(-0.411f*zoom+centroX), (int)(0.078f*zoom+centroY));
      g2.drawString("T", (int)(-0.369f*zoom+centroX), (int)(-0.019f*zoom+centroY));
      g2.drawString("I", (int)(-0.479f*zoom+centroX), (int)(-0.006f*zoom+centroY));
   }
   
   private void atrapaClickInit()
   {
      Point[] arista = {null,null,null,null,null,null,null,null};
      atrapaClick = new ArrayList<Polygon>();
      int i;
      int alto = getHeight();
      int ancho = getWidth();
      int zoom = Math.min(alto, ancho);
      int centroX = ancho / 2;
      int centroY = alto / 2;
      
      int[] xi = {0,0,0,0};
      int[] yi = {0,0,0,0};
      
      //cara arriba
      float[] xf = { 0.056f, -0.184f,  0.167f,  0.355f};
      float[] yf = {-0.247f, -0.153f, -0.055f, -0.189f};
      for (i=0; i<4; i++)
      {
         xi[i] = (int)(xf[i] * zoom + centroX);
         yi[i] = (int)(yf[i] * zoom + centroY);
      }
      atrapaClick.add(new Polygon(xi, yi, 4));
      
      //cara izquierda
      xf[0] = -0.424f; xf[1] = -0.42f;  xf[2] = -0.52f;  xf[3] = -0.544f;
      yf[0] = -0.125f; yf[1] =  0.012f; yf[2] =  0.085f; yf[3] = -0.078f;
      for (i=0; i<4; i++)
      {
         xi[i] = (int)(xf[i] * zoom + centroX);
         yi[i] = (int)(yf[i] * zoom + centroY);
      }
      atrapaClick.add(new Polygon(xi, yi, 4));
      
      //cara frente
      xf[0] = -0.137f; xf[1] = -0.184f; xf[2] =  0.167f; xf[3] = 0.156f;
      yf[0] =  0.17f;  yf[1] = -0.153f; yf[2] = -0.055f; yf[3] = 0.312f;
      for (i=0; i<4; i++)
      {
         xi[i] = (int)(xf[i] * zoom + centroX);
         yi[i] = (int)(yf[i] * zoom + centroY);
      }
      atrapaClick.add(new Polygon(xi, yi, 4));
      
      //cara derecha
      xf[0] = 0.317f; xf[1] =  0.355f; xf[2] =  0.167f; xf[3] = 0.156f;
      yf[0] = 0.115f; yf[1] = -0.189f; yf[2] = -0.055f; yf[3] = 0.312f;
      for (i=0; i<4; i++)
      {
         xi[i] = (int)(xf[i] * zoom + centroX);
         yi[i] = (int)(yf[i] * zoom + centroY);
      }
      atrapaClick.add(new Polygon(xi, yi, 4));
      
      //cara atras
      xf[0] = -0.424f; xf[1] = -0.42f;  xf[2] = -0.291f; xf[3] = -0.274f;
      yf[0] = -0.125f; yf[1] =  0.012f; yf[2] =  0.057f; yf[3] = -0.095f;
      for (i=0; i<4; i++)
      {
         xi[i] = (int)(xf[i] * zoom + centroX);
         yi[i] = (int)(yf[i] * zoom + centroY);
      }atrapaClick.add(new Polygon(xi, yi, 4));
      
      //cara abajo
      xf[0] = -0.291f; xf[1] = -0.42f;  xf[2] = -0.52f;  xf[3] = -0.375f;
      yf[0] =  0.057f; yf[1] =  0.012f; yf[2] =  0.085f; yf[3] = 0.155f;
      for (i=0; i<4; i++)
      {
         xi[i] = (int)(xf[i] * zoom + centroX);
         yi[i] = (int)(yf[i] * zoom + centroY);
      }atrapaClick.add(new Polygon(xi, yi, 4));
   }
   /*
   public int etapaTerminada()
   {
      return rubik.etapaTerminada();
   }*/
}
