module kyojintati4d.taskselector;

private import y4d;
private import y4d_aux.filesys;
private import y4d_draw.textureloader;
private import y4d_thread.gamescenetransiter;

private import kyojintati4d.myapp;
private import kyojintati4d.gameinfo;
private import kyojintati4d.userinfo;
private import kyojintati4d.bookmark;
private import kyojintati4d.taskyesno;
private import kyojintati4d.taskeyecatche;

private import yamalib.gui.guibutton;
private import yamalib.gui.keygroup;
private import yamalib.counterfsp;
private import yamalib.log.log;

/**
	シナリオ選択タスク
*/
/// ScenarioDrawテスト
class TaskSelector : GameTaskBase {
	
	/// 毎回呼び出す
	override int onMove(Object o) {
		try {
			GameInfo info = cast(GameInfo) o;
			
			if (!init) {
				onInit(info);
				init = true;
			}
			
			m_mouse.update();
			// ダイアログ表示中は何もしない
			if (info.isShowYesNo) {
				return 0;
			}

			if (showDialog && TaskYesNo.CLICK.NO_CLICK != info.yesnoClick) {
				Log.print("TASK_SCENARIO CLICK!!");
				// 上書き承認
				if (TaskYesNo.CLICK.YES == info.yesnoClick) {
					info.setData(m_param);
					info.hideDialog();
					// 一度描画させて、ダイアログを消してから遷移する
					exitScene = true;
					Log.print("JUMP SCENARIO TASK");
					return 0;
				}
				showDialog = false;
			}
	
			int mx,my;
			m_mouse.getPos(mx,my);
			bool bL = m_mouse.isLButtonUp();
			
			// フォーカス処理
			if (info.key.isPush(3)) {
				m_keyGroup.prev();
			} else if (info.key.isPush(4)) {
				m_keyGroup.next();
			}
			
			// ボタン
			foreach(int i,inout GUIButton bt; m_titleButtons) {
				if (i <= BT_MAIN_MAX + 1) {
					continue;
				}
				bt.onMove(info.screen);
				if (bt.isIn()) {
					buttonActive(i);
				}
				if ( bt.isLClick() ) {
					// GameInfo オブジェクトを通して、選択されたシナリオを引き渡す
					m_param[0] = KyojinConst.Task.Task_Scenario;	// 呼び出してほしいタスクね
					m_param[1] = texStoryMap[i];	// 呼び出してほしいシナリオ番号ね
//					m_param[2] = eyeTypeMap[ m_param[1] ];	// 呼び出してほしいアイキャッチ（シナリオに対応したやつってこと）ね

					foreach (inout Bookmark bm; info.bookmark) {
						if (bm.isAuto()) {
							if (bm.isUse()) {
								// 上書き警告ダイアログ
								showDialog = true;
								info.showDialog(TaskYesNo.TYPE.OVERWRITE);
								break;
							}
						} 
					}

					if (!showDialog) {
						info.setData(m_param);
						jumpScenarioViaTelop(info, texStoryMap[i]);
						return 1;
					}
				}
			}
			
			btBack.onMove(info.screen);
			if ( !showDialog && btBack.isLClick() ) {
				// もどる！
				returnScene(info);
				info.playSystemSE(SYS_SE.CLICK_TITLE_NEGATIVE);
				
				return 1;
			}
	
			return 0;
		} catch (Exception e) {
			Log.printFatal("RuntimeException %s#onMove : [%s] [%s]", 
				super.toString(), e.toString(), e.msg);
			throw e;
		}
	}
	
