module kyojintati4d.tasktitle;

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

private import kyojintati4d.myapp;
private import kyojintati4d.val.kyojinconst;
private import kyojintati4d.gameinfo;
private import kyojintati4d.userinfo;
private import kyojintati4d.bookmark;
private import kyojintati4d.component.titledial;

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

/**
	タイトルタスク（メニュー画面）
*/
class TaskTitle : GameTaskBase {

	private static bool USE_SOUND_CHANK_ONLY = true;
	
	/// タスク名を返却する
	/**
		このタスク名称を使って、コントローラ部でタスク判別を行う可能性があるので
		ユニークな名前で、実装しておくべきである
	*/	
	override char[] getTaskName() {
		with (kyojintati4d.val.kyojinconst) {
			return KyojinConst.TASK_NAME[KyojinConst.Task.Task_Title];
		}
	}
	
	/// 移動の処理を行います
	int onMove(Object o) {
		try {
			info = cast(GameInfo)o;
	
			if (!init) {
				init = true;
				onInit();
			}
			
			m_mouse.update();

			// 画面イン処理
			if (m_into) {
				m_dialx.inc();
				m_dialy.inc();
				if (m_dialx.isEnd() && m_dialy.isEnd()) {
					m_into = false;
				}
			} else if (m_toExit) {
				// 画面アウト処理

			} else {
				// 通常動作処理
				
				// キー操作によるフォーカシング
				if ( info.key.isPush(1) ) {
					m_keyGroup.prev();
				} else if ( info.key.isPush(2) ) {
					m_keyGroup.next();
				}

				// ボタン動作
				onMoveMenu(info.screen);
				
				if (m_destroyTask) {
					return 1;
				}

				// タイトルフェード
				m_titlePhase.inc();
			}
			
			// ダイヤル移動計算
			m_dial.onMove(info.screen);
			
			return 0;

		} catch (Exception e) {
			Log.printFatal("RuntimeException %s#onMove : [%s] [%s]", 
				super.toString(), e.toString(), e.msg);
			throw e;
		}
	}
	
	/// ボタンを動作させる
	void onMoveMenuSimple(Screen screen) {
		// ここで元の参照を取っておく。
		// このループの中で m_menuButtons を変更する可能性があるので
		GUIButton[] theButtons = m_menuButtons;
		foreach (int i,inout GUIButton bt; theButtons) {
			bt.onMove(info.screen);
			if (m_switingMenu) {
				continue;
			}
			if ( bt.isIn() ) {
				buttonActive(i);
				m_dial.turnTo(getDialID(i));
				// keyGroupの内部移動
				// これにより、Keyであれマウスであれ、今選択されいるところに
				// keyGroupインデックスがあることになる
				m_keyGroup.setSelectNo(i);
			}
			if (bt.isLClick()) {
				checkSelected(i);
				break;
			}
		}
	}
	
	/// 対象のボタンをアクティブに、他を元に戻す
	void buttonActive(int index, bool force=false) {
		if (index < 0) {
			return;
		}
		if (m_lastSelect != index || force) {
			GUIButton[] theButtons = m_menuButtons;
			
			if (0 <= m_lastSelect && m_lastSelect < theButtons.length) {
				// 今アクティブになっているものを元に戻す
				auto v = cast(GUINormalButtonListener) theButtons[m_lastSelect].getEvent();
				v.setType(9);
				v.setImageOffset(0);
				theButtons[m_lastSelect].setEvent(v);
			}
			
			// 今アクティブのものをONにする
			auto v = cast(GUINormalButtonListener) theButtons[index].getEvent();
			v.setType(32);
			v.setImageOffset(1);
			theButtons[index].setEvent(v);
			m_lastSelect = index;
			
			// keyGroupも移動
			m_keyGroup.setSelectNo(index);
		}
	}

