/*******************************************
 * Breakout Clone
 * @version v1.0
 * @author Maan Ashgar
 * email: al_amed@yahoo.com
 * **********************************************/

import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
import javax.microedition.lcdui.game.*;


public class PongClone 
 extends MIDlet
 implements CommandListener
{
 // the main screen commands 
 private Command about = new Command("About",Command.HELP,1);
 private Command exit = new Command("Exit",Command.EXIT,1);
 private Command new_game = new Command("new game",Command.SCREEN,99);
 // TODO: add a pause command , give the player the abillity to pause
 
 Display display;
 Form main_form;
 GameClass game_class;
 
 
 
 /** debuging method*/
 static void debug(String s)
 {
  System.out.println(s);
 }
 
 protected void startApp() 
  throws MIDletStateChangeException
 {
  main_form = new Form("Pong Clone");
  
  display = Display.getDisplay( this );
  display.setCurrent(main_form);
  
  //adding commands to the form
  main_form.addCommand(about);
  main_form.addCommand(exit);
  main_form.addCommand(new_game);
  main_form.setCommandListener(this);
 }
 
 public void commandAction(Command c, Displayable s)
 {
  if( c == about )//what to do on about command
  {
   Alert about_alert = new Alert( "About" , "This game is by Maan Ashgar" , null , AlertType.INFO );
   display.setCurrent(about_alert,main_form);
  }
  
  if( c == exit )//what to do on exit command
  {
   try
   {
    game_class.exit();
    destroyApp(false);
    notifyDestroyed();
   }
   catch (Exception e)
   {
    
   }
   
  }
  
  if( c == new_game )//what to do on new game command
  {
   //start a new game
   game_class = new GameClass();
   game_class.addCommand(exit);
   display.setCurrent(game_class); 
  }
 }
  
    //////////////////////destory & pause //////////////////////
 protected void destroyApp( boolean unconditional ) 
  throws MIDletStateChangeException
 {
  /*TODO : change all objects to null, stop all threads*/
  display = null ;
  main_form = null ;
  game_class.inPlay = false ;
  game_class = null ;
  System.gc();
 }
 
 protected void pauseApp()
 {
 }
}


/**
 * the game class, where the thread handling and the background painting
 * and the user input checking is made
 */
class GameClass 
 extends javax.microedition.lcdui.game.GameCanvas
 implements Runnable
{
 //new game indecator
 private boolean new_game;
 private Ball ball;
 private Puck puck;
   Bricks brick; 
 //width of the screen
 int width = getWidth();
 //height of the screen
 int height = getHeight();
 //the ball image
 String ball_image_string = "/xd.png";
 //the puck image
 String puck_image_string = "/puck.png";
 //puck image width
 int puck_image_width ;
 //puck image width
 int puck_image_height ;
 // the LayerManager
 LayerManager lm = new LayerManager(); 
 //the on/off variable to the game loop
 boolean inPlay;
 //the ball direction
 int x_dir = 5 ;
 int y_dir = 5 ;
 //game over flag
 boolean end_game;
 
 public GameClass()
 {
  super(false);
  
  // create the sprites and start the game thread
  try
  {
   // create the ball sprite
   Image temp_image = Image.createImage( ball_image_string );
   ball = new Ball( temp_image );
   
   //create the puck sprite
   temp_image = Image.createImage( puck_image_string );
   puck = new Puck( temp_image );
   
   //get the height and width of the puck image
   puck_image_width = temp_image.getWidth();
   puck_image_height = temp_image.getHeight();
   
   //create the brick sprite
   temp_image = Image.createImage("/bricks.png");
   brick = new Bricks(temp_image);
   
   //set the puck and the ball start location in the screen
   puck.setPosition( width/2 - puck_image_width/2 , height - 30 );
   ball.setPosition( width/3 , height/3 * 2 );
   
  }
  catch(Exception e)
  {
   
  }
  //add the ball and puck to the layer manager
  lm.append(brick);
  lm.append(ball);
  lm.append(puck);

  //set the game loop on
  inPlay = true;
  //start the game thread
  new Thread(this).start();
 }
 
 public void paint(Graphics g)
 {
  //draw the white background
  g.setColor(0xffffff);
  g.fillRect(0,0,width,height);
  
  //draw the sprites
  lm.paint(g,0,0);
  
  //in case the game end , draw this
  if(end_game == true)
  {
   g.setColor(0x000000);
   g.fillRect(0,(height/2)-20,width,40);
   g.setColor(0xffffff);
   g.drawString("Oops! Game over",width/2,height/2, Graphics.BASELINE|Graphics.HCENTER );
  }
  flushGraphics();
 }
 
 public void run()
 {
  while(inPlay)
  {
   checkKeys();
   ballMove();
   this.paint(getGraphics());
   try
   {
    Thread.sleep(100);
   }
   catch(Exception e)
   {
   
   }
  }
 }
 
 /**
  * this method will check for user input and move the puck
  * accordingly
  */
 public void checkKeys()
 {
  int x = puck.getX();
  int key = getKeyStates();
  //Left?
  if( (key & LEFT_PRESSED) != 0)
  {
   if ( x - 7 >= 0 )
    puck.move(-7,0);
   else if ( x - 7 < 0 )
    puck.move( (-1 * x) ,0);
  }
  //Right?
  if( (key & RIGHT_PRESSED) != 0)
  {
   if( x + puck_image_width+ 7 < width )
    puck.move( 7 , 0 );
   else if( x + puck_image_width + 7 >= width )
    puck.move( 0 , 0 );
  }
  
 }
 
 /**
  * this method will set the inPlay to false on exit to stop the loop
  */
 public void exit()
 {
  inPlay = false;
 }
 
 /**
  * this method will be responsbale for moving the ball
  */
 public void ballMove()
 {
  // if the ball hit the puck
  if (ball.collidesWith(puck,false))
  {
   //TODO: more advance puck/ball hit calculations
   if(ball.getX() > (puck.getX()+18) && ball.getX() <= (puck.getX()+37))
   {
    y_dir *= -1 ;
   }
   else if (ball.getX()> (puck.getX()+37))
   {
    y_dir = (y_dir * -1) - 2 ;
    
   }
   else if (ball.getX() <= (puck.getX()+18))
   {
    y_dir = (y_dir * -1) + 2 ;
   }
   
  }
  
  if (ball.collidesWith(brick,false) && brick.isVisible())
  {
   brick.setVisible(false);
  }
  
  //if the ball hit one of the walls
  if ((ball.getX()+15) >= width || ball.getX() <= 0 )
   x_dir *= -1 ;
  //if the ball hit the roof
  if (ball.getY() <= 0 )
   y_dir *= -1 ;
  //End game hit, if the ball hit the floor
  if ((ball.getY()+15) >= height)
  {
   end_game = true ;
   inPlay = false ;
  }
  ball.move(x_dir,y_dir) ;
  
 }
 
 
}

class Ball extends javax.microedition.lcdui.game.Sprite
{
 public Ball(Image image) throws Exception
 {
  super(image);
 }
}

class Puck extends javax.microedition.lcdui.game.Sprite
{ 
 public Puck(Image image) throws Exception
 {
  super(image); 
 }
}

class Bricks extends javax.microedition.lcdui.game.TiledLayer
{
 Image brick_image ;
 public Bricks(Image brick_image) throws Exception
 {
  super(4,3,brick_image,51,21);
  int[] map = {
    1,2,3,0,
    2,0,2,0,
    3,2,1,0
  };
  
  for (int i=0; i < map.length; i++) {
   int column = i % 4;
   int row = (i - column) / 3;
   setCell(column,row,map[i]);
   }
  
 }
}