	/// 毎回呼び出すなり
	override int onDraw(Object o) {
		try {
			GameInfo info = cast(GameInfo) o;
	
			if (!init) {
				onInit(info);
				init = true;
			}
			
			info.screen.clear();
			info.screen.blendSrcAlpha();
			
			// 背景描画
			info.screen.blt(m_imgBg,0,0);

			// パーツ描画
			foreach (int i, inout bool b; this.readFlags) {
				if (!b) {
					continue;
				}
				if ( CLASS.ACTOR == i ) {
					// アクターの足切り描画
					info.screen.blt( m_seqParts.get(i), OBJ_POS[i].x, OBJ_POS[i].y, &this.rcActor );
				} else if ( CLASS.S02 == i ) {
					// シナリオ２の足きり描画
					info.screen.blt( m_seqParts.get(i), OBJ_POS[i].x, OBJ_POS[i].y, &this.rc2nd );
				} else {
					info.screen.blt( m_seqParts.get(i), OBJ_POS[i].x, OBJ_POS[i].y );
				}
			}
			
			if (this.m_gameEnd) {
				info.screen.blt(m_imgLastMsg, LAST_MSG_X, LAST_MSG_Y);
			}
			
			info.screen.setColor(255, 255, 255);
			int offsetw = cast(int) m_imgTerm.getWidth() / 2;
			int offseth = cast(int) m_imgTerm.getHeight() / 2;
			
			// ターミネータ描画
			for (int i = 0; i < TERMI.length; ++i) {

				if ( !termiFlags[i] ) {
					continue;
				}
				info.screen.blt(m_imgTerm, TERMI[i].x - offsetw, TERMI[i].y - offseth);
			}

			// ボタン描画
			foreach(int i,inout GUIButton bt; m_titleButtons) {
				bt.onDraw(info.screen);
			}
			
			// ボタン描画
			btBack.onDraw(info.screen);
			
			// シナリオ名描画
			info.screen.blt(m_titleNames.get(this.m_selectedIndex), TITLE_NAME_X, TITLE_NAME_Y);
			
			if (exitScene) {
				jumpScenarioViaTelop(info, m_param[1]);
				return -1;
			}
			
			return 0;
		} catch (Exception e) {
			Log.printFatal("RuntimeException %s#onDraw : [%s] [%s]", 
				super.toString(), e.toString(), e.msg);
			throw e;
		}
	}
	
	/// レガシーなやつ
	override int task(Object o) {
		return 0;
	}

	/// メモリリーク回避
	override void destroy() {
		m_mouse = null;
		readFlags = null;
		termiFlags = null;
		btBack = null;
		m_imgTerm = null;
		
		if ( !(m_seqParts is null) ) {
			m_seqParts.releaseAll();
			m_seqParts.releaseFileList();
		}
		if ( !(m_titleNames is null) ) {
			m_titleNames.releaseAll();
			m_titleNames.releaseFileList();
		}
		
		m_titleButtons = null;
		m_keyGroup = null;
 
		Texture.safeRelease(m_imgLastMsg);
		Texture.safeRelease(m_imgTerm);
		Texture.safeRelease(m_imgBg);

		Log.print("%s#destroy : destroyed.", super.toString());
	}
	
	
	/// コンストラクタ
	this() {
		m_keyGroup = new KeyGroup();
	}
	
	/// 静的コンストラクタ
	static this() {
		int[int] tmp;
		int i = 0;
		tmp[i++] = KyojinConst.ScenarioID.NOT_DATA;
		tmp[i++] = KyojinConst.ScenarioID.STORY01;
		tmp[i++] = KyojinConst.ScenarioID.STORY02_0;
		tmp[i++] = KyojinConst.ScenarioID.STORY03;
		tmp[i++] = KyojinConst.ScenarioID.STORY04;
		tmp[i++] = KyojinConst.ScenarioID.STORY05;
		tmp[i++] = KyojinConst.ScenarioID.STORY06;
		tmp[i++] = KyojinConst.ScenarioID.STORY07;
		tmp[i++] = KyojinConst.ScenarioID.KYOJIN01;
		tmp[i++] = KyojinConst.ScenarioID.KYOJIN02;
		tmp[i++] = KyojinConst.ScenarioID.KYOJIN03;
		texStoryMap = tmp;

		int[int] tmp1;
		tmp1[KyojinConst.ScenarioID.STORY01] = TaskEyeCatche.SHI_TYPE.TOMIE01;
		tmp1[KyojinConst.ScenarioID.STORY02_0] = TaskEyeCatche.SHI_TYPE.ANZAI01;
		tmp1[KyojinConst.ScenarioID.STORY03] = TaskEyeCatche.SHI_TYPE.ALICE01;
		tmp1[KyojinConst.ScenarioID.STORY04] = TaskEyeCatche.SHI_TYPE.ALICE01;
		tmp1[KyojinConst.ScenarioID.STORY05] = TaskEyeCatche.SHI_TYPE.ALICE01;
		tmp1[KyojinConst.ScenarioID.STORY06] = TaskEyeCatche.SHI_TYPE.MIDO01;
		tmp1[KyojinConst.ScenarioID.STORY07] = TaskEyeCatche.SHI_TYPE.AYA01;
		eyeTypeMap = tmp1;
	}
	
	/// デストラクタ
	~this() {
	}
	
private:
	/// シーケンスオブジェクトの有効矩形の枠サイズ
	static const int F_SIZE = 2;
	
	enum CLASS : int {ACTOR=0,S01,S02,S03,S04,S05,S06,S07,K01,K02,K03};

