package hussam.wireless.games.beans;
/**
 *
 *@author Hussam-Al-Mulhim
 *@version 2.2.4
 */


import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
import javax.microedition.rms.*;
import java.util.*;

public class LastBean extends MIDlet{
	static Display display;
	static LastBean lastBean ;
	public void startApp(){
		lastBean=this;
		display=Display.getDisplay(this);
		Canvas canvas=new BeanCanvas();
		display.setCurrent(canvas);
	}
	public void destroyApp(boolean force){}
	public void pauseApp(){}

}


class TooManyBeansException extends Exception{
	TooManyBeansException(String x){
		super(x);
	}
}
class AvailableBeans{
	int set;
	int total;
	Vector beans;
	AvailableBeans(int amount, int set)throws TooManyBeansException{
		if(amount<set)throw new TooManyBeansException("Batch should be lower than Total amount");
		if(set>9)throw new TooManyBeansException("Beans Batch should be lower than 10.");
		total=amount;
		this.set=set;
		createBeans();
	}
	private void createBeans(){
		beans=new Vector(total);
		
		for(int i=0;i<total;i++){
			beans.addElement(new Bean());
		}	
	}
	void restart(){
		createBeans();
	}
	public int getMaximumBatch(){
		return set;
	}
	public int getAvailableBeansCount(){
		return beans.size();
	}
	public Vector getBeans(int amount)throws TooManyBeansException{
		if(amount==0)throw new TooManyBeansException("You cannot have 0 Beans.");
		if(amount>set)
			throw new TooManyBeansException("You can have up to "+set+" beans");
		if(hasFinished())throw new TooManyBeansException("Beans have finished");
		if(amount>beans.size())amount=beans.size();
		Vector batchBeans=new Vector();
		for(int i=0;i<amount;i++){
			batchBeans.addElement(getBean());
		}
		return batchBeans;
	}
	public boolean hasFinished(){
		return beans.size()==0;
	}
	private Bean getBean(){
		Bean bean=(Bean)beans.elementAt(0);
		beans.removeElementAt(0);
		return bean;
	}


}
class BeanCanvas extends Canvas implements CommandListener{
	static final int BASE=48;
	static final String VERSION="2.2.4";
	private static BeanCanvas beanCanvas;
	private static Display display;
	
