import java.awt.*;
import java.awt.event.*; 
import java.util.EventListener; 

public class Pongp extends java.applet.Applet implements Runnable 
{ 
  protected MainCanvasm maincanvas;
  GameCanvas canvas;

  protected static final int PLAY = 1;
  protected static final int START = 2; 
  protected static final int STOP = 3; 
  protected static final int NEW = 4; 
  protected static final int OK = 5; 
  
  boolean right = false;
  boolean left = false; 
 
  /** The animation thread */ 
  Thread bouncingThread; 

  int delay;
  int balls = 2;
  int score;
  int tot_blocks;
  int level = 1; 
  int nblocks;
 
  boolean focus = false;
 
  Panel centerPanel; 
  Panel gamedialogPanel;

  Dialog gameDialog; 

  EventListener listener; 

  TextField textscore, textlevel, ballsleft;   
  
  String gameoverlabel, message;
 
  buttons  playButton, startButton, stopButton, newButton, okButton; 

  protected class ButtonHandler implements ActionListener 
  { 
    private int cmd = 0; 

    public ButtonHandler (int cmd) { this.cmd = cmd; } 

    public void actionPerformed (ActionEvent event) 
    { 
      switch (cmd) 
      { 
        case PLAY: remove(centerPanel);  
            add(canvas); 
            game_init(); 
            startButton.setEnabled(true); 
            newButton.setEnabled(true);  
            break; 
        case START: canvas.requestFocus(); 
            playstart(); 
            stopButton.setEnabled(true); 
            break; 
         case STOP: stop(); 
            stopButton.setEnabled(false); 
            break; 
         case NEW: newgame(); 
            stopButton.setEnabled(true); 
            break; 
         case OK: gameDialog.dispose(); 
            setLevel(1); 
            newgame(); 
            break; 
         
        } 
      } 
    } 

   protected class KeyEventHandler implements KeyListener, FocusListener 
   { 
     public void keyPressed (KeyEvent event) 
     { 
       switch (event.getKeyCode()) 
       {  
         case event.VK_LEFT: left = true; 
          canvas.repaint(); 
          break; 
         case event.VK_RIGHT: right = true; 
          canvas.repaint(); 
          break; 
        } 
      }
      public void keyReleased (KeyEvent event) 
      { 
        switch (event.getKeyCode()) 
        { 
          case event.VK_LEFT: left = false; 
           break; 
          case event.VK_RIGHT: right = false; 
           break; 
        } 
      } 
      public void keyTyped (KeyEvent event) {} 

      public void focusGained (FocusEvent event) 
      { 
        focus = true; 
        canvas.repaint(); 
     } 
     public void focusLost (FocusEvent event) 
     { 
       focus = false; 
       canvas.repaint(); 
     } 
  } 
  protected EventListener projectListener() 
  { 
    return new KeyEventHandler(); 
  }

   protected class LevelListener implements AdjustmentListener 
   { 
     public void adjustmentValueChanged (AdjustmentEvent event) 
     { 
       setLevel(event.getValue()); 
       setLevel1(event.getValue()); 
     } 
   } 

  protected class buttons extends Button 
  { 
    buttons (String name) 
    { super(name);  } 
  } 