	/// 初期化処理
	void onInit(GameInfo info) {
		// メモリー状況をプリント
		GameInfo.printMemoryState();

		// マウス情報
		m_mouse = info.keyDecolateMouse;
		
		m_selectedIndex = CLASS.S01;

		// パーツ画像読み込み
		m_seqParts = new TextureLoader();
		m_seqParts.loadDefFile(cast(char[]) "img/sequence/parts.lst");
		
		// タイトル名
		m_titleNames = new TextureLoader();
		m_titleNames.loadDefFile(cast(char[]) "img/sequence/title_name.lst");

		// 描画フラグ初期化
		initFlags(info.userInfo);
		
		if (this.m_gameEnd) {
			m_imgLastMsg = new Texture();
			m_imgLastMsg.load(cast(char[]) "img/sequence/seq_actor2.png");
		}
		
		// 背景画像ロード
		m_imgBg = new Texture();
		m_imgBg.load(cast(char[]) "img/sequence/seq_bg.png");
		
		// 終端画像（×）ロード
		m_imgTerm = new Texture();
		m_imgTerm.load(cast(char[]) "img/sequence/seq_trm.png");
		
		// ボタン初期化
		initTitleButtons();
				
		// 「戻る」ボタン
		auto tl = new TextureLoader();
		tl.loadDefRW( FileSys.read(cast(char[]) "img/sequence/back_bt.lst") );
		auto v  = new GUIBlinkButtonListener();
		v.setTextureLader(tl,0);
		v.setType(BT_TYPE_BACK);
		v.setBlinkSpeed(4);

		btBack = new GUIButton();
		btBack.setMouse(m_mouse);
		btBack.setEvent(v);
		btBack.setXY(BACK_BT_X,BACK_BT_Y);
		
		m_keyGroup.add(btBack);
		
		// デフォルト選択
		buttonActive(CLASS.S01);
		m_keyGroup.focus(m_titleButtons[CLASS.S01]);
	}
	
	
	/// ユーザ情報から描画用フラグの初期化を行います
	void initFlags(UserInfo ui) {
		// とりあえず既読フラグをコピー
		bool[] flags = ui.getReadFlags();
		this.readFlags = null;
		this.termiFlags = null;

/*/ ---------------------- DEBUG		
flags[KyojinConst.ScenarioID.STORY01] = true;
flags[KyojinConst.ScenarioID.STORY02_0] = true;
flags[KyojinConst.ScenarioID.STORY02_1] = true;
flags[KyojinConst.ScenarioID.STORY02_2] = true;
flags[KyojinConst.ScenarioID.STORY03] = true;
flags[KyojinConst.ScenarioID.STORY04] = true;
flags[KyojinConst.ScenarioID.STORY05] = true;
flags[KyojinConst.ScenarioID.STORY06] = true;
flags[KyojinConst.ScenarioID.STORY07] = false;
flags[KyojinConst.ScenarioID.KYOJIN01] = false;
flags[KyojinConst.ScenarioID.KYOJIN02] = false;
flags[KyojinConst.ScenarioID.KYOJIN03] = false;
// ---------------------- DEBUG		/*/

		// 一個多いのはアウター
		this.readFlags = new bool[flags.length + 1];
		this.termiFlags = new bool[flags.length + 1];
		
		// 最初はアウター
		this.readFlags[CLASS.ACTOR] = true;
		// シナリオ１は常に選択可能
		this.readFlags[CLASS.S01] = true;
		this.readFlags[CLASS.S02] = true;
		this.termiFlags[CLASS.S01] = true;
		this.readFlags[CLASS.S03] = true;
		this.readFlags[CLASS.S06] = true;
		this.readFlags[CLASS.S04] = true;
		this.termiFlags[CLASS.S03] = true;
		this.readFlags[CLASS.S05] = true;
		this.termiFlags[CLASS.S04] = true;
		this.termiFlags[CLASS.S05] = true;
		this.readFlags[CLASS.S07] = true;
		this.termiFlags[CLASS.S06] = true;
		this.termiFlags[CLASS.S07] = true;
		
		this.readFlags[CLASS.K01] = true;
		
		// すべての日記が既読
		if ( readFlags[CLASS.S03] && readFlags[CLASS.S06] ) {
			this.termiFlags[CLASS.S02] = true;
		}

		// KYOJIN01が既読
		if ( flags[KyojinConst.ScenarioID.KYOJIN01]) {
			this.readFlags[CLASS.K02] = true;
			this.termiFlags[CLASS.K01] = true;
		}
		// KYOJIN02が既読
		if ( flags[KyojinConst.ScenarioID.KYOJIN02]) {
			this.readFlags[CLASS.K03] = true;
			this.termiFlags[CLASS.K02] = true;
		}
		// KYOJIN03が既読
		if ( flags[KyojinConst.ScenarioID.KYOJIN03]) {
			this.termiFlags[CLASS.K03] = true;
			this.termiFlags[CLASS.ACTOR] = true;
			this.m_gameEnd = true;
		}

		float tw = m_seqParts.get(CLASS.ACTOR).getWidth();
		float th = m_seqParts.get(CLASS.ACTOR).getHeight();
		
		// アウター表示
		this.rcActor.left = 0;
		this.rcActor.top = 0;
		this.rcActor.right = tw;
		this.rcActor.bottom = ACTOR_MAX[0];
		
		// 最大一致（去人シナリオ１がよめる）
		if ( this.readFlags[CLASS.K01] ) {
			// 全部表示
			this.rcActor.bottom = th;
		} else if ( this.readFlags[CLASS.S03] || this.readFlags[CLASS.S06] ) {
			// シナリオ２が既読
			this.rcActor.bottom = ACTOR_MAX[1];
		}
		
		// シナリオ２表示
		tw = m_seqParts.get(CLASS.S02).getWidth();
		th = m_seqParts.get(CLASS.S02).getHeight();

		this.rc2nd.left = 0;
		this.rc2nd.top = 0;
		this.rc2nd.right = tw;
		this.rc2nd.bottom = S02_MAX[0];

		if ( this.readFlags[CLASS.S03] || readFlags[CLASS.S06] ) {
			this.rc2nd.bottom = th;
		}

	}
	