	boolean quickMotion=false;
	BeanDrawer drawer;
	AvailableBeans availableBeans;
	BeanEater eater1, eater2, firstPlayer, secondPlayer;
	Font font=Font.getFont(Font.FACE_SYSTEM, Font.STYLE_PLAIN, Font.SIZE_SMALL);
	int userInput=0;
	Thread gameThread;
	Command changePlayers;
	Command whoIsFirst;
	Command changeGrid;
	Command changeBatch;
	Command restart;
	Command about;
	Command gameHelp;
	Command exit;
	Command quick;
	Game game;
	BeanCanvas(){
		beanCanvas=this;
		setupCommands();
		changePlayers("عبدالله", "", 1);
		try{
			changeBatch(20,2);
		}catch(TooManyBeansException e){
			e.printStackTrace();
		}
		startGame();
		display=LastBean.display;
	}
	private void setupCommands(){
		changePlayers=new Command("تغيير اللاعب", Command.ITEM, 1);
		changeGrid=new Command("حجم الشبكة", Command.ITEM, 1);
		changeBatch=new Command("مسافة الوصول والقفز", Command.ITEM, 1);
		whoIsFirst=new Command("تغيير من يلعب أولا", Command.ITEM, 1);
		restart=new Command("إعادة اللعبة", Command.OK, 1);
		about=new Command("حول البرنامج", Command.HELP, 1);
		gameHelp=new Command("مساعدة", Command.HELP, 1);
		exit=new Command("خروج", Command.EXIT, 1);
		quick=new Command("تغيير السرعة", Command.ITEM, 2);
		addCommand(changePlayers);
		addCommand(changeBatch);
		addCommand(whoIsFirst);
		addCommand(restart);
		addCommand(quick);
		addCommand(changeGrid);
		addCommand(about);
		addCommand(gameHelp);
		addCommand(exit);
		setCommandListener(this);
	}
	public void exit(){
		LastBean.lastBean.notifyDestroyed();
	}
	public void changeBatch(int amount, int batch)throws TooManyBeansException{
		
		availableBeans=new AvailableBeans(amount, batch);
		int row=200;
		int col=200;
		int minimum=10000;
		for(int i=50;i>=1;i--){
			for(int o=50;o>=1;o--){
				if((i*o)>=amount&minimum>(i+o)){
					row=o;
					col=i;
					minimum=row+col;
				}
			}
		}
		setTable(col,row);
	}
	public void changePlayers(String name, String other, int type){
		eater1=new BeanEater(name);
		switch (type){
			case 0: eater2=new BeanEater(other);
			break;
			case 1: eater2=new RandomEater();
			break;
			case 2: eater2=new LittleBitSmartEater();
			break;
			case 3: eater2=new HussamEater();
			break;
		}
		firstPlayer=eater1;
		secondPlayer=eater2;
	}
	private void switchPlayers(){
		BeanEater b=firstPlayer;
		firstPlayer=secondPlayer;
		secondPlayer=b;
	}
	protected BeanEater firstPlayer(){
		return firstPlayer;
	}
	protected BeanEater secondPlayer(){
		return secondPlayer;
	}
	protected BeanEater otherPlayer(BeanEater b){
		if(b==firstPlayer())return secondPlayer();
		return firstPlayer();
	}
	public void setTable(int col, int row){
		if(col<1|row<1)throw new RuntimeException("Table row and col should be positive integers.");
		drawer=new BeanDrawer(col, row);
	}
	public void startGame(){
		if(game!=null)game.finish();
		synchronized(firstPlayer()){
			firstPlayer().notifyAll();
		}synchronized(secondPlayer()){
			secondPlayer().notifyAll();
		}
//		System.out.println("NOTIFIED ALL");
		game=new Game(){
			BeanEater player=firstPlayer();
			boolean finished=false;
			public boolean isFinished(){
				return finished;
			}
			public void start(){
				System.out.println("New Game>>>>>>>>>>");
				System.out.println(eater1.beans().size()+"\t"+eater2.beans.size());
				new Thread(new Runnable(){
	//				BeanEater player;
					public void run(){
						availableBeans.restart();
						firstPlayer().restart();
						secondPlayer().restart();
						while(!isFinished()){
							if(availableBeans.hasFinished()){
								swap();
								LastBean.display.setCurrent(new Alert("الفائز",player.name(),null, AlertType.INFO));
								finish();
								return;
							}
							repaint();
							player().play();
							System.out.println(player().name()+" Has Played.");
							swap();
						}	
					}
						
				}).start();
			}
			private void swap(){
				if(player==firstPlayer())player=secondPlayer();else player=firstPlayer();
			}
			
			public void finish(){
				finished=true;
			}
			public BeanEater player(){
				return player;
			}
		};
		game.start();		
				
//		nextEater();
	}
	interface Game{
		void start();
		void finish();
		BeanEater player();
		boolean isFinished();
	}
	private Game game(){
		return game;
	}
	public final void play(final BeanEater eater, final int amount){
		final Canvas canvas=this;
		if(quickMotion){
			try{
				eater.eatBeans(availableBeans.getBeans(amount));
				repaint();
//				nextEater();
			}catch(TooManyBeansException e){
				e.printStackTrace();
				eater.play();
			}
			
			
			return;
		}//*/
		Thread motion=new Thread(new Runnable(){
			
			public void run(){
	//			nextEater();
				try{
					for(int i=0;i<amount;i++){
						eater.eatBeans(availableBeans.getBeans(1));
						
						try{
							Thread.currentThread().sleep(250);
						}catch(InterruptedException e){
							e.printStackTrace();
						}
						eater.lastPlay=amount;
						repaint();
						
					}
					synchronized(canvas){
						canvas.notify();
					}
				}catch(TooManyBeansException e){
					e.printStackTrace();
				}
				
			}
			
		});
		
		motion.start();
		synchronized(canvas){
			try{
				canvas.wait();
			}catch(Exception e){
				e.printStackTrace();
			}
		}
		
	}

