import javax.microedition.midlet.*; 
import javax.microedition.lcdui.*; 
import javax.microedition.rms.*; 
import java.util.*; 

public class Micronoid extends MIDlet { 

   private Display display; 
   private GameCanvas canvas; 
   private Timer tm; 
   private PlayTimer pt; 

public Micronoid() { 

   display=Display.getDisplay(this); 
   canvas=new GameCanvas(this); 
   } 

public void startApp() { 

   display.setCurrent(canvas); 
   } 

public void pauseApp() { 
   } 

public void destroyApp(boolean unconditional) { 
   } 

public void exitMIDlet() { 

       destroyApp(true); 
       notifyDestroyed(); 
   } 
    
public void startTimer() { 

       tm=new Timer(); pt=new PlayTimer(canvas); tm.schedule(pt,0,60); }    
    
public void stopTimer() { 

   if (tm!=null) 
       tm.cancel(); 
   tm=null; 
   } 
} 

class PlayTimer extends TimerTask { 

  private GameCanvas canvas; 

public PlayTimer (GameCanvas canvas) { 

   this.canvas=canvas; 
   } 

public final void run() { 

   canvas.doGamePlay(); 
   canvas.repaint(); 
   } 
} 

class GameCanvas extends Canvas implements CommandListener { 

  private Command cmExit; 
  private Command cmStart; 
  private Command cmStop; 
  private Command cmResume; 
  private String text; 
  private Micronoid midlet; 
  private int gameState; 

  private int playerPos; 
  private int ballX,ballY; 
  private int deltaX,deltaY; 
  private int move; 
  private int bricksLeft; 
  
  private Image screen; 
  private Graphics offScreen; 
  private int width, height; 
  private int distance=5; 
  private int brickWidth, brickHeight; 
  private int xNum=4; 
  private int yNum=6; 
  