	/// タイトルボタンを初期化する
	void initTitleButtons() {
		auto tl = new TextureLoader();
		tl.loadDefFile(cast(char[]) "img/sequence/title_bt.lst");
		
		auto tmp = new GUIButton();
		auto vTmp = new GUINullButtonListener();
		tmp.setMouse(this.m_mouse);
		tmp.setEvent(vTmp);
		m_titleButtons ~= tmp;
		
		foreach(int i,inout PointInt pt; TITLE_POS) {
			if (!this.readFlags[i+1]) {
				m_titleButtons ~= createNullButton();
				continue;
			}
			auto bt = new GUIButton();
			bt.setMouse(this.m_mouse);
			bt.setXY(pt.x, pt.y);
			auto v = new GUINormalButtonListener();
			v.setTextureLader(tl,i*2);
			if (i <= BT_MAIN_MAX) {
				v.setType(32);
				v.setImageOffset(0);
			} else {
				// on/off + focus
				v.setType(9);
			}
			bt.setEvent(v);
			
			m_keyGroup.add(bt);
			
			m_titleButtons ~= bt;
		}
	}

	/// nullボタンを生成する
	GUIButton createNullButton() {
		auto bt = new GUIButton();
		auto v = new GUINullButtonListener();
		bt.setMouse(this.m_mouse);
		bt.setEvent(v);
		bt.setXY(0,0);
		return bt;
	}
	
	/// 戻る
	void returnScene(GameInfo info) {
		info.gameSceneTransiter.returnScene();
		destroy();
	}
	
	/// シナリオタスクに遷移する
	void jumpScenario(GameInfo info, int sId) {
		info.selectedStory = sId;

		// すべてのスタックを破棄		
		info.gameSceneTransiter.exitScene();
		
		// 強制バックアップを行う
		info.gameSceneTransiter.setTransitType( GameSceneTransiter.C_NO_EFFECT, 1, true );
		info.gameSceneTransiter.callScene(KyojinConst.Task.Task_EyeCatche);

		// タイトル画面ＢＧＭの終了
		info.bgmloader.get(0).stopFade(1000);
		
		destroy();
	}

	/// シナリオタスクに遷移する
	void jumpScenarioViaTelop(GameInfo info, int sId) {
		info.selectedStory = sId;

		// すべてのスタックを破棄		
		info.gameSceneTransiter.exitScene();
		
		// 強制バックアップを行う
		info.gameSceneTransiter.setTransitType( GameSceneTransiter.C_NO_EFFECT, 1, true );
		info.gameSceneTransiter.callScene(KyojinConst.Task.Task_TelopKyojin);

		// タイトル画面ＢＧＭの終了
		info.bgmloader.get(0).stopFade(1000);
		
		destroy();
	}
	