	public void keyPressed(int key){
		userInput=key-BASE;
		if(userInput>9|userInput<1)return;
		synchronized(game.player()){
			game.player().notify();
		}
	}
	public int getUserInput(){
		
		return userInput;
			
	}
		
/*
	BeanEater nextEater(){
		final BeanEater b=currentEater;
		new Thread(new Runnable(){
			public void run(){
				currentEater.play();
				if(availableBeans.hasFinished()){
					LastBean.display.setCurrent(new Alert("الفائز",currentEater.name(),null, AlertType.INFO));
			//		return currentEater;
				}
				if(currentEater==eater1)currentEater=eater2;
				else currentEater=eater1;
			}
		}).start();

		return currentEater;
	}
//*/	
	public int getTableHeight(){
//		return getHeight();
		return getHeight()-2*font.getHeight();
	}
	public int getTableWidth(){
		return getWidth();
	}
	public int getFirstRowPosition(){
	//	return 0;
		return 1*font.getHeight();
	}
	public int getFirstColPosition(){
		return 0;
	}
	public void paint(Graphics g){
		g.setFont(font);
		g.setColor(0,0,0);
		g.fillRect(0,0,getWidth(),getHeight());

		drawer.startOver();
		
		g.setColor(255,0,0);
		drawer.paint(g, eater1.beans().size());
				
		g.setColor(0,255,0);
		drawer.paint(g,availableBeans.getAvailableBeansCount());
		
		g.setColor(0,0,255);
		drawer.paint(g, eater2.beans().size());
		
/*		g.drawString(game().player().name()+"'s turn. "+
			availableBeans.getAvailableBeansCount()+" beans remaining. "+
			"Max: "+availableBeans.getMaximumBatch(), 0, 0, 0);
		g.drawString(
			eater1.name()+
			".\t Ate: "+eater1.beans().size()+
			"\t Last play: "+eater1.lastPlay(), 0,font.getHeight(),0);
		g.drawString(
			eater2.name()+
			".\t Ate: "+eater2.beans().size()+
			"\t Last play: "+eater2.lastPlay(), 0,getHeight()-font.getHeight(),0);
			
//*/	
		String up="دور: "+
		game().player().name()+".  "+
		"الحد الأقصى: " + availableBeans.getMaximumBatch();
		String down="الباقي: " + availableBeans.getAvailableBeansCount()+".  "+
		" آخر لعبة: "+otherPlayer(game().player()).lastPlay()+".";
			
		g.setColor(0,0,0);
		g.fillRect(0,0, font.stringWidth(up), font.getHeight());
		g.fillRect(0, getHeight()-font.getHeight(), font.stringWidth(down), font.getHeight());
		g.setColor(255,255,255);
		g.drawString(up, 0,0,0);
		g.drawString(down, 0,getHeight()-font.getHeight(),0);

		
	}
	

	
	
