/**
 * TAKE.java
 *
 *
 * Created: Thu Sep 24 22:59:26 1998 (for Waba B3)
 *
 * Modified: Wed May 06 (for Waba B7)
 *
 * My first Java Program!!
 *
 * @author TAKEchi Masashi
 * @version
 */

import waba.ui.*;
import waba.fx.*;
import waba.io.*;
import waba.sys.*;

/**
 * A control that displays an application's title.
 * taken from Scribble example.
 */
class Title extends Control
{
    String name;
    Font font;
    
    public Title(String name){
	this.name=name;
	this.font=new Font("Helvetica", Font.BOLD, 12);
    }
    
    public void onPaint(Graphics g){
	// draw line across
	g.setColor(0, 0, 0);
	int y = this.height - 1;
	g.drawLine(0, y, this.width, y);
	y--;
	g.drawLine(0, y, this.width, y);
	
	// draw title
	FontMetrics fm = getFontMetrics(font);
	int boxWidth = fm.getTextWidth(name) + 8;
	g.fillRect(0, 0, boxWidth, y);
	g.setColor(255, 255, 255);
	g.setFont(font);
	g.drawText(name, 4, 2);
    }
}

// Cell class
class Cell{
    boolean dot;
    int x, y, a;

    public Cell(int x,int y,int a){
	this.dot=false;
	this.x=x;
	this.y=y;
	this.a=a;
    }

    // set Cell attribute
    public void setCell(boolean att){
	this.dot=att;
    }

    // reverse dot
    public void reverse(){
	if(this.dot==true){
	    this.dot=false;
	}
	else{
	    this.dot=true;
	}
    }

    public boolean check(){
	return this.dot;
    }

    public boolean contains(int x,int y){
	if (x<this.x || x>=this.x+a || y<this.y || y>this.y+a){
	    return false;
	}
	return true;
    }
    
    public void paint(Graphics g){
	g.setColor(0,0,0);
	g.fillRect(x,y,a,a);
	if(this.dot==false){
	    g.setColor(255,255,255);
	    g.fillRect(x+1,y+1,a-2,a-2);
	}
    }
}

// Random class
class Random{
  byte xn,a,b,c;
    public Random(){ // Default constructor uses time as start number
	Time t=new Time();
	a=3;
	b=7;
	c=127;
	xn=(byte)(t.second%c);
    }
    // generate random number
    public byte getRandom(byte n){
	xn=(byte)(((xn*a)+b)%c);
	return (byte)(xn%n);
    }		 
} // Random

// Board class
class Board extends Control{
    // (XMAX * YMAX) must less than 127!
    final byte XMAX=6;
    final byte YMAX=5;
    final byte CELLSIZE=22;
    final String CATALOGNAME=new String("hqVk.DATA");
    private Graphics graphics;
    private Cell[][] Cells=new Cell[XMAX][YMAX];
    private Cell[][] StartCells=new Cell[XMAX][YMAX];

    private byte Qlevel=0;
    private byte Left=0;
    private Random rand=new Random();

    public Board(){
	clear();
	loadState();
    }
    public void added(){
	graphics=createGraphics();
    }