	/// 対象のボタンをアクティブに、他を元に戻す
	void buttonActive(int index, bool force=false) {
		if (index < 0) {
			return;
		}
		if (m_selectedIndex != index || force) {
			// 今アクティブになっているものを元に戻す
			auto v = cast(GUINormalButtonListener) m_titleButtons[m_selectedIndex].getEvent();
			v.setType(9);
			v.setImageOffset(0);
			m_titleButtons[m_selectedIndex].setEvent(v);
			
			// 今アクティブのものをONにする
			v = cast(GUINormalButtonListener) m_titleButtons[index].getEvent();
			v.setType(32);
			v.setImageOffset(1);
			m_titleButtons[index].setEvent(v);
			m_selectedIndex = index;
			
			// keyGroupも移動 
			m_keyGroup.setSelectNo(m_titleButtons[index]);
		}
	}
	
	/// シーセンス図のパーツの描画位置
	static const PointInt[] OBJ_POS = [
		{x:0,  y:0},		// アウター
		{x:16, y:26},		// シナリオ１
		{x:16, y:67},		// シナリオ２
		{x:193,y:151},		// シナリオ３
		{x:287,y:180},		// シナリオ４
		{x:359,y:208},		// シナリオ５
		{x:202,y:114},		// シナリオ６
		{x:461,y:142},		// シナリオ７
		{x:17, y:224},		// 去人１
		{x:113,y:260},		// 去人２
		{x:205,y:295},		// 去人３
	];
	
	/// タイトル名ボタン描画位置
	static const PointInt TITLE_POS[] = [
		{x:102,y:37},	// シナリオ１
		{x:172,y:76},	// シナリオ２
		{x:265,y:166},	// シナリオ３
		{x:337,y:196},	// シナリオ４
		{x:404,y:228},	// シナリオ５
		{x:404,y:127},	// シナリオ６
		{x:508,y:157},	// シナリオ７
		{x:84, y:242},	// 去人１
		{x:178,y:272},	// 去人２
		{x:281,y:302}	// 去人３
	];
	static const int BT_MAIN_MAX = 6;

	/// ターミネーション描画位置
	static const PointInt[] TERMI = [
		{x:28, y:396},			// アウター
		{x:135,y:134},
		{x:206,y:238},
		{x:303,y:273},
		{x:371,y:294},
		{x:445,y:273},
		{x:475,y:215},
		{x:542,y:208},
		{x:115,y:342},
		{x:210,y:367},
		{x:315,y:411},
	];
	
	/// アウターシーケンスの描画量
	static const int[] ACTOR_MAX = [
		100,	// シナリオ１
		245, 	// シナリオ２
		300		// メイン終了
	];
	/// Ｓ０２シーケンスの描画量
	static const int[] S02_MAX = [
		47,	// 読める
		200, 	// 終了
	];
	
	static int[int] texStoryMap;	//!< テクスチャインデックスとストーリー番号のマップ
	static int[int] eyeTypeMap;	//!< シナリオ番号とアイキャッチタイプのマップ
	static const GUIBlinkButtonListener.TYPE BT_TYPE_BACK = 
		GUIBlinkButtonListener.TYPE.DEFAULT	| GUIBlinkButtonListener.TYPE.BLINK_FIX;
		
	/// 戻るボタン描画位置
	static const int BACK_BT_X = 539;
	static const int BACK_BT_Y = 425;
	
	/// シナリオタイトル描画位置	
	static const int TITLE_NAME_X = 0;
	static const int TITLE_NAME_Y = 416;

	/// 最終メッセージ描画位置	
	static const int LAST_MSG_X = 0;
	static const int LAST_MSG_Y = 356;
	
	bool init;
	bool showDialog;
	bool exitScene;
	MouseInput m_mouse;			//!< マウスデバイス
	bool[] readFlags;			//!< UserInfoより描画用に変換された描画フラグ配列
	bool[] termiFlags;			//!< 終端描画フラグ
	GUIButton btBack;			//!< 「戻る」ボタン
	
	int[2] m_param;
	int flameIndex;
	Rect rcActor;	//!< アウター用表示矩形
	Rect rc2nd;		//!< シナリオ２用表示矩形
	
	// パーツ刷新 ----------
	TextureLoader m_seqParts;
	TextureLoader m_titleNames;
	Texture m_imgLastMsg;
	bool m_gameEnd;
	int m_selectedIndex;
	Texture m_imgBg;	//!< 背景画像
	Texture m_imgTerm;		//!< ターミネーション画像
	GUIButton[] m_titleButtons;
	KeyGroup m_keyGroup;
}