	public class BeanDrawer{
		int beanHeight;
		int beanWidth;
		int position=0;
		int col,row;
		BeanDrawer(int x,int y){
			col=x;
			row=y;
			beanHeight=(int)(getTableHeight()/row);
			beanWidth=(int)(getTableWidth()/col);
		}
		public void startOver(){
			position=0;
		}
		public void paint(Graphics g, int boxes){
			int total=position+boxes;
			int color=g.getColor();
			while(position!=total){
				int c=(position%col);//
				int r=(position/col);//
		//		System.out.println(position%col+"\t"+position/row);
				g.setColor(color);
	//			g.fillRect(c*beanWidth,r*beanHeight+getFirstRowPosition(),beanWidth-1, beanHeight-1);
	//			g.setColor(200);
				g.fillArc(c*beanWidth,r*beanHeight+getFirstRowPosition(),beanWidth-1, beanHeight-1, 0, 360);
				g.setColor(0,0,0);
				String word= String.valueOf(position+1);
	//			g.drawString(word, c*beanWidth+beanWidth/2-font.stringWidth(word)/2,r*beanHeight+getFirstRowPosition()+beanHeight/2-font.getHeight()/2,0);
				position++;
			}
			
		}
	}
	public void commandAction(Command c, Displayable d){
		if(c==restart)startGame();
		else if(c==changeGrid)ChangeGridForm.start();
		else if(c==changeBatch){ChangeBatchForm.start();}
		else if(c==changePlayers){ChangePlayerForm.start();}
		else if(c==about)AboutForm.start();
		else if(c==quick)quickMotion=!quickMotion;
		else if(c==gameHelp)GameHelpForm.start();
		else if(c==whoIsFirst){ChangeWhoIsFirstForm.start();}
		else if(c==exit)exit();
		
	}

	static class ChangeGridForm extends Form implements CommandListener{
		TextField col,row;
		Command back, ok;
		static Form form=new ChangeGridForm();
		ChangeGridForm(){
			super("تغيير حجم المربعات");
			col=new TextField("عدد الأعمدة", 10+"", 2, TextField.NUMERIC);
			row=new TextField("عدد الصفوف", 10+"", 2,TextField.NUMERIC);
			append(col);
			append(row);
			append("تأكد بوضع قيم أكبر من الصفر.");
			back=new Command("رجوع",Command.BACK, 1);
			ok=new Command("موافق",Command.OK, 1);
			addCommand(ok);
			addCommand(back);
			setCommandListener(this);
		}
		
		public void commandAction(Command c, Displayable d){
			if(c==ok){
				try{
					beanCanvas.setTable(Integer.parseInt(col.getString()), Integer.parseInt(row.getString()));
					display.setCurrent(beanCanvas);
				}catch(RuntimeException e){
					e.printStackTrace();
				}
			}else if(c==back){
				display.setCurrent(beanCanvas);
			}
		}
		public static void start(){
			display.setCurrent(form);
		}
	}
	static class ChangeBatchForm extends Form implements CommandListener{
		TextField amount,batch;
		Command back, ok;
		static Form form=new ChangeBatchForm();
		ChangeBatchForm(){
			super("تغيير عدد الحبوب");
			amount=new TextField("عدد الحبوب الكلي", ""+30, 3, TextField.NUMERIC);
			batch=new TextField("أعلى حد للأكل ", ""+3, 1,TextField.NUMERIC);
			append(amount);
			append(batch);
			append("تأكد أن عدد الحبوب يجب أن يكون أكبر من حد الأكل.");
			append("\n");
			append("كما أن الحد يجب أن يكون أقل من العشرة.");
			append("\n");
			append("إذا كان عدد الحبوب كبيرا، لا تنس تغيير حجم الصفحة بعد ذلك!");
			back=new Command("رجوع",Command.BACK, 1);
			ok=new Command("موافق",Command.OK, 1);
			addCommand(ok);
			addCommand(back);
			setCommandListener(this);
		}
		