    // initialize
    public void loadState(){
	Catalog c=new Catalog(CATALOGNAME,Catalog.READ_ONLY);
	if(!c.isOpen() || c.getRecordCount()==0 || !c.setRecordPos(0)){
	    return;
	}
	byte[] b=new byte[XMAX*YMAX*2+2];
	c.readBytes(b,0,XMAX*YMAX*2+2);
	c.close();
	int i=0;
	for(byte x=0;x<XMAX;x++){
	    for(byte y=0;y<YMAX;y++){
		if(b[i]==1){
		    Cells[x][y].setCell(true);
		}
		else{
		    Cells[x][y].setCell(false);
		}
		i++;
		if(b[i]==1){
		    StartCells[x][y].setCell(true);
		}
		else{
		    StartCells[x][y].setCell(false);
		}
		i++;
	    }
	}
	Qlevel=b[i++];
	Left=b[i];
    }
    // save current status.
    public void saveState(){
	Catalog c=new Catalog(CATALOGNAME,Catalog.CREATE);
	if(!c.isOpen()){
	    return;
	}
	if(c.getRecordCount()!=XMAX*YMAX*2+2){
	    c.addRecord(XMAX*YMAX*2+2);
	}
	c.setRecordPos(0);
	byte[] b=new byte[XMAX*YMAX*2+2];
	int i=0;
	for(byte x=0;x<XMAX;x++){
	    for(byte y=0;y<YMAX;y++){
		if(Cells[x][y].check()){
		    b[i]=1;
		}
		else{
		    b[i]=0;
		}
		i++;
		if(StartCells[x][y].check()){
		    b[i]=1;
		}
		else{
		    b[i]=0;
		}
		i++;
	    }
	}
	b[i++]=Qlevel;
	b[i]=Left;
	c.writeBytes(b,0,XMAX*YMAX*2+2);
	c.close();
    }

    public void nextGame(){
	Sound.beep();
	// init start pattern
	for(byte x=0;x<XMAX;x++){
	    for(byte y=0;y<YMAX;y++){
		StartCells[x][y].setCell(false);
	    }
	}
	Left=0;
	while(Left==0){
	    // make pattern
	    for(byte i=0;i<Qlevel;i++){
		byte x=rand.getRandom(XMAX);
		byte y=rand.getRandom(YMAX);
		if(x>=0 && x<XMAX && y>=0 && y<YMAX){
		    StarReverse(x,y,false);
		    StartCells[x][y].reverse();
		}
	    }
	}
	this.onPaint(graphics);
    }
    public void resetGame(){
	Sound.beep();
	for(byte x=0;x<XMAX;x++){
	    for(byte y=0;y<YMAX;y++){
		Cells[x][y].setCell(false);
	    }
	}
	Left=0;
	for(byte x=0;x<XMAX;x++){
	    for(byte y=0;y<YMAX;y++){
		if(StartCells[x][y].check()){
		    StarReverse(x,y,false);
		}
	    }
	}
    }
    public void onPaint(Graphics g){
	for(char x=0;x<XMAX;x++){
	    for(char y=0;y<YMAX;y++){
		Cells[x][y].paint(graphics);
	    }
	}
	showStatus();
    }

    public void clear(){    
	Sound.beep();
	for(byte x=0;x<XMAX;x++){
	    for(byte y=0;y<YMAX;y++){
		Cells[x][y]=new Cell(x*CELLSIZE+15,y*CELLSIZE+15,CELLSIZE-2);
		StartCells[x][y]=new Cell(x*CELLSIZE+15,y*CELLSIZE+15,CELLSIZE-2);
	    }
	}
	Left=0;
	Qlevel=0;
    }
    
    public void OneReverse(byte x,byte y,boolean look){
	if(x>=0 && x<XMAX && y>=0 && y<YMAX){
	    Cells[x][y].reverse();
	    if(look==true){
		Cells[x][y].paint(graphics);
	    }
	    if(Cells[x][y].check()==true){
		Left++;
	    }
	    else{
		Left--;
	    }
	}
	else{
	    return;
	}
    }
    // reverse
    public void StarReverse(byte x,byte y,boolean look){
	Sound.beep();
	OneReverse(x,y,look);
	OneReverse((byte)(x-1),y,look);
	OneReverse((byte)(x+1),y,look);
	OneReverse(x,(byte)(y-1),look);
	OneReverse(x,(byte)(y+1),look);
    }
    