  Font labelfont = new Font("TimesRoman", Font.PLAIN, 18); 
  protected class label extends Label 
  { label(String name, Font font, Color colr, int position)
     { super(name); 
       super.setFont(font); 
       super.setForeground(colr); 
       super.setAlignment(position); 
     } 
  } 

public Pongp() 
{
  setLayout(new BorderLayout()); 
  canvas = new GameCanvas(); 
  maincanvas = new MainCanvasm(); 
  Panel northPanel = new Panel(); 
  northPanel.setBackground(Color.yellow); 
  northPanel.setLayout(new FlowLayout()); 
  label titlelabel = new label("THE PONG GAME", new Font("TimesRoman", Font.ITALIC, 40), Color.green, Label.CENTER); 
  northPanel.add(titlelabel); 
  Panel centersouthPanel = new Panel(); 
  centersouthPanel.setBackground(Color.black); 
  centersouthPanel.setLayout(new FlowLayout()); 
  playButton = new buttons("PLAY"); 
  centersouthPanel.add(playButton); 
  centerPanel = new Panel(); 
  centerPanel.setLayout(new BorderLayout()); 
  centerPanel.setBackground(Color.black); 
  centerPanel.add("Center", maincanvas); 
  centerPanel.add("South", centersouthPanel); 
  Panel southPanel = new Panel(); 
  southPanel.setLayout(new FlowLayout()); 
  startButton = new buttons("START"); 
  southPanel.add(startButton); 
  stopButton = new buttons("STOP"); 
  southPanel.add(stopButton); 
  newButton = new buttons ("NEW GAME"); 
  southPanel.add(newButton);  
  southPanel.setBackground(Color.yellow); 
  southPanel.add(new Label ("Balls Left:", Label.CENTER)); 
  ballsleft = new TextField("2", 3); 
  southPanel.add(ballsleft); 
  ballsleft.setEnabled(false);
  southPanel.add(new Label ("Current Level:", Label.CENTER)); 
  textlevel = new TextField("1", 3); 
  southPanel.add(textlevel); 
  textlevel.setEnabled(false); 
  southPanel.add(new Label ("Your Score:", Label.CENTER)); 
  textscore = new TextField("0", 8); 
  southPanel.add(textscore); 
  textscore.setEnabled(false);  
  add("Center", canvas); 
  add("Center", centerPanel); 
  add("North", northPanel); 
  add("South", southPanel); 

  playButton.addActionListener(new ButtonHandler(PLAY));
  startButton.addActionListener(new ButtonHandler(START)); 
  stopButton.addActionListener(new ButtonHandler(STOP)); 
  newButton.addActionListener(new ButtonHandler(NEW));    
  listener = projectListener(); 
  addKeyListener((KeyListener) listener);
  addFocusListener((FocusListener) listener); 
} 

   public void setround () 
   {
     balls--; 
     ballsleft.setText(String.valueOf(balls)); 
     return; 
   }
 
   public void setscore (int hits) 
   { 
     score += hits; 
     textscore.setText(String.valueOf(score)); 
     return; 
   }
 
   public void setLevel (int s) 
   { 
      level = s; 
      textlevel.setText(String.valueOf(level)); 
      this.newgame(); 
    }
 
     public void setLevel1 (int s) 
     { 
      level = s; 
      textlevel.setText(String.valueOf(level)); 
      this.stop();
      this.game_init();
      canvas.repaint();
     }
    public void gamedialoginit (int finalscore, String result) 
    { 
      gamedialogPanel = new Panel(); 
      gamedialogPanel.setLayout(new BorderLayout()); 
      gameDialog = new Dialog(new Frame(), false); 
      gameDialog.setSize(300, 120); 
      gameDialog.setLocation(200,500); 
      gameDialog.setTitle ("GAME IS OVER"); 
      gameDialog.setResizable (false); 
      message = result;
      label messagelabel = new label (message, labelfont, Color.black, Label.CENTER);
      gamedialogPanel.add(messagelabel);
      gameDialog.add("North",messagelabel); 
      gameoverlabel = "You scored  " + finalscore + "!";
      label gamelabel = new label (gameoverlabel, labelfont, Color.black, Label.CENTER);
      gamedialogPanel.add(gamelabel);
      gameDialog.add("Center", gamelabel);
      okButton = new buttons ("OK");
      gamedialogPanel.add(okButton);
      gameDialog.add("South", okButton);
      gameDialog.show();
      okButton.addActionListener(new ButtonHandler(OK));
      gameDialog.addWindowListener (new WindowAdapter()
      { 
        public void windowClosing (WindowEvent event) 
        { 
          gameDialog.dispose(); 
        }}); 
      }
 
 
 
    public void newgame () 
    { 
       this.stop(); 
       this.game_init(); 
       canvas.repaint(); 
       textscore.setText("0"); 
       score = 0; 
       balls = 2; 
       ballsleft.setText(String.valueOf(balls)); 
       textlevel.setText(String.valueOf(level));
    }
 