  private boolean[][] rasta=new boolean[xNum][yNum]; 

public GameCanvas(Micronoid midlet) { 

   this.midlet=midlet; 
   gameState=0; 
   width=getWidth()/2; 
   height=getHeight(); 
   cmExit=new Command("Exit",Command.EXIT, 1); 
   cmStart=new Command("Start",Command.SCREEN, 1); 
   cmStop=new Command("Stop",Command.SCREEN, 2); 
   cmResume=new Command("Fortsetzen",Command.SCREEN, 3); 
   addCommand(cmExit); 
   addCommand(cmStart); 
   addCommand(cmStop); 
   if (recordSetExists()) 
       addCommand(cmResume); 
   setCommandListener(this); 
   repaint(); 
   } 
    
private void initScreen(boolean resetRasta) { 

   screen=Image.createImage(width,height); 
   offScreen=screen.getGraphics(); 
   brickWidth=(width-distance)/xNum-distance; 
   brickHeight=(height-distance)/yNum-distance; 
   if (resetRasta) 
       bricksLeft=0; 
   for (int x=0;x<xNum;x++) { 
        for (int y=0;y<yNum;y++) { 
             if (resetRasta||rasta[x][y]) 
                 drawBrick(x,y,true); 
             if (resetRasta) { 
                 rasta[x][y]=true; 
                 bricksLeft++; 
                 } 
             } 
        } 
   } 
    
protected void paint(Graphics g) { 

   g.setColor(255,255,255); 
   g.fillRect(width/2,0,width/2,height); 
   g.setColor(0,0,0); 

   switch (gameState) { 
      case 0: g.setColor(255,255,255);                  
              g.fillRect(0,0,getWidth(),height); 
              g.setColor(0,0,0);                        
              g.drawString("press start!",width,height/2,Graphics.BASELINE|Graphics.HCENTER); 
              break; 
      case 1: g.setColor(255,255,255); 
              g.fillRect(width,0,width,height); 
              g.drawImage(screen,0,0,Graphics.LEFT|Graphics.TOP); 
              g.setColor(0,0,0); 
              g.fillRect(getWidth()-5,playerPos,3,20); 
              g.fillRect(ballX,ballY,2,2); 
              break; 
      case 3: g.setColor(255,255,255);                  
              g.fillRect(0,0,getWidth(),height);        
              g.setColor(0,0,0);                        
              g.drawString("game over",getWidth()/2,getHeight()/2,Graphics.BASELINE|Graphics.HCENTER); 
              break; 
      case 4: g.setColor(255,255,255);                  
              g.fillRect(0,0,getWidth(),height);        
              g.setColor(0,0,0);                        
              g.drawString("you made it!",getWidth()/2,getHeight()/2,Graphics.BASELINE|Graphics.HCENTER); 
              break; 
      } 
   } 
    
public void doGamePlay() { 

   ballX+=deltaX; 
   ballY+=deltaY; 

   playerPos+=move; 

   if (playerPos<0) { 
       playerPos=0; 
       move=0; 
       } 
   if (playerPos>getHeight()-20) { 
       playerPos=getHeight()-20; 
       move=0; 
       } 
   if (ballX<0) { 
       ballX=0; 
       deltaX*=-1; 
       } 
   else if (ballX>getWidth()-1) { 
       gameState=3; 
       midlet.stopTimer(); 
       repaint(); 
       } 
   if (ballY<0) { 
       ballY=0; 
       deltaY*=-1; 
       } 
   else if (ballY>getHeight()-1) { 
       ballY=getHeight()-1; 
       deltaY*=-1; 
       } 
    
   if (ballX<width) { 
       if (((ballX-distance+1)%(brickWidth+distance)<=brickWidth)&&(checkBrick())) { 
           if (((ballY-distance+1)%(brickHeight+distance)<=brickHeight)&&(checkBrick())) { 
               if (((ballX-distance+1-deltaX)%(brickWidth+distance)<=brickWidth)&&(checkBrick())) 
                   deltaY*=-1; 
               else 
                   deltaX*=-1; 
               clearBrick(); 
               } 
            } 
       } 

   if ((ballX>getWidth()-7)&&(ballX<=getWidth()-4)) { 
       if ((ballY>playerPos)&&(ballY<playerPos+20)) { 
           deltaX*=-1; 
           int ang=(ballY-playerPos)/3; 
           deltaY=ang-3; 
           } 
       } 
   } 
    
private void drawBrick(int x, int y, boolean draw) { 

   if (draw) 
       offScreen.setColor(0,0,0); 
   else 
       offScreen.setColor(255,255,255); 
        
   offScreen.fillRect(distance+x*(brickWidth+distance),distance+y*(brickHeight+distance),brickWidth,brickHeight); 
   }    
    
private boolean checkBrick() { 

   int x=(ballX-distance+1)/(brickWidth+distance); 
   int y=(ballY-distance+1)/(brickHeight+distance); 
    
   if ((x<0)||(x>=xNum)||(y<0)||(y>=yNum)) 
       return(false); 
        
   if (rasta[x][y]) { 
       return(true); 
       } 
   return(false); 
   } 

private void clearBrick() { 

   int x=(ballX-distance+1)/(brickWidth+distance); 
   int y=(ballY-distance+1)/(brickHeight+distance); 
    
   if ((x<0)||(x>=xNum)||(y<0)||(y>=yNum)) 
       return; 
        
   drawBrick(x,y,false); 
   rasta[x][y]=false; 
   bricksLeft--; 
    
   if (bricksLeft<=0) { 
       gameState=4; 
       midlet.stopTimer(); 
       deleteRecordSet(); 
       repaint(); 
       } 
   } 

private void startGame() { 

   ballX=getWidth()-5; 
   ballY=getHeight()/2; 
   playerPos=(getHeight()-20)/2; 
   deltaX=-2; 
   deltaY=0; 
   gameState=1; 
   midlet.startTimer(); 
   } 
    
private void stopGame() { 

   midlet.stopTimer(); 
   gameState=0; 
   repaint(); 
   } 
    
protected void keyPressed(int keyCode) { 

   switch (keyCode) { 
      case KEY_NUM2: move=-2; 
                     break; 
      case KEY_NUM8: move=2; 
                     break; 
      } 
  } 

protected void keyReleased(int keyCode) { 

   switch (keyCode) { 
      case KEY_NUM2: move=0; 
                     break; 
      case KEY_NUM8: move=0; 
                     break; 
      } 
  } 

public void commandAction(Command c, Displayable d) { 

   if (c==cmExit) { 
       saveGameState(); 
       midlet.exitMIDlet(); 
       } 
   else if (c==cmStart) { 
       if (gameState!=1) { 
           initScreen(true); 
           startGame(); 
           } 
       } 
  else if (c==cmStop) 
       stopGame(); 
  else if (c==cmResume) { 
       restoreGame(); 
       initScreen(false); 
       startGame(); 
       } 
   } 
    
private void saveGameState() { 

   RecordStore rs=null; 
   byte[] rec=new byte[xNum]; 

   deleteRecordSet(); 
   try { 
       rs=RecordStore.openRecordStore("GameState",true); 
       } 
   catch (Exception e) { 
       System.out.println("Fehler beim Anlegen von Recordset"); 
       } 
   for (int i=0;i<yNum;i++) { 
        for (int j=0;j<xNum;j++) { 
             if (rasta[j][i]) { 
                 rec[j]=1; 
                 } 
             else { 
                 rec[j]=0; 
                 } 
             } 
        try { 
            rs.addRecord(rec,0,rec.length); 
            } 
        catch (Exception e) { 
            System.out.println("Fehler beim Einfügen von Record["+i+"]"); 
            } 
        } 
   //und wieder schließen 
   try { 
        rs.closeRecordStore(); 
        } 
   catch (Exception e) { 
        System.out.println("Fehler beim Schließen von Recordset"); 
        } 
   } 
    
private void restoreGame() { 

   byte[] rec=new byte[xNum]; 
   RecordStore rs=null; 
   int len, i=0, j=0; 
    
   bricksLeft=0; 

   //öffnen des Speichers 
   try { 
       rs=RecordStore.openRecordStore("GameState",true); 
       } 
   catch (Exception e) { 
       System.out.println("Fehler beim Öffnen des Speichers"); 
       return; 
       } 

   try { 
       for (i=0;i<yNum;i++) { 
            len=rs.getRecord(i+1,rec,0); 
            for (j=0;j<xNum;j++) { 
                 if (rec[j]==1) { 
                     bricksLeft++; 
                     rasta[j][i]=true; 
                     } 
                 else { 
                     rasta[j][i]=false; 
                     } 
                 } 
            } 
       } 
   catch (Exception e) { 
       System.err.println("Fehler beim Lesen von Recordset i="+i+" j="+j); 
       e.printStackTrace(); 
       } 

   //und wieder schließen 
   try { 
        rs.closeRecordStore(); 
        } 
   catch (Exception e) { 
        System.out.println("Fehler beim Schließen von Recordset"); 
        } 
   } 
    
private boolean recordSetExists() { 

   RecordStore rs=null; 
   //öffnen des Speichers 
   try { 
       rs=RecordStore.openRecordStore("GameState",false); 
       } 
   catch (Exception e) { 
       return(false); 
       } 
   //und wieder schließen 
   try { 
        rs.closeRecordStore(); 
        } 
   catch (Exception e) { 
        System.out.println("Fehler beim Schließen von Recordset"); 
        } 
   return(true); 
   } 

private void deleteRecordSet() { 
    
   try { 
       RecordStore.deleteRecordStore("GameState"); 
       } 
   catch (Exception e) { 
       System.out.println("Fehler beim Löschen von Recordset"); 
       e.printStackTrace(); 
       } 
   } 
} 
