import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import javax.swing.border.*;

/**
   Class that implements click the ball game.
   In order to win a game, user has to click on the bouncing ball 10 times.
   User can adjust the speed up to level 10.
   @author Sugi
   @version 10/23/02
*/

public class ClickTheBall
{
   public static void main(String[] args)
   {
      Move frame = new Move();
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.show();
   }
}

class Move extends JFrame
{
   public Move()
   {
      setSize(SIZE, SIZE);
      setTitle("Click on The ball!! v1.0 @ Sugi");
      field = new JTextField(5);
      field.setText("0");
      field.setEditable(false);
      setResizable(false);
      panel = new Draw(this);
      panel.setBackground(Color.black);
      panel.setBorder(BorderFactory.createLineBorder(Color.yellow));
      getContentPane().add(panel);
      // The buttons
      start = new JButton("Start");
      stop = new JButton("Pause");
      stop.setEnabled(false);
      quitCurr = new JButton("Quit current game");
      quitCurr.setEnabled(false);
      quit = new JButton("Quit");
      // The combo box
      level = new JComboBox();
      level.setEditable(false);
      level.addItem("1");
      level.addItem("2");
      level.addItem("3");
      level.addItem("4");
      level.addItem("5");
      level.addItem("6");
      level.addItem("7");
      level.addItem("8");
      level.addItem("9");
      level.addItem("10");
      JPanel pane2 = new JPanel();
      pane2.setBackground(Color.gray);
      pane2.setBorder(BorderFactory.createLineBorder(Color.red));
      JPanel pane3 = new JPanel();
      pane3.setBorder(BorderFactory.createLineBorder(Color.red));
      pane3.setBackground(Color.gray);
      JLabel label = new JLabel("Score");
      pane3.add(label);
      pane3.add(field);
      JLabel label2 = new JLabel("Level");
      field2 = new JTextField(5);
      field2.setEditable(false);
      field2.setText("1");
      pane3.add(label2);
      pane3.add(field2);
      start.addActionListener(new
         ActionListener()
         {
            public void actionPerformed(ActionEvent e)
            {
               panel.startSimulation();
               gameOnProgress = true;
               start.setEnabled(false);
               stop.setEnabled(true);
               quitCurr.setEnabled(true);
               panel.resetScore();
            }
         });
      stop.addActionListener(new
         ActionListener()
         {
            public void actionPerformed(ActionEvent e)
            {
               panel.stopSimulation();
               gameOnProgress = false;
               start.setEnabled(true);
               stop.setEnabled(false);
               quitCurr.setEnabled(false);
            }
         });
      quit.addActionListener(new
         ActionListener()
         {
            public void actionPerformed(ActionEvent e)
            {
               panel.stopSimulation();
               gameOnProgress = false;
               System.exit(1);
            }
         });
      level.addActionListener(new
         ActionListener()
         {
            public void actionPerformed(ActionEvent e)
            {
               String lev = (String) level.getSelectedItem();
               theLevel = Integer.parseInt(lev);
               field2.setText(lev);
               panel.updateLevel(theLevel);
            }
         });

      quitCurr.addActionListener(new
         ActionListener()
         {
            public void actionPerformed(ActionEvent e)
            {
               panel.stopSimulation();
               gameOnProgress = false;
               start.setEnabled(true);
               stop.setEnabled(false);
               quitCurr.setEnabled(false);
               panel.setLocation(0.0,0.0);
               panel.resetScore();

            }
         });
      pane2.add(start);
      pane2.add(stop);
      pane2.add(quitCurr);
      pane2.add(new JLabel("Level"));
      pane2.add(level);
      pane2.add(quit);
      getContentPane().add(pane3, BorderLayout.NORTH);
      getContentPane().add(pane2, BorderLayout.SOUTH);
   }

   public JTextField getMedia()
   {
      return field;
   }

   public void enableStartButton()
   {
      start.setEnabled(true);
      gameOnProgress = false;
   }

   public void disablePauseButton()
   {
      stop.setEnabled(false);
   }

   public void disableQuitButton()
   {
      quitCurr.setEnabled(false);
   }