    public void game_init () 
    { 
      if (level == 1) 
       delay = 40; 
      if (level == 2) 
       delay = 30; 
     if (level == 3) 
       delay = 20; 
      if (level == 4) 
       delay = 16; 
      if (level == 5) 
        delay = 8; 
     doLayout(); 
     canvas.init(); 
     this.requestFocus(); 
     }
 
    public void init () 
    {
        doLayout(); 
        maincanvas.init(); 
        startButton.setEnabled(false); 
        stopButton.setEnabled(false); 
        newButton.setEnabled(false);  
        maincanvas.requestFocus(); 
    }
 
    public void start() {} 

    public void playstart() 
    { 
       if (bouncingThread == null) 
       {  
         bouncingThread = new Thread(this); 
          bouncingThread.start(); 
        }   
    }
 
   public void stop() 
   { 
    if (bouncingThread != null) 
    { 
       bouncingThread = null; 
    } 
    this.requestFocus(); 
    left = false; 
    right = false;
   }
 
   public void run() 
   {  
     while (Thread.currentThread() == bouncingThread)
     { 
      try 
      { Thread.currentThread().sleep(delay);
      }
      catch (InterruptedException e){}
      maincanvas.repaint(); 
      canvas.repaint(); 
     } 
   }
 

 class GameCanvas extends Canvas 
 {
   Color backgroundcolor = Color.black;
   Color rectanglecolor = Color.cyan;
   Color ballcolor = Color.red; 
   protected int radius = 20;
   protected int radius1 = 18;
   protected int length1 = 40;
   protected int breadth1 = 15;
   protected int x, y,x1,y1;
   protected int dx = -2, dy = -4, dx1= 4,dy1 = 0;
   int columns = 4; 
   int rows; 
   protected Image image;
   protected Graphics offscreen;
   protected Dimension d;
   Blocks[][] blocks; 
   String result1; 

