import java.applet.*;
import java.awt.*;
import java.awt.event.*;

public class m_jigsaw extends Applet implements Runnable{

   Thread th = null;
   Image os;
   Graphics og;
   int ch=2,sw,mp,rx,ry,dx,dy,sd,af,hf=1;
   int bx=450,by=150;
   double bt;
   int px1,py1,px2,py2,s1,s2,fg = 0;
   int td[] = new int[64];
   int sp,sp1,sp2;
   int lx[] = {350,550,550,350,350};
   int ly[] = {50,50,250,250,50};
   Choice spe = new Choice();
   Choice sep = new Choice();
   Choice pat = new Choice();
   Button sh,vf;
   Label la;

   public void init(){
      os = createImage(600,300);
      og = os.getGraphics();
      setBackground(Color.white);

      spe.addItem(" slow  ");
      spe.addItem(" normal ");
      spe.addItem(" fast  ");
      spe.addItemListener(new MyListener1());
      sep.addItem("  3x3  ");
      sep.addItem("  4x4  ");
      sep.addItem("  5x5  ");
      sep.addItem("  6x6  ");
      sep.addItemListener(new MyListener2());
      pat.addItem(" ball ");
      pat.addItem(" polygon ");
      pat.addItem(" ripple  ");
      pat.addItemListener(new MyListener3());
      setLayout(new BorderLayout());
      Panel pan = new Panel();
      pan.setLayout(new FlowLayout());
      pan.add(sh = new Button("  shuffle  "));
      pan.add(la = new Label("  "));
      pan.add(sep);
      pan.add(la = new Label("  "));
      pan.add(pat);
      pan.add(la = new Label("  "));
      pan.add(spe);
      pan.add(la = new Label("  "));
      pan.add(vf = new Button("open/close"));
      add("South",pan);

      for(int ni = 0;ni < 64;ni ++){
         td[ni] = ni;
      }
      sw = 3;
      sp = 150;

      addMouseListener(
         new MouseAdapter(){
            public void mousePressed(MouseEvent e){
               if((e.getX() > 30)&&(e.getX() < 270)&&(e.getY() > 30)&&(e.getY() < 270)){
                  if(fg == 0){
                     px1 = (e.getX()-30)/(240/sw);
                     py1 = (e.getY()-30)/(240/sw);
                     for(int ss = 0;ss < sw*sw;ss ++){
                        if(td[ss] == px1+py1*sw)s1 = ss;
                     }
                     fg = 1;
                  }else{
                     px2 = (e.getX()-30)/(240/sw);
                     py2 = (e.getY()-30)/(240/sw);
                     for(int ss = 0;ss < sw*sw;ss ++){
                        if(td[ss] == px2+py2*sw)s2 = ss;
                     }
                     sd = td[s1] ; td[s1] = td[s2] ; td[s2] = sd ;
                     fg = 0;
                  }
               }
               repaint();
            }
         }
      );

      sh.addActionListener(new ActionListener(){
         public void actionPerformed(ActionEvent e){
            for(int s1 = 0;s1 < sw*sw;s1 ++){
               sp1 = (int)(sw*sw*Math.random());
               sp2 = (int)(sw*sw*Math.random());
               sd = td[sp1] ; td[sp1] = td[sp2] ; td[sp2] = sd ;
            }
            repaint();
         } 
      });
      vf.addActionListener(new ActionListener(){
         public void actionPerformed(ActionEvent e){
            hf = -1 * hf;
            repaint();
         } 
      });

   }

   class MyListener1 implements ItemListener{
      public void itemStateChanged(ItemEvent e){
         Choice spe = (Choice)e.getSource();
         switch(spe.getSelectedIndex()){
            case 0 : sp = 400 ; break;
            case 1 : sp = 200 ; break;
            case 2 : sp = 100 ; break;
         }
         repaint();
      }
   }