	/// ボタンを動作させる
	void onMoveMenu(Screen screen) {
		/// 切り替え中
		if (m_switingMenu) {
			
			// スタートカウンター
			m_moveStartCount.inc();
			
			if (!m_mainMenu) {
				// main -> extra
				if (!m_afterIn) {
					// スライドアウト開始
					foreach (int i,ICounter c; m_mainOxCounter) {
						if (m_moveStartCount.get() < i) {
							break;
						}
						c.inc();
						m_menuButtons[i].setXY(MENU_POS[i].x+c.get(),MENU_POS[i].y);
					}
					// スライドアウト終了か
					bool outMain = isEndAll(m_mainOxCounter);

					// 拡張メニューをスライドインさせる
					if (outMain) {
						// メインメニューでアクティブにしていたのを戻す
						buttonActive(0);
						
						m_menuButtons = m_extraButtons;
						m_offsetCounter = m_extraOxCounter;
						setKeyGroup(m_menuButtons);
						m_afterIn = true;
						initPos(m_menuButtons,m_offsetCounter);
						// 拡張メニューを強制アクティブ
						buttonActive(0,true);

					}
				} else {
					foreach (int i,ICounter c; m_extraOxCounter) {
						if (m_moveStartCount.get() < i) {
							break;
						}
						c.inc();
						m_menuButtons[i].setXY(MENU_POS[i].x+c.get(),MENU_POS[i].y);
					}
					// スライドアウト終了か
					bool inExtra = isEndAll(m_extraOxCounter);
					if (inExtra) {
						m_afterIn = false;
						m_switingMenu = false;
						Log.print("####  EXTRA IN");
					}
				}
				
			} else {
				// extra -> main
				if (!m_afterIn) {
					// スライドアウト開始
					foreach (int i,ICounter c; m_extraOxCounter) {
						if (m_moveStartCount.get() < i) {
							break;
						}
						c.inc();
						m_menuButtons[i].setXY(MENU_POS[i].x+c.get(),MENU_POS[i].y);
					}
					// スライドアウト終了か
					bool outMain = isEndAll(m_extraOxCounter);

					// 拡張メニューをスライドインさせる
					if (outMain) {
						// メニューでアクティブにしていたのを戻す
						buttonActive(0);

						m_menuButtons = m_mainButtons;
						m_offsetCounter = m_mainOxCounter;
						setKeyGroup(m_menuButtons);
						m_afterIn = true;

						// メインメニューを強制アクティブ
						buttonActive(0,true);
					}
				} else {
					foreach (int i,ICounter c; m_mainOxCounter) {
						if (m_moveStartCount.get() < i) {
							break;
						}
						c.inc();
						m_menuButtons[i].setXY(MENU_POS[i].x+c.get(),MENU_POS[i].y);
					}
					// スライドアウト終了か
					bool inExtra = isEndAll(m_mainOxCounter);
					if (inExtra) {
						m_afterIn = false;
						m_switingMenu = false;
						Log.print("####  EXTRA IN");
					}
				}
			}
		}
		// 切り替え中は入力を受け付けない
		if (!m_switingMenu) {
			onMoveMenuSimple(screen);
		}
	}
	
	/// ボタンの位置を初期化する
	static void initPos(GUIButton[] buttons, ICounter[] counters) {
		foreach (int i,ICounter c; counters) {
			buttons[i].setXY(MENU_POS[i].x+c.get(),MENU_POS[i].y);
		}
	}
	
	/// 全て終端に達したか
	static bool isEndAll(ICounter[] counters) {
		foreach (ICounter c; counters) {
			if (!c.isEnd()) {
				return false;
			}
		}
		return true; 
	}

	/// 描画の処理を行います
	int onDraw(Object o) {
		try {
			info = cast(GameInfo)o;
	
			Color4ub colorOrg = info.screen.getColor4ub();
			info.screen.setColor(255,255,255,255);

			// 画面消去
			info.screen.setClearColor(255,255,255);
			info.screen.clear();
			info.screen.blendSrcAlpha();
			info.screen.setClearColor(0,0,0);

			// 背景描画
			info.screen.blt(m_imgBg,cast(int) BG_RECT.left,cast(int) BG_RECT.top, &BG_RECT);
			// フレーム描画
//			info.screen.blt(m_imgFrame, 0,0);

			// ダイヤルの描画
			m_dial.setXY(m_dialx.get(), m_dialy.get());
			m_dial.onDraw(info.screen);

			// タイトル描画	
			TransBltter.blt(21,info.screen, m_imgTitle, TITLE_POS_X,TITLE_POS_Y,m_titlePhase.get() );

			// copyright描画
			info.screen.blt(m_imgCopyright, COPY_POS_X, COPY_POS_Y);
			
			// ボタン描画
			foreach (int i,inout GUIButton bt; m_menuButtons) {
				bt.onDraw(info.screen);
			}

			// 説明文の表示
			info.screen.blt(m_tlCaption.get(getCaptionNo()), CAPTION_POS_X, CAPTION_POS_Y);
			
			// カラーオリジナル戻し
			info.screen.setColor(colorOrg);
	
			return 0;
		} catch (Exception e) {
			Log.printFatal("RuntimeException %s#onDraw : [%s] [%s]", 
				super.toString(), e.toString(), e.msg);
			throw e;
		}
	}