   public void init() 
   {
    String att = getParameter("delay");
    if (att != null) {
      delay = Integer.parseInt(att);
   }
    d = getSize();
    d.width = 345;
    d.height = 350;
    x = d.width *2/3;
    y = d.height - radius * 6/2;
    x1= d.width * 2/3; 
    y1 = d.height - radius1 * breadth1/7;
    if (level ==1) 
    {   
        tot_blocks = 12; 
        rows = 3; 
        blocks_init (rows); 
        nblocks = tot_blocks; 
    }
    if (level ==2) 
    {   tot_blocks = 16; 
        rows = 4; 
        blocks_init (rows); 
        nblocks = tot_blocks; 
    }
    if (level ==3) 
    {   tot_blocks = 20; 
        rows = 5; 
        blocks_init (rows); 
        nblocks = tot_blocks; 
    }
    if (level ==4) 
    {   tot_blocks = 24; 
        rows =6; 
        blocks_init (rows); 
        nblocks = tot_blocks; 
    }
   
    if (level == 5)
    { tot_blocks = 28;
      rows = 7;
      blocks_init (rows);
      nblocks = tot_blocks;
    }  
   
  }
  public void update(Graphics g) {
    // create the off-screen image buffer
    // if it is invoked the first time
    if (image == null) {
      image = createImage(d.width, d.height);
      offscreen = image.getGraphics();
    }
    // draw the background
    offscreen.setColor(backgroundcolor);
    offscreen.fillRect(0,0,d.width,d.height);
 
    //Ball will bounce back if it touches any of the
    // four sides
    if (x < radius || x > d.width - radius) {
      dx  =  -dx;
    }
    if (y < radius || y > d.height - radius) {
      dy  =  -dy;
    }
    x += dx;
    y += dy;
   
    // if ball comes in contact with a block it will knock off the
    // block and will bounce back
   for (int i = 1; i <= columns; i++)
   { 
    for (int j = 1; j <= rows; j++)
    {  
       if (level <= 5 && blocks[i][j].color != backgroundcolor) 
       { 
          if (removeblock(i, j)) 
          {
            blocks[i][j].color = backgroundcolor;
            nblocks--; 
          }
       } 
     }
   } 
   //Will lose the ball if it goes below the paddle 
   if (y > d.height - radius * 6/2 && balls <= 2 && balls > 0) 
   { 
     ballcolor = Color.black; 
     stop(); 
     x = d.width * 2/3;
     y = d.height - radius * 6/2;
     x1 = d.width * 2/3; 
     y1 = d.height - radius1 * breadth1/7;
     ballcolor = Color.red; 
     setround();
   } 

   // The player is given three chances, after which the game ends
   if (y > d.height - radius * 6/2 && balls <= 0) 
   {  
     result1 = "SORRY,YOU LOST!";  
     setLevel1(1);
     gamedialoginit(score, result1); 
     
   }
   
   // check if all of the blocks in one level have been destroyed 
   // if so, then, move on to the next level 
   // if player has lost all his chances, then end the game

   if (nblocks == 0 && level <= 4 && balls <= 2 && balls >= 0) 
   { 
     level++; 
     setLevel1(level); 
     int previous_level = level - 1;
   } 
   if (nblocks == 0 && level == 5 && balls <= 2 && balls >= 0)
   {   
    result1 = "CONGRATULATIONS,YOU WON!";
    setLevel1(1);
    gamedialoginit(score,result1);
     
   } 

   // adjust the position of the ball 
   // reverse the direction if it touches the line 
   if ((y + (radius * 2)) >= (y1 + (radius1 / 2))) 
   { if (((x + radius) >= x1) && ((x + radius) <= (x1 + (radius1 * 8)))) 
     { 
      dy = -Math.abs(dy);
     } 
     if (((x + (radius * 2)) >= x1) && ((x + radius) <= x1)) 
     { 
       dy = -Math.abs(dy);
        dx = -Math.abs(dx);
     }
    if ((x <= (x1 + (radius * 8))) && ((x + radius) >= (x1 + (radius * 8)))) 
    { 
      dy = -Math.abs(dy); 
      dx = -Math.abs(dx);
    } 
  }
  // move the line with the left and right arrow keys 
  if (left) 
  {
    x1 = x1 - radius1;
    if (x1 < radius1) 
     x1 = radius1*2; 
  } 
  if (right) 
  {
     x1 = x1 + radius1; 
    if (x1 > d.width + radius1 - (radius1 * 3)) 
      x1 = d.width + radius1 - (radius1 * 3); 
  } 
    
    // draw the ball
      offscreen.setColor(ballcolor);
      offscreen.fillOval(x - radius, y - radius,
                           radius * 2, radius * 2);
    //draw the rectangle 
    offscreen.setColor(Color.cyan);
    offscreen.fillRect(x1-length1,y1-breadth1,length1*2,breadth1);

    // draw the blocks 
     for (int i = 1; i <= columns; i++) 
     { for (int j = 1; j <= rows; j++) 
       { if (blocks[i][j].color != Color.black)
         { offscreen.setColor(blocks[i][j].color); 
           offscreen.fillRect(blocks[i][j].bx - blocks[i][j].length,
                               blocks[i][j].by - blocks[i][j].length, 
                               blocks[i][j].length * 8, blocks[i][j].length * 2); 
          }
       } 
     }
    // copy the off-screen image to the screen
    g.drawImage(image, 0, 0, this);
    
  }   
   
   public void blocks_init (int r) 
   { blocks = new Blocks[columns+1][rows+1]; 
     for (int i = 1; i <= columns; i++)
     { for (int j = 1; j <= rows; j++)
       { blocks[i][j] = new Blocks(); 
         blocks[i][j].length = 10; 
         blocks[i][j].bx = (85 * i) + 15 - 85; 
         setblockColor(i, j); 
         blocks[i][j].by = (15 * j) + ((j - 1) * 10);
       } 
      } 
   } 
   public void setblockColor (int i, int j)
   { if (j == 1) blocks[i][j].color = Color.magenta;
      if (j == 2) blocks[i][j].color = Color.pink; 
      if (j == 3) blocks[i][j].color = Color.blue;
      if (j == 4) blocks[i][j].color = Color.green;
      if (j == 5) blocks[i][j].color = Color.yellow; 
      if (j == 6) blocks[i][j].color = Color.orange;
      if (j == 7) blocks[i][j].color = Color.red;
   }
  