   class MyListener2 implements ItemListener{
      public void itemStateChanged(ItemEvent e){
         Choice sep = (Choice)e.getSource();
         switch(sep.getSelectedIndex()){
            case 0 : sw = 3 ; break;
            case 1 : sw = 4 ; break;
            case 2 : sw = 5 ; break;
            case 3 : sw = 6 ; break;
         }
         for(int ni = 0;ni < 64;ni ++){
            td[ni] = ni;
         }
         fg = 0;
         repaint();
      }
   }

   class MyListener3 implements ItemListener{
      public void itemStateChanged(ItemEvent e){
         Choice spe = (Choice)e.getSource();
         switch(spe.getSelectedIndex()){
            case 0 : ch = 2 ; break;
            case 1 : ch = 1 ; break;
            case 2 : ch = 0 ; break;
         }
         repaint();
      }
   }

   public void paint(Graphics g){
      og.setColor(Color.black);
      og.fillRect(0,0,600,300);

      d_pattern(ch);
      og.setColor(Color.white);
      og.fillRect(0,0,330,300);
      og.fillRect(300,0,300,30);
      og.fillRect(300,270,300,30);
      og.fillRect(570,0,30,300);

      for(int k1 = 0;k1 < sw*sw;k1 ++){
        og.copyArea(330+(k1%sw)*(240/sw),30+(k1/sw)*(240/sw),240/sw,240/sw,((td[k1]%sw)-(k1%sw))*(240/sw)-300,((td[k1]/sw)-(k1/sw))*(240/sw));
      }
      af = 1;
      for(int a1 = 0;a1 < sw*sw;a1 ++){
         if(td[a1] != a1)af = 0;
      }
      if(af == 0){
         for(int k1 = 0;k1 < sw*sw;k1 ++){
           og.setColor(Color.gray);og.drawRect(30+(k1%sw)*(240/sw),30+(k1/sw)*(240/sw),240/sw,240/sw);
         }
      }
      if(fg == 1){
         og.setColor(Color.blue);
         og.drawRect(px1*240/sw+30,py1*240/sw+30,240/sw,240/sw);
         og.drawRect(px1*240/sw+31,py1*240/sw+31,240/sw-2,240/sw-2);
      }
      if(hf == 1){
         og.setColor(Color.lightGray);
         og.fillRect(330,30,240,240);
      }
      g.drawImage(os,0,0,this);
   }

   public void d_pattern(int nn){
      switch(nn){
         case 0 : og.setColor(new Color(255,100,100)) ; og.drawOval(350+rx-mp,50+ry-mp,mp*2,mp*2);
                  og.setColor(new Color(255,50,50)) ; og.drawOval(350+rx-(mp+5),50+ry-(mp+5),(mp+5)*2,(mp+5)*2);
                  og.setColor(new Color(255,0,0)) ; og.drawOval(350+rx-(mp+12),50+ry-(mp+12),(mp+12)*2,(mp+12)*2);
                  break;
         case 1 : og.setColor(Color.green);
                  og.fillPolygon(lx,ly,5);
                  break;
         case 2 : for(int c1 = 0;c1 < 10;c1 ++){
                     og.setColor(new Color(0,150-c1*10,255-c1*10));
                     og.drawOval(bx-c1,by-c1,c1*2,c1*2);
                  }
                  break;
      }
   }

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

   public void stop(){
      th = null;
   }

   public void run(){
      while(th != null){
         try{
            mp = mp + 5;
            if(mp > 100){
               mp = 0;
               rx = (int)(200 * Math.random());
               ry = (int)(200 * Math.random()) ; 
            }
            for(int i1 = 0;i1 < 4;i1 ++){
               lx[i1] = (int)(120*Math.cos(3*bt+i1))+450;
               ly[i1] = (int)(120*Math.cos(4*bt+i1-0.8))+150;
            }
            lx[4] = lx[0] ; ly[4] = ly[0] ;
            bt = bt + 0.02;
            bx = (int)(110*Math.cos(6*bt))+450;
            by = (int)(110*Math.cos(5*bt-0.8))+150;
            Thread.sleep(sp);
         }
         catch (InterruptedException e){
         }
         repaint();
      }
   }

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