		public void commandAction(Command c, Displayable d){
			if(c==ok){
				try{
					beanCanvas.changeBatch(Integer.parseInt(amount.getString()), Integer.parseInt(batch.getString()));
					beanCanvas.startGame();
					display.setCurrent(beanCanvas);
				}catch(Exception e){
					e.printStackTrace();
				}
			}else if(c==back){
				display.setCurrent(beanCanvas);
			}
		}
		public static void start(){
			display.setCurrent(form);
		}
	}
	static class ChangePlayerForm extends Form implements CommandListener{
		TextField name,other ;
		ChoiceGroup choice;
		Command back, ok;
		static  final Form form=new ChangePlayerForm();
		public static void start(){
			display.setCurrent(form);
		}
		ChangePlayerForm(){
			super("تغيير حجم المربعات");
			name=new TextField("اللاعب الأول", "عبدالله", 20, TextField.ANY);
			other=new TextField("اللاعب الثاني","خالد", 20,TextField.ANY);
			String[]items= {"شخص","حاسب غبي","حاسب ذكي", "حسام"};
			choice=new ChoiceGroup("نوع اللاعب الثاني", ChoiceGroup.EXCLUSIVE,items, null);
			back=new Command("رجوع", Command.BACK, 1);
			ok=new Command("موافق",Command.OK, 1);
			append(name);
			append(other);
			append(choice);
			addCommand(ok);
			addCommand(back);
			setCommandListener(this);
		}
		
		public void commandAction(Command c, Displayable d){
			if(c==ok){
				try{
					beanCanvas.changePlayers(name.getString(), other.getString(), choice.getSelectedIndex());
					beanCanvas.startGame();
					display.setCurrent(beanCanvas);
				}catch(RuntimeException e){
					e.printStackTrace();
				}
			}else if(c==back){
				display.setCurrent(beanCanvas);
			}
		}
		
	}
	static class ChangeWhoIsFirstForm extends Form implements CommandListener{
		Command back, ok;
		static  final ChangeWhoIsFirstForm form=new ChangeWhoIsFirstForm();
		public static void start(){
			form.update();
			display.setCurrent(form);
		}
		ChangeWhoIsFirstForm(){
			super("من يلعب أولا؟");
			back=new Command("رجوع", Command.BACK, 1);
			ok=new Command("تغيير",Command.OK, 1);
//			update();
			addCommand(ok);
			addCommand(back);
			setCommandListener(this);
		}
		private void update(){
			try{
				delete(0);
				delete(0);
			}catch(IndexOutOfBoundsException e){
				System.out.println(e.getMessage());
			}
			append("اللاعب الأول: "   +beanCanvas.firstPlayer().name());
			append("اللاعب الثاني: "   +beanCanvas.secondPlayer().name());
		}
		
		public void commandAction(Command c, Displayable d){
			if(c==ok){
				try{
					beanCanvas.switchPlayers();
					form.update();
				}catch(RuntimeException e){
					e.printStackTrace();
				}
			}else if(c==back){
				beanCanvas.startGame();
				display.setCurrent(beanCanvas);
			}
		}
		
	}
	static class AboutForm extends Form implements CommandListener{
		Command back;
		static Form form=new AboutForm();
		AboutForm(){
			super("حول البرنامج");
			back=new Command("رجوع",Command.BACK, 1);
			append("برنامج آخر حبة");
			append("\n");
			append("تطوير حسام الملحم");
			append("\n");
			append("الإصدار");
			append(VERSION);
			append("\n");
			append("جوال 0504812912");
			append("\n");
			append("المرسال: ");
			append("hussam@kfupm.edu.sa");
			append("\n");
			append("أو: ");
			append("hmulhim@gawab.com");
			append("\n");
			append("لغيرها من البرامج توجه إلى");
			append("\n");
			append("http://faculty.kfupm.edu.sa/MISAC/Hussam/");
			append("\n");
			append("مع الشكر والتقدير للفريق العربي للبرمجة");
			append("\n");
			append("www.arabteam2000.com");
			append("\n");
			append(" لإصدارات جديدة أو برامج جديدة توجه إلى الصفحات السابقة.");
			addCommand(back);
			setCommandListener(this);
		}
		