   public boolean isGameOnProgress()
   {
      return gameOnProgress;
   }

   public int getCurrentLevel()
   {
      return theLevel;
   }

   public static final int SIZE = 600;
   private int theLevel;
   private Draw panel;
   private JButton start;
   private JButton stop;
   private JButton quitCurr;
   private JComboBox level;
   private JButton quit;
   private JTextField field;
   private JTextField field2;
   private boolean gameOnProgress = false;
}

class Draw extends JPanel
{
   public Draw(Move m)
   {
      topEX = 0.0;
      topEY = 0.0;
      this.m = m;
      score = 0;
      field = m.getMedia();
      level = 1;
      addMouseListener(new MouseHandler());
   }

   public void paintComponent(Graphics g)
   {
      super.paintComponent(g);
      g2 = (Graphics2D) g;
      red = (int)(Math.random() * 255);
      green = (int)(Math.random() * 255);
      blue = (int)(Math.random() * 255);
      g2.setPaint(new Color(red, green, blue));
      g2.fill(ellipse = new Ellipse2D.Double(topEX, topEY, RADIUS, RADIUS));
   }

   public void setLocation(double x, double y)
   {
      topEX = x;
      topEY = y;
   }

   public void startSimulation()
   {
      simulator = new Runner(this, RADIUS, level);
      simulator.start();
   }

   public void stopSimulation()
   {
      if(simulator != null)
         simulator.interrupt();
   }

   public double getXP()
   {
      return topEX;
   }

   public double getYP()
   {
      return topEY;
   }

   public void updateLevel(int s)
   {
      if(simulator != null)
         simulator.update(s);
      level = s;
   }

   public void resetScore()
   {
      score = 0;
      field.setText("0");
   }

   private class MouseHandler extends MouseAdapter
   {
      public void mousePressed(MouseEvent e)
      {
         Point p = e.getPoint();
         double x = p.getX();
         double y = p.getY();
         if(m.isGameOnProgress())
         {
            if(ellipse.contains(x, y))
               field.setText("" + ++score);
            if(score >= GAMEPOINT)
            {
               stopSimulation();
               m.enableStartButton();
               m.disablePauseButton();
               m.disableQuitButton();
               setLocation(0.0, 0.0);
               JOptionPane.showMessageDialog(null, "You have won!!", "Game over",
                  JOptionPane.INFORMATION_MESSAGE);
            }
         }
      }
   }

   public static final double RADIUS = 30.0;
   public static final int GAMEPOINT = 10;
   private Ellipse2D.Double ellipse;
   private Move m;
   private JTextField field;
   private Graphics2D g2;
   private static int score;
   private static int level;
   private double topEX;
   private double topEY;
   private Runner simulator;
   private int red;
   private int green;
   private int blue;


}

class Runner extends Thread
{
   public Runner(Draw panel, double rad, int fact)
   {
      this.panel = panel;
      this.rad = rad;
      this.fact = fact;
      speed = 1000 / fact;
      topEX = panel.getXP();
      topEY = panel.getYP();
   }

   public void run()
   {
      try
      {
         while(!interrupted())
         {
            topEX += dx;
            topEY += dy;
            if(topEX < 0)
            {
               topEY += dy;
               dx = Math.abs(dx);
            }
            if(topEX + rad >= BAR + OFFSET)
            {
               topEY += dy;
               dx = -dx;
            }
            if(topEY < 0)
            {
               topEY = 0;
               dy = -dy;
            }
            if(topEY + rad >= BAR)
            {
               topEY = BAR - rad;
               dy = -dy;
            }
            panel.setLocation(topEX, topEY);
            panel.repaint();
            sleep(speed);
         }
      }
      catch(InterruptedException e)
      {
      }
   }

   public void update(int s)
   {
      fact = s;
      speed = 1000 / fact;
   }

   public static final double BAR = 500.0;
   public static final double OFFSET = 100.0;
   private int speed;
   private double rad;
   private Draw panel;
   private int fact;
   private double topEX;
   private double topEY;
   private double dx = 20.0;
   private double dy = 20.0;
}