	/// 表示すべき説明画像のインデックス番号を取得する	
	int getCaptionNo() {
		if (m_switingMenu) {
			return m_mainMenu ? MAIN_BUTTON_ID.max + EXTRA_BUTTON_ID.max + 1 : MAIN_BUTTON_ID.max;
		} else {
			return m_mainMenu ? m_lastSelect : MAIN_BUTTON_ID.max + 1 + m_lastSelect;
		}
	}

	/// レガシーなタスク
	override int task(Object o) {
		return 0;
	}

	/// 使用メモリの解放
	override void destroy() {
		m_menuButtons = null;
		m_mainButtons = null;
		m_extraButtons = null;
		m_keyGroup = null;
		m_offsetCounter = null;
		m_mainOxCounter = null;
		m_extraOxCounter = null;
		m_moveStartCount = null;
		m_titlePhase = null;
		Texture.safeRelease(m_imgBg);
		Texture.safeRelease(m_imgFrame);
		Texture.safeRelease(m_imgTitle);
		Texture.safeRelease(m_imgCopyright);
		m_tlCaption = null;
		m_dial = null;
		m_dialx = null;
		m_dialy = null;
		m_bgAlpha = null;
		
//		foreach (inout Sound snd; wheelL) {
//			if ( !(snd is null) ) {
//				snd.release();
//			}
//			snd = null;
//		}
//		foreach (inout Sound snd; wheelR) {
//			if ( !(snd is null) ) {
//				snd.release();
//			}
//			snd = null;
//		}
		
		if ( !(m_tlCaption is null) ) {
			m_tlCaption.releaseAll();
			m_tlCaption.releaseFileList();
			m_tlCaption = null;
		}

		Log.print("%s#destroy : destroyed.", super.toString());
	}

	/// コンストラクタ
	this() {
		// KeyGroup
		m_keyGroup = new KeyGroup();

		//wheel音
//		for(int i; i<wheelL.length; ++i) {
//			wheelL[i] = new Sound();
//			wheelR[i] = new Sound();
//		}
		
		m_moveStartCount = new InteriorCounter();
		m_titlePhase = new RootCounterS();
		m_titlePhase.set(0,255,2);
		
		m_dialx = new FreeLineCounter(new RootCounterS());
		m_dialy = new FreeLineCounter(new RootCounterS());
		
		// 背景用のアルファ
		m_bgAlpha = new RootCounterS();

		m_into = true;
	}
	
private:

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

		m_mainMenu = true;
		// この画面で一貫して使用するマウス
		m_mouse = info.keyDecolateMouse;
	
/+
		Sound testS = new Sound();
		testS.load("snd\\bgm\\00.ogg", -1);
		testS.stop;
Log.print("STOP ALL");
			Sound.stopAll;
+/
		
		// BGMを再生していなければ再生を始める
		if (!info.bgmloader.get(0).isPlay()) {
			info.bgmloader.get(0).setLoop(-1);
			if (USE_SOUND_CHANK_ONLY) {
				info.bgmloader.get(0).play();
				Log.printSoundLog("======= PALY BGM with CHANK. =======");
			} else {
				info.bgmloader.playBGM(0);
			}
			
		}
		info.bgmloader.get(0).setVolume(info.optionInfo.getBgmVol());

		// 背景画像読み込み
		m_imgBg = new Texture();
		m_imgBg.load("img/title/bg_a.png");
		
		// 画面フレーム読み込み
		m_imgFrame = new Texture();
		m_imgFrame.load("img/title/t_cov.png");
		
		// タイトル画像の読み込み
		m_imgTitle = new Texture();
		m_imgTitle.load("img/title/t_logo.png");
		
		// Copyright 画像の読み込み
		m_imgCopyright = new Texture();
		m_imgCopyright.load("img/title/t_copy.png");
		
		// ボタン初期化
		initMenuButton();
		// 描画対象ボタンにメインを設定
		m_menuButtons = m_mainButtons;
		m_offsetCounter = m_mainOxCounter;
		