		public void commandAction(Command c, Displayable d){
			if(c==back){
				display.setCurrent(beanCanvas);
			}
		}
		public static void start(){
			beanCanvas.startGame();
			display.setCurrent(form);
		}
	}
	static class GameHelpForm extends Form implements CommandListener{
		Command back;
		static Form form=new GameHelpForm();
		GameHelpForm(){
			super("مساعدة");
			back=new Command("رجوع",Command.BACK, 1);
			append("حاول أكل آخر حبة: كما تعرف فإن آخر حبة هي ألذ حبة، لذلك توجب عليك أن تخطط لتأكل آخر حبة.");
			append("\n");
			append("كلما جاء دورك، تستطيع التهام من حبة إلى العدد المتفق عليه مسبقا.");
			append("\n");
			append("تستطيع مباراة أخ لك أو الحاسب أو أن تتحدى حساما بنفسه.");
			append("\n");
			append("من خلال الخيارات تستطيع تغيير حجم الطاولة وعدد الحبات وعدد ما تستطيع التهامه في المرة الواحدة.");
			append("\n");
			append("هل تستطيع أن تأكلها؟");
			addCommand(back);
			setCommandListener(this);
		}
		
		public void commandAction(Command c, Displayable d){
			if(c==back){
				display.setCurrent(beanCanvas);
			}
		}
		public static void start(){
			display.setCurrent(form);
		}
	}

	class RandomEater extends BeanEater{
		Random random;
		RandomEater(){
			this("حاسب غبي");
		}
		RandomEater(String name){
			super(name);
			random=new Random();
		}
		protected int compute(){
			return Math.abs(random.nextInt())%availableBeans.getMaximumBatch()+1;
			
		}
	}
	class LittleBitSmartEater extends HussamEater{
		LittleBitSmartEater(){
			super("حاسب ذكي");
		}
		protected int compute(){
			final Game thisGame=game();
			int amount=availableBeans.getAvailableBeansCount();
			int batch=availableBeans.getMaximumBatch();
			if(amount<=batch*3)super.compute();
			return Math.abs(random.nextInt())%availableBeans.getMaximumBatch()+1;
		}
		
	}
	class HussamEater extends RandomEater{
		HussamEater(String name){
			super(name);
		}
		HussamEater(){
			this("حسام");
		}
		protected int compute(){
			final Game thisGame=game();
			int amount=availableBeans.getAvailableBeansCount();
			int batch=availableBeans.getMaximumBatch();
			int play=amount%(batch+1);
	//		if(thisGame.isFinished())return;
			if(play==0)return super.compute();
			else return play;
		}
	}
	
	class BeanEater{
		Vector beans;
		String name;
		int lastPlay=0;
		boolean play=true;
		BeanEater(String name){
			this.name=name;
			beans=new Vector();
		}
		void restart(){
			beans.removeAllElements();
		}
		public final void play(){
			int no=compute();
			if(no==0)return;
			BeanCanvas.this.play(this, no);
		}
		protected int compute(){
			final Game thisGame=game();
			System.out.println(play);
			if(!play)return 0;
			
			synchronized(this){
				try{
					play=false;
					System.out.println(name+"is waiting....");
					wait();
					play=true;
					if(thisGame.isFinished())return 0;
				}catch(InterruptedException e){
					e.printStackTrace();
					return 0;
				}
				System.out.println(name+" is Notified..");
				return getUserInput();
			}
			
		}
		void eatBeans(Vector beans){
			lastPlay=beans.size();
			Enumeration e=beans.elements();
			while(e.hasMoreElements()){
				this.beans.addElement(e.nextElement());
			}
			
		}
		public Vector beans(){
			return beans;
		}
		public int lastPlay(){
			return lastPlay;
		}
		public String name(){
			return name;
		}
		public String toString(){
			return name+" has "+beans.size()+" beans.";
		}
	}
}


	


class Bean{
	int color;
	static final int EMPTY=0;
	static final int BLACK=1;
	static final int WHITE=2;
	static final int BEAN=3;
	Bean(){
		
	}
	void setType(int type){
		color=type;
	}
	int getType(){
		return color;
	}

}

