package com.haru.tetoru.sample.frame.AI;

import com.haru.tetoru.parts.Debug;
import com.haru.tetoru.parts.Mino;
import com.haru.tetoru.parts.Table;
import com.haru.tetoru.template.Display;
import com.haru.tetoru.template.Player;

public abstract class GameThreadAI implements Runnable {

	/* 進行速度パラメータ */
	protected static int FPS = 60; /* フレームレート */ /* 入力読み取り間隔 */
	protected static int DOWN_RATE = 60; /* 下降頻度 */


	/* 画面 */
	protected Display display
	/* プレイヤー */;
	protected AIPlayer player;


	public GameThreadAI(Display display, AIPlayer player) {
		/* 画面の登録 */
		this.display = display;
		/* プレイヤーを登録 */
		this.player = player;
	}


	/**
	 * ゲーム初期化処理
	 */
	protected abstract void initialize();

	/**
	 * ゲームループ
	 */
	public void run() {
		/* ゲーム進行用変数 */
		Table myTable = new Table();/* テーブル */
		Mino current = null;		/* 操作中のミノ */
		int downCnt = 0;			/* カウンタ(下降用) */

		int retType = Player.OP_NO;	/* 操作の種類 */
		boolean retOperate = false;	/* 操作の復帰値 */
		boolean isGrounding = false;/* 設置中フラグ */
		boolean isSettled = false;	/* 設置確定フラグ */
		boolean retDelLine = false;	/* ライン消去の復帰値 */
		boolean retSetMino = false;	/* 出現可能判定の復帰値 */
		boolean retStartSign = false; /* 開始合図待ちの復帰値 */

		/* ゲーム初期化処理 */
		initialize();
		
		/* テーブル表示 */
		display.disp(myTable.toString());
		Debug.println("init table", myTable.toString());


		/* 開始合図待ち */
		retStartSign = display.waitStartSign(player);
		if (!retStartSign) {
			/* 異常終了 */
		}

		/**********************************************************************/
		/* ミノ出現															  */
		/**********************************************************************/
		/* ミノ生成 */
		current = myTable.initMino();

		/* 出現可能判定はここではしない */

		/* ミノをテーブルに設定 */
		myTable.setMino(current);

		/* テーブル表示 */
		display.disp(myTable.toString());
		player.setTable(myTable);
		player.setCurrentMino(current);
		Debug.println("new block", myTable.toString());
		
		/* ネクストの表示 */
		display.dispNext(myTable.toStringNext());

		/* debug */player.setDisplay((MyGameFrame)display);
		player.plan();
		
		/**********************************************************************/
		/* 移動開始															  */
		/**********************************************************************/
		for (downCnt = 0; ; downCnt=(downCnt+1)%DOWN_RATE) {
			/* 定期的なact */
			player.act(); 
			
			/* ブロック下降タイミングか判定 */
			if (0 == downCnt)  {
// debug //				/* ブロック下降 */
// debug //				isGrounding = !( myTable.moveDown(current) );
				/* テーブル表示 */
				display.disp(myTable.toString());
				player.setTable(myTable);
				player.setCurrentMino(current);
//				Debug.println("down block", myTable.toString());

				/* 下に設置したか判定 */
				if (isGrounding) {
					/* 設置確定 */
					isSettled = true;
					Debug.println("settle①");
				}

			} else {
				/* 操作を読み取り(ノンブロッキング) */
				retType = player.readOperate();

				/* ミノの操作 */
				retOperate = player.doOperate(myTable, current, retType);

				/* テーブル表示 */
				display.disp(myTable.toString());
				player.setTable(myTable);
				player.setCurrentMino(current);

				/* 下に操作したか判定 */
				if (Player.OP_DOWN == retType) {
					/* 下に設置していたか判定 */
					if (isGrounding) {
						/* 下に設置していた場合、設置確定 */
						downCnt = DOWN_RATE - 1;
						Debug.println("設置中に下移動");
					} else {
						/* 下移動できた場合 */
						if (retOperate) {
							/* 下への移動が頻発しないために、次の下移動のタイミングを調整する */
							if (isGrounding) System.err.println("下移動の問題");
							downCnt = 0;							
						/* 下移動できなかった場合 */
						} else {
							/* 設置中にする(設置のタイミングを下降と同様にする) */
							Debug.println("下移動失敗して、すぐ下が地面");
							isGrounding = true;
							downCnt = DOWN_RATE - 1;
						 }
					}
				/* 右か左に操作したか判定 */
				} else if (Player.OP_RIGHT == retType ||
						Player.OP_LEFT == retType) {
					/* 移動できてかつ、地面に設置していた場合 */
					if (retOperate && isGrounding) {
					
						/* 設置の猶予期間を設定する */
						downCnt = 10;
						System.err.println("idle time!!");
						
						/* 下に設置中を解除する */
						/* TODO:isGroundingの仕様が良くない */
						isGrounding = false;
					}
				/* 回転操作したか判定 */
				} else if (Player.OP_ROTATE_RIGHT == retType
						|| Player.OP_ROTATE_LEFT == retType) {
					/* 回転できたか判定 */
					if (retOperate) {
						downCnt = 0;
						if (isGrounding) {
							System.err.println("回転の問題");
							isGrounding = !isGrounding;
						}
					} else {
						Debug.println("回転失敗");
					}
				/* それ以外は何もしない */
				} else {
				}
			}

			/* 設置確定した場合 */
			if (isSettled) {
				/* 設置していない状態にする */
				isSettled = false;
				isGrounding = false;

				/**********************************************************************/
				/* ライン消去														  */
				/**********************************************************************/
				retDelLine = myTable.delMultiLine(current);
				if (retDelLine) {
					/* テーブル表示 */
					display.disp(myTable.toString());
					player.setTable(myTable);
					player.setCurrentMino(current);
					Debug.println("next block", myTable.toString());
					
					/* 削除する前に一時停止 */
					try {
						Thread.sleep(1000/4);
					} catch( InterruptedException e) {
					}
					
					/* 削除された行を詰める */
					myTable.pack();
				}

				/**********************************************************************/
				/* ミノ出現															  */
				/**********************************************************************/
				/* ミノ生成 */
				current = myTable.initMino();

				/* 出現可能判定 */
				retSetMino = myTable.isSetMino(current, current.getX(), current.getY());
				if (!retSetMino) {
					/* ゲーム終了 */
					break;
				}

				/* ミノをテーブルに設定 */
				myTable.setMino(current);

				/* テーブル表示 */
				display.disp(myTable.toString());
				player.setTable(myTable);
				player.setCurrentMino(current);
				Debug.println("next block", myTable.toString());

				/* ネクストの表示 */
				display.dispNext(myTable.toStringNext());
				
				player.plan();
			}

			/* スリープ */
			try {
				Thread.sleep(1000/FPS);
			} catch( InterruptedException e) {
			}
		}

		/**********************************************************************/
		/* 終了処理															  */
		/**********************************************************************/
		Debug.println("終了!!!");

		/* スリープ */
		try {
			Thread.sleep(1000/2);
		} catch( InterruptedException e) {
		}

		/* 再スタート */
		new Thread(this).start();
	}
}