		// Key group 設定
		setKeyGroup(m_menuButtons);

		// デフォルト選択を行う
		if ( isSaveExist() ) {
			buttonActive(MAIN_BUTTON_ID.CONTINUE,true);
		} else {
			buttonActive(MAIN_BUTTON_ID.START,true);
		}
		
		
		// 説明画像の読み込み
		m_tlCaption = new TextureLoader();
		m_tlCaption.loadDefFile("img/title/caption.lst");
		
		// ダイアルをセット
		setDial();

		info.screen.setClearColor(255,255,255);

		// 既読フラグをみて、タイトルに表示するボタンを決める
		bool[] mpIndexStory = new bool[13];
		UserInfo ui = info.userInfo();
		int n = 0;
		mpIndexStory[n++] = true;
		mpIndexStory[n++] = ui.isRead( KyojinConst.ScenarioID.STORY01 );
		mpIndexStory[n++] = ui.isRead( KyojinConst.ScenarioID.STORY02_1 );
		mpIndexStory[n++] = ui.isRead( KyojinConst.ScenarioID.STORY03 );
		mpIndexStory[n++] = ui.isRead( KyojinConst.ScenarioID.STORY04 );
		mpIndexStory[n++] = ui.isRead( KyojinConst.ScenarioID.STORY02_2 );
		mpIndexStory[n++] = ui.isRead( KyojinConst.ScenarioID.STORY06 );
		mpIndexStory[n++] = false;		// ある秋までの歴史１
		mpIndexStory[n++] = false;
		mpIndexStory[n++] = false;
		mpIndexStory[n++] = ui.isReadMain();
		mpIndexStory[n++] = ui.isRead( KyojinConst.ScenarioID.KYOJIN01 );
		mpIndexStory[n++] = ui.isRead( KyojinConst.ScenarioID.KYOJIN02 );

		//wheelL[0].load(FileSys.makeFullName("snd/title/wheel_L.ogg"),0);
		//wheelL[1].load(FileSys.makeFullName("snd/title/wheel_L.ogg"),0);
		//wheelR[0].load(FileSys.makeFullName("snd/title/wheel_R.ogg"),0);
		//wheelR[1].load(FileSys.makeFullName("snd/title/wheel_R.ogg"),0);
		