    public void onEvent(Event event){
	if(event.type==PenEvent.PEN_DOWN){
	    PenEvent pe=(PenEvent)event;
	    for(byte i=0;i<XMAX;i++){
		for(byte j=0;j<YMAX;j++){
		    if(Cells[i][j].contains(pe.x,pe.y)){
			StarReverse(i,j,true);
		    }
		}
	    }
	    showStatus();
	}
    }
    public void showStatus(){
	if(Left==0){   // clear?
	    graphics.setColor(255,255,255);
	    graphics.fillRect(0,0,width,14);
	    graphics.setColor(0,0,0);
	    graphics.drawText("Wait a moment...",3,2);
	    Qlevel++;
	    nextGame();
	}
	graphics.setColor(255,255,255);
	graphics.fillRect(0,0,width,14);
	graphics.setColor(0,0,0);
	graphics.drawText("Level."+Convert.toString(Qlevel)
			  +" Left."+Convert.toString(Left), 3, 2);
    }
}

// TAKE! main class
public class TAKE extends  MainWindow{
    static final int PLAY=0;
    static final int ABOUT=1;

    private Board board;
    private Button closeButton;
    private Button resetButton;
    private Button fullResetButton;

    int state=PLAY;

    public TAKE() {
	Title title=new Title("TAKE!");
	title.setRect(0,0,this.width,15);
	add(title);
	
	closeButton=new Button("Close");
	closeButton.setRect(0,this.height-15,44,15);
	add(closeButton);
	
	resetButton=new Button("Try again");
	resetButton.setRect(46,this.height-15,44,15);
	add(resetButton);

	fullResetButton=new Button("Full reset");
	fullResetButton.setRect(92,this.height-15,44,15);
	add(fullResetButton);

       	board=new Board();
	board.setRect(0,15,this.width,this.height-40);
	add(board);
	board.added();
    }
    public void onExit(){
	board.saveState();
    }

    public void onEvent(Event event){
	if (event.type==ControlEvent.PRESSED){
	    if(event.target==closeButton){
		exit(0);
	    }
	    else if(event.target==resetButton){
		board.resetGame();
		this.repaint();
	    }
	    else if(event.target==fullResetButton){
		board.clear();
		this.repaint();
	    }
	}
	else if(event instanceof KeyEvent){
	    KeyEvent e=(KeyEvent)event;
	    if (e.key==IKeys.MENU || e.key=='i'){
		drawAbout(new Graphics(this),state!=ABOUT);
	    }
	}
	else if(event instanceof PenEvent){
	    PenEvent e=(PenEvent)event;
	    switch(e.type){
	    case PenEvent.PEN_DOWN:
		if(state==ABOUT){
		    drawAbout(new Graphics(this),false);
		    return;
		}
	    }
	}
    }

    public void drawRect(Graphics g,int x,int y,int w,int h){
	g.setColor(255,255,255);
	g.fillRect(x,y,w,h);
	g.setColor(0,0,0);
	w--;
	h--;
	g.drawLine(x,y,x+w,y);
	g.drawLine(x+w,y,x+w,y+h);
	g.drawLine(x,y,x,y+h);
	g.drawLine(x,y+h,x+w,y+h);
    }

    public void drawCenteredText(Graphics g,String s,int x,int y){
	FontMetrics fm=getFontMetrics(defaultFont);
	g.drawText(s,x-fm.getTextWidth(s)/2,y-fm.getAscent()/2);
    }

    public void drawAbout(Graphics g,boolean b){
	int w=width;
	int h=height/2;
	if(b){
	    Sound.beep();
	    Sound.tone(2000,200);
	    Sound.tone(4000,200);
	    g.translate(0,height/4);
	    state=ABOUT;
	    drawRect(g,0,0,w,h);
	    drawCenteredText(g,"TAKE! v.2.0",w/2,h/5);
	    drawCenteredText(g,"by TAKEchi Masashi",w/2,2*h/5);
	    drawCenteredText(g,"take@TAKEchon.NET",w/2,3*h/5);
	    drawCenteredText(g,"http://www.TAKEchon.NET/",w/2,4*h/5);
	    g.translate(0,-height/4);
	}
	else{
	    state=PLAY;
	    damageRect(0,height/4,w,h);
	}                                           
    }
} // TAKE