   public void paint (Graphics g)
   { update (g); }

   public boolean removeblock (int i,int j) 
   { 
     if(((y + (radius * 2)) >= blocks[i][j].by) && ((y + (radius * 2))
          <= (blocks[i][j].by + (blocks[i][j].length * 2)))) 
     { 
       if ((((x + (radius * 2)) > blocks[i][j].bx) && ((x + (radius * 2))
                < (blocks[i][j].bx + (blocks[i][j].length * 8)))) 
               || ((x < (blocks[i][j].bx + (blocks[i][j].length * 8))) && (x > blocks[i][j].bx))) 
       { 
          dy = -Math.abs(dy);
          dx = -Math.abs(dx);
          setScore_by_Color (i, j); 
         return (true);
       } 
    } 
    if((y <= (blocks[i][j].by + (blocks[i][j].length * 2))) && (y >= blocks[i][j].by)) 
    {  
       if ((((x + (radius * 2)) > blocks[i][j].bx) && ((x + (radius * 2))
            < (blocks[i][j].bx + (blocks[i][j].length * 8)))) 
           || ((x < (blocks[i][j].bx + (blocks[i][j].length * 8))) && (x > blocks[i][j].bx))) 
       {
           dy = Math.abs(dy);
           setScore_by_Color (i, j);
           return (true); 
      } 
    } 
    if(((x + (radius * 2)) >= blocks[i][j].bx) && ((x + (radius * 2))
        <= (blocks[i][j].bx + (blocks[i][j].length * 8)))) 
    { 
      if ((((y + (radius * 2)) > blocks[i][j].by) && ((y + (radius * 2)) 
          < (blocks[i][j].by + (blocks[i][j].length * 2)))) 
          || ((y < (blocks[i][j].by + (blocks[i][j].length * 2))) && (y > blocks[i][j].by))) 
      { 
        dx = -Math.abs(dx); 
        dy = -Math.abs(dy); 
        setScore_by_Color (i, j);
        return (true); 
      } 
   } 
   if((x <= (blocks[i][j].bx + (blocks[i][j].length * 8))) && (x >= blocks[i][j].bx)) 
   { 
      if ((((y + (radius * 2)) > blocks[i][j].by) && ((y + (radius * 2))
            < (blocks[i][j].by + (blocks[i][j].length * 2)))) 
           || ((y < (blocks[i][j].by + (blocks[i][j].length * 2))) && (y > blocks[i][j].by))) 
      {
        dx = Math.abs(dx);
        dy = Math.abs(dy); 
        setScore_by_Color (i, j); 
        return (true); 
      }
   }
   return (false); 
  } 
  public void setScore_by_Color (int i, int j) 
  { 
    if (blocks[i][j].color == Color.magenta) setscore(50);
    if (blocks[i][j].color == Color.pink) setscore(35); 
    if (blocks[i][j].color == Color.blue) setscore(25); 
    if (blocks[i][j].color == Color.green) setscore(20);
    if (blocks[i][j].color == Color.yellow) setscore(15); 
    if (blocks[i][j].color == Color.orange) setscore(10); 
    if (blocks[i][j].color == Color.red) setscore(5); 
  } 
    public GameCanvas() 
    { 
      listener = canvasListener(); 
      addKeyListener((KeyListener) listener);
      addFocusListener((FocusListener) listener); 
    } 
   
    protected EventListener canvasListener() 
    { 
     return new KeyEventHandler(); 
    }
 
    class Blocks 
    {
      Color color; 

      // The current position of the block 
      int bx; 
      int by; 
     
      int length; 
      int rounds = 1;
 
    } 
 }
} 