		/// これは、ダイアルの位置を画面外にセットされる
		reset();		
	}
	
	/// セーブデータが存在しているか？
	bool isSaveExist() {
		foreach (inout Bookmark bm; info.bookmark) {
			if ( bm.isAuto() ) {
				return bm.isUse(); 
			} 
		}
		return false;
	}
	
	/// メニューボタンを初期化します
	void initMenuButton() {
		auto tl = new TextureLoader();
		tl.loadDefFile("img/title/menu_bt_main.lst");
		
		bool readAll = isScenarioRead(KyojinConst.ScenarioID.STORY05) 
						&& isScenarioRead(KyojinConst.ScenarioID.STORY07);
		
		for (int i = 0; i <= MAIN_BUTTON_ID.max; ++i) {
			
			// TODO 評価版用
			if (MAIN_BUTTON_ID.EXTRA == i && !readAll) {
				break;
			}
			
			auto bt = new GUIButton();
			bt.setMouse(this.m_mouse);
			bt.setXY(MENU_POS[i].x, MENU_POS[i].y);
			auto v = new GUINormalButtonListener();
			v.setTextureLader(tl,i*2);
			// on/off + focus
			v.setType(9);
			bt.setEvent(v);
			
			m_mainButtons ~= bt;
			auto counter = new FreeLineCounter(new RootCounterS());
			counter.set(0,MENU_OFFSET_X,MENU_SWITCH_STEP);
			m_mainOxCounter ~= counter;
		}
		
		if (readAll) {
			tl = new TextureLoader();
			tl.loadDefFile("img/title/menu_bt_extra.lst");
			int pos_index = 0;
			for (int i = 0; i <= EXTRA_BUTTON_ID.max; ++i) {
				
				auto bt = new GUIButton();
				bt.setMouse(this.m_mouse);
				bt.setXY(MENU_POS[i].x, MENU_POS[i].y);

				GUIButtonEventListerner v = new GUINormalButtonListener();

				if ( EXTRA_BUTTON_ID.MUSIC == i || EXTRA_BUTTON_ID.RETURN == i || true) { 
					GUINormalButtonListener btListener = cast(GUINormalButtonListener) v;
					// on/off + focus
					btListener.setType(9);
					btListener.setTextureLader(tl,i*2);
					bt.setXY(MENU_POS[pos_index].x, MENU_POS[pos_index].y);
					pos_index++;
				} else {
					v = new GUINullButtonListener();
				}

				bt.setEvent(v);
				
				m_extraButtons ~= bt;
				auto counter = new FreeLineCounter(new RootCounterS());
				counter.set(0,MENU_OFFSET_X,MENU_SWITCH_STEP);
				m_extraOxCounter ~= counter;
			}
		}
		
	}
	
	/// シナリオを読んだかどうかを返却する
	bool isScenarioRead(KyojinConst.ScenarioID scenarioID) {
		return info.userInfo.isRead(scenarioID);
	}
	
	/// 今のKEY GROUPを解除し、指定したボタンを登録する
	void setKeyGroup(GUIButton[] buttons) {
		m_keyGroup.clear();
		foreach (inout GUIButton bt; buttons) {
			m_keyGroup.add(bt);
		}
	}

	/// 状態のリセット
	void reset() {
		m_toExit = false;
		m_into = true;
		m_dialx.set(DIAL_POS_X + DIAL_OUT_POS_OFFSET, DIAL_POS_X, 4);
		m_dialy.set(DIAL_POS_Y + DIAL_OUT_POS_OFFSET, DIAL_POS_Y, 4);
		m_titlePhase.reset();
	}
	
	/// 右回りさせるか
	static bool isRightTurn(MouseInput mouse, KeyInputBase key) {
		return mouse.isRButtonUp() || key.isPush(4);
	}
	
	/// 左回りさせるか
	static bool isLeftTurn(MouseInput mouse, KeyInputBase key) {
		return mouse.isLButtonUp() || key.isPush(3);
	}

	/// 選択時のチェック
	int checkSelected(int buttonID) {
		int ret = 0;
		if (m_mainMenu) {
			// メインメニュー
			switch (buttonID) {
			case MAIN_BUTTON_ID.START:
				info.gameSceneTransiter.callScene(KyojinConst.Task.Task_Selector);
				info.fromTitle = true;
				// しおりの動作モード設定
				Bookmark.setTitle(false);
				info.playSystemSE(SYS_SE.CLICK_TITLE_ACTIVE);
				break;
			case MAIN_BUTTON_ID.CONTINUE:
				if ( isSaveExist() ) {
					info.gameSceneTransiter.callScene(KyojinConst.Task.Task_Bookmark);
					info.bookmark[KyojinConst.BookmarkID.AUTO].setTitle(true);
					// しおりの動作モード設定
					Bookmark.setTitle(true);
					info.playSystemSE(SYS_SE.CLICK_TITLE_ACTIVE);
				} else {
					info.playSystemSE(SYS_SE.CLICK_TITLE_NEGATIVE);
				}
				ret = 0;
				break;
			case MAIN_BUTTON_ID.OPTION:
				// スタックにつんでオプション画面へ
				info.gameSceneTransiter.callScene(KyojinConst.Task.Task_Option);
				info.fromTitle = true;
				ret = 0;
				info.playSystemSE(SYS_SE.CLICK_TITLE_ACTIVE);
				break;
			case MAIN_BUTTON_ID.EXIT:
				// ゲーム終了
				info.gameTaskController.terminate();
//				ret = 1;
				// FIXME タスクコントローラにエンバグしたらしく、０を返さないと正常終了しない
				ret = 0;
				break;
			case MAIN_BUTTON_ID.EXTRA:
				m_mainMenu = false;
				m_switingMenu = true;
				setUpMainSlideOut();
				info.playSystemSE(SYS_SE.CLICK_TITLE_ACTIVE);
				break;
			default:
				assert(false);
			}
		} else {
			// 拡張メニュー
			switch (buttonID) {
				case EXTRA_BUTTON_ID.MUSIC:
				info.gameSceneTransiter.callScene(KyojinConst.Task.Task_Music);
				ret = 0;
				// タイトル画面ＢＧＭの終了
				info.bgmloader.stopFade(0,1000);
				info.playSystemSE(SYS_SE.CLICK_TITLE_ACTIVE);
				break;
			case EXTRA_BUTTON_ID.DEV_ROOM:
				// スタックにつんで
				info.gameSceneTransiter.callScene(KyojinConst.Task.Task_Dev);
				ret = 0;
				info.bgmloader.stopFade(0,1000);
				info.playSystemSE(SYS_SE.CLICK_TITLE_ACTIVE);
				break;
			case EXTRA_BUTTON_ID.DEMO:
				info.gameSceneTransiter.jumpScene(KyojinConst.Task.Task_Demo);
				ret = 1;
				info.playSystemSE(SYS_SE.CLICK_TITLE_ACTIVE);
				break;
			case EXTRA_BUTTON_ID.KYOJIN2:
				// 予告編
				int[] param = new int[2];
				param[0] = KyojinConst.Task.Task_Scenario;	// 呼び出してほしいタスクね
				param[1] = KyojinConst.ScenarioID.KYOJIN02;	// 呼び出してほしいシナリオ番号ね
				info.setData(param);
				// シナリオ画面に遷移する
				jumpScenario(info, KyojinConst.ScenarioID.KYOJIN02);
				ret = 1;
				break;
			case EXTRA_BUTTON_ID.RETURN:
				m_mainMenu = true;
				m_switingMenu = true;
				setUpExtraSlideOut();
				info.playSystemSE(SYS_SE.CLICK_TITLE_ACTIVE);
				break;
			default:
				assert(false);
			}
		}
		if (ret) {
			// タイトル画面ＢＧＭの終了
			info.bgmloader.stopFade(0,1000);
		}
		// メモリの明示的解放
		if (ret != 0) {
			m_destroyTask = true;
			destroy();
		}
		
		return ret;
	}
	
	/// シナリオ画面にジャンプする
	/// シナリオタスクに遷移する
	void jumpScenario(GameInfo info, int sId) {
		info.selectedStory = sId;
		// すべてのスタックを破棄		
		info.gameSceneTransiter.exitScene();
		// 強制バックアップを行う
		info.gameSceneTransiter.setTransitType( GameSceneTransiter.C_NO_EFFECT, 1, true );
		info.gameSceneTransiter.jumpScene(KyojinConst.Task.Task_EyeCatche);

	}

	/// ダイヤルの設定を行う
	void setDial() {
		m_dial = new TitleDial();
		auto t = new Texture();
		t.load("img/title/dial_item/null.png");

		m_dial.addItemName(t, LC_DID_START);
		m_dial.addItemName(t, LC_DID_CONTINUE);
		m_dial.addItemName(t, LC_DID_OPTION);
		m_dial.addItemName(t, LC_DID_EXIT);

//info.userInfo.setReadFlag(KyojinConst.ScenarioID.STORY01,true);
//info.userInfo.setReadFlag(KyojinConst.ScenarioID.STORY02_1,true);
//info.userInfo.setReadFlag(KyojinConst.ScenarioID.STORY02_2,true);
		// demo
		if ( info.userInfo.isRead(KyojinConst.ScenarioID.STORY02_1) 
				&& info.userInfo.isRead(KyojinConst.ScenarioID.STORY02_2) ) 
		{
			m_dial.addItemName(t, LC_DID_DEMO);
			m_dial.addItemName(t, LC_DID_MUSIC);
		}

		// その他
		// TODO 評価版用
		if ( info.userInfo.isReadMain() ) {
			m_dial.addItemName(t, LC_DID_DEV);
			m_dial.addItemName(t, LC_DID_SCENARIO_2CH);
		}

		Texture t3 = new Texture();
		t3.load( "img/title/t_op.png" );

		m_dial.setDialTexture(t3);
		m_dial.setXY(DIAL_POS_X, DIAL_POS_Y);
	}

	/// 表示メニューにより、ダイアルのIDを取得する	
	int getDialID(int line) {
		if ( !m_mainMenu ) {
			// 拡張メニュー
			return MAIN_BUTTON_ID.max-1 + line;
		}
		return line;
	}
	
	/// メインメニューをスライドアウトさせる準備
	void setUpMainSlideOut() {
		m_moveStartCount.set(0,MAIN_BUTTON_ID.max, MENU_OUT_INTERVAL);
		foreach (inout ICounter c; m_mainOxCounter) {
			c.set(0, MENU_OFFSET_X, MENU_SWITCH_STEP);
		}
		foreach (inout ICounter c; m_extraOxCounter) {
			c.set(MENU_OFFSET_X, 0, MENU_SWITCH_STEP);
		}
	}

	/// 拡張メニューをスライドアウトさせる準備
	void setUpExtraSlideOut() {
		m_moveStartCount.set(0,MAIN_BUTTON_ID.max, MENU_OUT_INTERVAL);
		foreach (inout ICounter c; m_extraOxCounter) {
			c.set(0, MENU_OFFSET_X, MENU_SWITCH_STEP);
		}
		foreach (inout ICounter c; m_mainOxCounter) {
			c.set(MENU_OFFSET_X, 0, MENU_SWITCH_STEP);
		}
	}

private:

	/** ダイヤルユニークキーＩＤ */
	static final const char[] LC_DID_START = "START";
	static final const char[] LC_DID_CONTINUE = "CONTINUE";
	static final const char[] LC_DID_OPTION = "OPTION";
	static final const char[] LC_DID_EXIT = "EXIT";
	static final const char[] LC_DID_MUSIC = "MUSIC";
	static final const char[] LC_DID_DEV = "DEV";
	static final const char[] LC_DID_SCENARIO_2CH = "SCENARIO_2CH";
	static final const char[] LC_DID_DEMO = "DEMO";
	
	static final int[char[]] LC_MAP_REMARK_ID;
	
	/// タイトル中の遷移フラグ
	enum eState{ NON,SIORI_IN,SIORI_OUT };

	// タイトルダイアルの角度定義
	static final const int[] titleRad = [0,72,146,219,293,366,438];
	static final const int rotaSpeed = 3;
	static final const int dxStep = 24;
	static final const int RX_POS = 20;
	
	/// メニュー切り替え固有値
	static final const int MENU_OFFSET_X = 200;
	static final const int MENU_SWITCH_STEP = 8;
	static final const int MENU_OUT_INTERVAL = 20;

	/// メインボタンID
	enum MAIN_BUTTON_ID : int { START=0, CONTINUE, OPTION, EXIT, EXTRA  };
	/// 拡張ボタンID
	enum EXTRA_BUTTON_ID : int { MUSIC=0, DEV_ROOM, DEMO, KYOJIN2,RETURN  };
	
	/// 各段のメニュー描画位置
	static final const PointInt[] MENU_POS = [
			{x:420,y:49},
			{x:420,y:89},
			{x:420,y:129},
			{x:420,y:169},
			{x:420,y:209}
		];
	/// タイトル文字画像の描画位置
	static final const int TITLE_POS_X = 0;
	static final const int TITLE_POS_Y = 32;
	/// 背景の描画矩形
	static final const Rect BG_RECT = {top:32, left:0, bottom:400, right:640};
	/// 説明文を表示する位置
	static final const int CAPTION_POS_X = 130;
	static final const int CAPTION_POS_Y = 400;
	/// copyright の描画位置
	static final const int COPY_POS_X = 451;
	static final const int COPY_POS_Y = 372;
	/// ダイアルの描画中心位置
	static final const int DIAL_POS_X = 646;
	static final const int DIAL_POS_Y = 131;
	static final const int DIAL_OUT_POS_OFFSET = 500;   

	GameInfo info;
	MouseInput m_mouse;
	bool init;

	bool m_destroyTask;	//!< タスク終了フラグ
	bool m_mainMenu;	//!< 今表示しているのはメインメニューか
	bool m_switingMenu;	//!< メニュー切り替え中か？
	bool m_afterIn;		//!< スライドイン中
	int m_lastSelect;	//!< 最後に選択されたメニューを保持しておき、それをアクティブにする
	GUIButton[] m_menuButtons;
	GUIButton[] m_mainButtons;
	GUIButton[] m_extraButtons;
	KeyGroup m_keyGroup;
	ICounter[] m_offsetCounter;
	ICounter[] m_mainOxCounter;
	ICounter[] m_extraOxCounter;
	ICounter m_moveStartCount;
	ICounter m_titlePhase;
	Texture m_imgBg;
	Texture m_imgFrame;
	Texture m_imgTitle;
	Texture m_imgCopyright;
	TextureLoader m_tlCaption;

	// Sound[2] wheelL;	//!< これは２重に再生してほしい可能性がある
	// Sound[2] wheelR;	//!< これは２重に再生してほしい可能性がある
	
	TitleDial m_dial;
	ICounter m_dialx;	//!< ダイアル移動用
	ICounter m_dialy;
	ICounter m_bgAlpha;
	
	bool m_into;
	bool m_toExit;
}
