module kyojintati4d.taskoption;

private import SDL;

private import y4d;
private import y4d_aux.filesys;
private import y4d_aux.lineparser;

private import kyojintati4d.myapp;
private import kyojintati4d.gameinfo;
private import kyojintati4d.taskyesno;
private import kyojintati4d.component.option.keyconfigdialon;

private import yamalib.serialize;
private import yamalib.counterfsp;

private import yamalib.input.adapter;
private import yamalib.input.adaptedkey;
private import yamalib.input.multimouse;

private import yamalib.gui.guibutton;
private import yamalib.gui.keygroup;
private import yamalib.gui.guislidebar;

private import yamalib.log.log;

enum ButtonRange{ VOL=10,TEXT_SPEED=4 };

/// オプションデータの情報クラス
class OptionInfo : Archive {
	static final const int SEVE_DATA_VERSION_LATEST = 100;
	static final const int SEVE_DATA_VERSION_100 = 100;
	
	
	enum TextSpeed { NORMAL=-2,FAST=1, LINE, PAGE };

	bool bgmOn=true;		// BGM:ON/OFF
	bool seOn=true;			// SE:ON/OFF
	bool voiceOn=false;		// VOICE:ON/OFF
	bool windowMode=false;	// window mode

	/// シリアライズ
	override void serialize(inout Serialize s) {
		s << dataVersion;
		if (SEVE_DATA_VERSION_LATEST == dataVersion ) {
			s << bgmVol << seVol << voiceVol << textSpeed
				<< bgmOn << seOn << voiceOn << windowMode;
		} else if (SEVE_DATA_VERSION_LATEST > dataVersion ) {
			// 下位互換
			// ここで、それぞれの下位バージョンを判定し、追加されたデータにデフォルト値を設定
			Log.printError("Can't load this save data version : %s", dataVersion);
		} else if (SEVE_DATA_VERSION_LATEST < dataVersion ) {
			// 上位互換
			// たぶん、これは、おもわぬ動作を引き起こすので、バージョンアップを促す
			Log.printError("Can't load this save data version : %s", dataVersion);
		}

/*		// 復元作業
		if (!s.isStoring()) {
			setBgmVolPos(bgmVolPos);
			setSeVolPos(seVolPos);
			setVoiceVolPos(voiceVolPos);
		}
*/
	};
	
	/// ボリューム設定
	void setVolumeBGM(int vol) {
		bgmVol = roundVol(vol);
//printf("bgm vol : %d\n", bgmVol);
	}
	/// ボリューム設定
	void setVolumeVoice(int vol) {
		voiceVol = roundVol(vol);
//printf("voice vol : %d\n", voiceVol);
	}
	/// ボリューム設定
	void setVolumeSE(int vol) {
		seVol = roundVol(vol);
//printf("se vol : %d\n", seVol);
	}
	int getBgmVol() { return bgmVol; }
	int getSeVol() { return seVol; }
	int getVoiceVol() { return voiceVol; }

/*
	/// 離散ボリューム設定
	void setBgmVolPos(int n) {
		if (n<0) n = 0;
		else if (n>=ButtonRange.VOL) n = ButtonRange.VOL-1;
		bgmVol = (100/ButtonRange.VOL)*(n+1);
		bgmVolPos = n;
	}
	/// 離散ボリューム設定
	void setSeVolPos(int n) {
		if (n<0) n = 0;
		else if (n>=ButtonRange.VOL) n = ButtonRange.VOL-1;
		seVol = (100/ButtonRange.VOL)*(n+1);
		seVolPos = n;
	}
	/// 離散ボリューム設定
	void setVoiceVolPos(int n) {
		if (n<0) n = 0;
		else if (n>=ButtonRange.VOL) n = ButtonRange.VOL-1;
		voiceVol = (100/ButtonRange.VOL)*(n+1);
		voiceVolPos = n;
	}
	int getBgmVolPos() { return bgmVolPos; }
	int getSeVolPos() { return seVolPos; }
	int getVoiceVolPos() { return voiceVolPos; }
*/
	/// 文章速度の設定／取得
	void setTextSpeed(int n) {
		textSpeed = n;
	}
	int getTextSpeed() {
		return textSpeed;
	}

	/// コンストラクタ
	this () {
		windowMode = false;
		setTextSpeed(TextSpeed.NORMAL);
		setVolumeBGM(80);
		setVolumeSE(100);
		setVolumeVoice(100);
		dataVersion = SEVE_DATA_VERSION_LATEST;
	}

private :
	static int roundVol(int vol) {
		if (100<vol) vol = 100;
		else if (vol<0) vol = 0;
		return vol;
	}
	int dataVersion;
	int textSpeed;		// 文字表示速度
	int bgmVol;			// マスターボリューム
	int voiceVol;		// マスターボリューム
	int seVol;			// マスターボリューム

}

/// オプション画面タスク
class TaskOption : GameTaskBase {

	/// タスク名を返却する
	/**
		このタスク名称を使って、コントローラ部でタスク判別を行う可能性があるので
		ユニークな名前で、実装しておくべきである
	*/	
	override char[] getTaskName() {
		with (kyojintati4d.val.kyojinconst) {
			return KyojinConst.TASK_NAME[KyojinConst.Task.Task_Option];
		}
	}


	/// 移動の処理を行います
	override int onMove(Object o) {
		try {
			info = cast(GameInfo)o;
	
			// 初期化
			if (!init) {
				init = true;
				onInit();
			}
			
			info.screen.blendSrcAlpha();
			alpha++;
			m_tox++;
			
			// KyeConfigダイアログ
			onMoveKeyConfDlg(info.screen);

			bool*[] volOn;
			volOn ~= &optionInfo.bgmOn;
			volOn ~= &optionInfo.voiceOn;
			volOn ~= &optionInfo.seOn;

			// スライダー移動
			foreach (int count, inout Slidebar sb; m_volBar) {
				sb.onMove(info.screen);
				if ( sb.isModifiy() ) {
					int vol = cast(int) (100 * sb.getSlidePos());
					m_setVol[count]( vol );
					
					if (false == (*volOn[count])) {
						onClickVolumeOff(btType[count], *volOn[count], count);
					}
				}
				
				if ( sb.isIn() ) {
					m_keyGroup.setSelectNo(sb);
				}
			}
			
			m_mouse.update();
			// キー操作によるフォーカシング
			if ( info.key.isPush(1) ) {
				m_keyGroup.prev();
			} else if ( info.key.isPush(2) ) {
				m_keyGroup.next();
			} else {
				// フォーカス移動
				foreach (GUIButton parts; button) {
					if ( parts.isIn() ) {
						m_keyGroup.setSelectNo(parts);
						break;
					}
				}
			}
			
	
			// ボタンの移動
			foreach (inout GUIButton bt; button) {
				bt.onMove(info.screen);
			}
	
			// エフェクト中ならここでかえる
			if (!alpha.isEnd()) {
				return 0;
			}
	
			// ボタンクリックチェック
			GUIBlinkButtonListener v;
			GUIBlinkButtonListener.TYPE typeBlink = GUIBlinkButtonListener.TYPE.DEFAULT 
								| GUIBlinkButtonListener.TYPE.IN_ACTIVE;
			GUIBlinkButtonListener.TYPE typeFix = GUIBlinkButtonListener.TYPE.OFFSET_FIX; 

			for (int i = 0; i < button.length; ++i) {
				if ( info.isShowYesNo() ) {
					break;				
				}
				// クリックされた？
				if (button[i].isLClick()) {
					switch (i) {
					case eButtonID.WINDOW :
						// ウィンドゥモード切替
						{
							if (!optionInfo.windowMode) {
								v = cast(GUIBlinkButtonListener)button[i].getEvent();
								v.setType(typeFix);
								v.setImageOffset(1);
								v = cast(GUIBlinkButtonListener)button[eButtonID.FULL].getEvent();
								v.setType(typeBlink);

								info.screen.setClearColor(0,0,0);
								info.screen.clear();
								info.screen.update();
								
								Texture.releaseAll();
	
								// 画面の変更
								info.screen.beginScreenTest();			// 今からスクリーンテストをはじめる
								info.screen.testVideoMode(640,480,0);	// ウィンドゥモード 640×480をテスト
								info.screen.endScreenTest();			// テスト終了
	
								// リソースの再読込
								reloadResources();
	
								optionInfo.windowMode = true;
							}
						}
						break;
					case eButtonID.FULL :
						// ウィンドゥモード切替
						{
							
							if (optionInfo.windowMode) {
								v = cast(GUIBlinkButtonListener)button[i].getEvent();
								v.setType(typeFix);
								v.setImageOffset(1);
								v = cast(GUIBlinkButtonListener)button[eButtonID.WINDOW].getEvent();
								v.setType(typeBlink);

								info.screen.setClearColor(0,0,0);
								info.screen.clear();
								info.screen.update();
								info.screen.disableBlend();
								
								Texture.releaseAll();
								
								// 画面の変更
								info.screen.beginScreenTest();			// 今からスクリーンテストをはじめる
								
								auto testBit = GameInfo.getFullScreenTestBitColor();
								foreach (bitColor; testBit) {
									Log.print("TEST COLOR : %s", bitColor);
									info.screen.testVideoMode(640,480,bitColor);	// フルスクリーン 640×480×bitをテスト
								}
								info.screen.endScreenTest();			// テスト終了
	
								reloadResources();
	
								optionInfo.windowMode = false;
							}
						}
						break;
					case eButtonID.T_NORMAL:
						{
							int pos = optionInfo.getTextSpeed();
							if (pos!=OptionInfo.TextSpeed.NORMAL) {
								v = cast(GUIBlinkButtonListener)button[i].getEvent();
								v.setType(typeFix);
								v.setImageOffset(1);
	
								int index;
								switch(pos) {
								case OptionInfo.TextSpeed.NORMAL:
									index = eButtonID.T_NORMAL;
									break;
								case OptionInfo.TextSpeed.FAST:
									index = eButtonID.T_NORMAL+1;
									break;
								case OptionInfo.TextSpeed.LINE:
									index = eButtonID.T_NORMAL+2;
									break;
								case OptionInfo.TextSpeed.PAGE:
									index = eButtonID.T_NORMAL+3;
									break;
								default:
									Log.printError("UNDEF TEXT SPEED : %d",pos);
									break;
								}
								v = cast(GUIBlinkButtonListener)button[index].getEvent();
								v.setType(typeBlink);
							}
							optionInfo.setTextSpeed(OptionInfo.TextSpeed.NORMAL);
						}
						break;
					case eButtonID.T_FAST :
						{
							int pos = optionInfo.getTextSpeed();
							if (pos!=OptionInfo.TextSpeed.FAST) {
								v = cast(GUIBlinkButtonListener)button[i].getEvent();
								v.setType(typeFix);
								v.setImageOffset(1);

								int index;
								switch(pos) {
								case OptionInfo.TextSpeed.NORMAL:
									index = eButtonID.T_NORMAL;
									break;
								case OptionInfo.TextSpeed.FAST:
									index = eButtonID.T_NORMAL+1;
									break;
								case OptionInfo.TextSpeed.LINE:
									index = eButtonID.T_NORMAL+2;
									break;
								case OptionInfo.TextSpeed.PAGE:
									index = eButtonID.T_NORMAL+3;
									break;
								default:
									assert(false);
								}
								v = cast(GUIBlinkButtonListener)button[index].getEvent();
								v.setType(typeBlink);
							}
							optionInfo.setTextSpeed(OptionInfo.TextSpeed.FAST);
						}
						break;
					case eButtonID.T_LINE:
						{
							int pos = optionInfo.getTextSpeed();
							if (pos!=OptionInfo.TextSpeed.LINE) {
								v = cast(GUIBlinkButtonListener)button[i].getEvent();
								v.setType(typeFix);
								v.setImageOffset(1);

								int index;
								switch(pos) {
								case OptionInfo.TextSpeed.NORMAL:
									index = eButtonID.T_NORMAL;
									break;
								case OptionInfo.TextSpeed.FAST:
									index = eButtonID.T_NORMAL+1;
									break;
								case OptionInfo.TextSpeed.LINE:
									index = eButtonID.T_NORMAL+2;
									break;
								case OptionInfo.TextSpeed.PAGE:
									index = eButtonID.T_NORMAL+3;
									break;
								default:
									assert(false);
								}
								v = cast(GUIBlinkButtonListener)button[index].getEvent();
								v.setType(typeBlink);
							}
							optionInfo.setTextSpeed(OptionInfo.TextSpeed.LINE);
						}
						break;
					case eButtonID.T_PAGE :
						{
							int pos = optionInfo.getTextSpeed();
							if (pos!=OptionInfo.TextSpeed.PAGE) {
								v = cast(GUIBlinkButtonListener)button[i].getEvent();
								v.setType(typeFix);
								v.setImageOffset(1);

								int index;
								switch(pos) {
								case OptionInfo.TextSpeed.NORMAL:
									index = eButtonID.T_NORMAL;
									break;
								case OptionInfo.TextSpeed.FAST:
									index = eButtonID.T_NORMAL+1;
									break;
								case OptionInfo.TextSpeed.LINE:
									index = eButtonID.T_NORMAL+2;
									break;
								case OptionInfo.TextSpeed.PAGE:
									index = eButtonID.T_NORMAL+3;
									break;
								default:
									assert(false);
								}
								v = cast(GUIBlinkButtonListener)button[index].getEvent();
								v.setType(typeBlink);
							}
							optionInfo.setTextSpeed(OptionInfo.TextSpeed.PAGE);
						}
						break;
					case eButtonID.BGM_OFF:
						{
							onClickVolumeOff(i, optionInfo.bgmOn, eSliderID.BGM);
						}
						break;
					case eButtonID.VOICE_OFF:
						{
							onClickVolumeOff(i, optionInfo.voiceOn, eSliderID.VOICE);
						}
						break;
					case eButtonID.SE_OFF:
						{
							onClickVolumeOff(i, optionInfo.seOn, eSliderID.SE);
						}
						break;
					case eButtonID.KEY_CONFIG:
						{
							if (info.isEnableJoystick()) {
								createKeyConfigDialog();
							}
						}
						break;
					case eButtonID.BACK:
						{
							info.gameSceneTransiter.returnScene();
							// セーブデータを保存しておく
							info.saveAppData();
	Log.print("---------TEXTSPPED:%s ------------", optionInfo.getTextSpeed());
							destroy();
							info.playSystemSE(SYS_SE.CLICK_TITLE_NEGATIVE);
						}
						return 1;
					default:
						Log.printError("UNDEF NUMBER : %d", i);
					}

					// ボタン押下SE再生
					info.playSEActive();
					
					break;
				}
				
			}
			
			
			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 {
			info = cast(GameInfo)o;
	
			// 初期化
			if (!init) {
				init = true;
				onInit();
			}

			info.screen.clear();
			info.screen.blendSrcAlpha();
	
			if (!alpha.isEnd()) {
				info.screen.setColor(255,255,255,alpha.get());
			}
	
			// 背景描画
			info.screen.blt(bg,0,0);
			// タイトル描画
			info.screen.blt(m_titleTex, m_tox.getSined(), 0);

			// アルファMAX
			info.screen.setColor( 255,255,255, 255 );
	
			// ボタンの描画
			foreach (inout GUIButton bt; button) {
				bt.onDraw(info.screen);
			}
			
			// スライダー描画
			foreach (inout Slidebar sb; m_volBar) {
				sb.onDraw(info.screen);
			}
			
			if (m_showDlg) {
				m_keyConfDlg.onDraw(info.screen);
			}
	
			return 0;
		} catch (Exception e) {
			Log.printFatal("RuntimeException %s#onDraw : [%s] [%s]", 
				super.toString(), e.toString(), e.msg);
			throw e;
		}
	}

	/// OnDraw+OnMove
	override int task(Object o) {
		return 0;
	}

	/// オブジェクトのメモリを解放する
	override void destroy() {
		Texture.safeRelease(bg);
		Texture.safeRelease(m_baseTexOn);
		Texture.safeRelease(m_baseTexOff);
		Texture.safeRelease(m_barTexOn);
		Texture.safeRelease(m_barTexOff);
		Texture.safeRelease(m_titleTex);

		tl = null;
		alpha = cast(RootCounterS) null;
		
		m_keyGroup = null;
		m_keyConfDlg = null;
		m_volBar = null;
		button = null;
		m_tox = cast(RootCounterS) null;
		OptionInfo optionInfo = null;
		
		if ( !(tl is null) ) {
			tl.releaseAll();
			tl.releaseFileList();
		}

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

	/// コンストラクタ
	this () {
		m_keyGroup = new KeyGroup();
		bg = new Texture;
		alpha = new RootCounterS(0,255,4);

		tl = new TextureLoader();
		tl.loadDefRW( FileSys.read("img/option/op_bt.lst") );

		// 表示位置
		static const PointInt[] point = [
			{x:214,y:106},{x:366,y:106},	// Window / Full
			{x:214,y:145},{x:290,y:145},{x:366,y:145},{x:442,y:145},	// 文章速度
			{x:442,y:199},	// ＢＧＭ
			{x:442,y:239},	// VOICE
			{x:442,y:279},	// 効果音
			{x:214,y:335},	// キーコンフィグ
			{x:538,y:425},	// 戻る
		];

		int i;
		foreach(inout PointInt pt; point) {
			GUIButton bt = new GUIButton;
			bt.setXY(pt.x, pt.y);
			button ~= bt;
			++i;
		}
	}

	/// コンストラクタ
	this (MouseInput mouse) {
		this();
		foreach (inout GUIButton bt; button) {
			bt.setMouse(mouse);
		}
	}

private:

	/// KeyConfigダイアログを動作させます
	void onMoveKeyConfDlg(Screen screen) {
		/// KeyConfigダイアログ
		if (m_showDlg) {
			NullableMouseInput aMouse = cast(NullableMouseInput) info.mouse;
			NullableKeyInput aKey = cast(NullableKeyInput) info.key;
			NullableMouseInput aKeyMouse = cast(NullableMouseInput) info.keyDecolateMouse;
			aMouse.enable();
			aKey.enable();
			aKeyMouse.enable();
			aMouse.updateMark();
			aKey.updateMark();
			aKeyMouse.updateMark();
			aMouse.update();
			aKey.update();
			aKeyMouse.update();
			m_keyConfDlg.onMove(info.screen);

			if (m_keyConfDlg.isFinish()) {
				m_keyConfDlg.hide();
				// キーマッピング更新
				updateJoystickMapping(m_keyConfDlg.getKeyButtonIDs());
				// 設定情報保存
				saveKeyConfigData(m_keyConfDlg.getSrcKey().getDeviceName(),
					m_keyConfDlg.getKeyButtonIDs());
				m_showDlg = false;
				return;
			}	
			
			// このダイアログ以外すべてのマウス操作をキャンセル
			aMouse.disable();
			aKey.disable();
			aKeyMouse.disable();
		}
	}
	
	/// 設定したKEY IDで アップデートする
	void updateJoystickMapping(int[] buttonIDs) {
		try {
			auto aMouse = cast(MousedKey) (cast(NullableKeyInput) info.key).getOriginal();
			assert( !(aMouse is null) );
			assert(buttonIDs.length == 5);
			aMouse.init();
			aMouse.addJoyKeyLeft(buttonIDs[0]);
			aMouse.addJoyKeyRight(buttonIDs[1]);
			aMouse.addJoyKeyWheelUp(buttonIDs[2]);
			aMouse.addJoyKeyWheelDown(buttonIDs[3]);
			aMouse.addJoyKeyExit(buttonIDs[4]);
			Log.print("JOYKEY MAPPING UPDATED");
		} catch (Object o) {
			Log.printFatal("RuntimeException %s#updateJoystickMapping : [%s]", 
				super.toString(), o.toString());
			throw o;
		}
	}

	/// BGM OFF がクリックされたときの処理
	void onClickVolumeOff(int type, inout bool flg, int sliderId) {
		GUIBlinkButtonListener.TYPE typeBlink 
			= GUIBlinkButtonListener.TYPE.DEFAULT | GUIBlinkButtonListener.TYPE.IN_ACTIVE;
		GUIBlinkButtonListener.TYPE typeFix 
			= GUIBlinkButtonListener.TYPE.OFFSET_FIX; 

		GUIBlinkButtonListener v = 
			cast(GUIBlinkButtonListener) button[type].getEvent();
		if (flg) {
			v.setType(typeFix);
			v.setImageOffset(1);
	
			// スライダー画像入れ替え
			replaceTexture(m_volBar[sliderId], m_baseTexOff, m_barTexOff);
		} else {
			v.setType(typeBlink);
			
			// スライダー画像入れ替え
			replaceTexture(m_volBar[sliderId], m_baseTexOn, m_barTexOn);
		}
		flg = cast(bool) !flg;
	}
	
	/// 初期化
	void onInit() {
		// メモリー状況をプリント
		GameInfo.printMemoryState();

		optionInfo = info.optionInfo;
		m_mouse = info.keyDecolateMouse;

		foreach (inout GUIButton bt; button) {
			bt.setMouse(m_mouse);
		}

		// ボリューム操作、委譲処理の生成		
		initDelegate();

		// 背景テクスチャロード
		bg.load(FileSys.makeFullName("img/option/bg.jpg"));
		// タイトルテクスチャ
		m_titleTex = new Texture();
		m_titleTex.load(FileSys.makeFullName("img/option/op_title_last.png"));
		m_tox = new RootCounterS();
		m_tox.set(-50, 0, 1);

		// ボタンの画像番号
		static const int bt_no[] = 
			[	0,2,		// window
				4,6,8,10,	// 文章速度
				12,	// bgm
				12,	// voice
				12,	// se
				14,
				16
			];

		// ボタンの初期化
		foreach(int i,inout GUIButton bt; button) {
			GUIBlinkButtonListener v  = new GUIBlinkButtonListener();
			v.setTextureLader(tl,bt_no[i]);

			GUIBlinkButtonListener.TYPE typeBlink = GUIBlinkButtonListener.TYPE.DEFAULT 
								| GUIBlinkButtonListener.TYPE.IN_ACTIVE;

			switch (i) {
			case eButtonID.WINDOW :
				{
					if (optionInfo.windowMode) {
						v.setType(GUIBlinkButtonListener.TYPE.OFFSET_FIX);
						v.setImageOffset(1);
					} else {
						v.setType(typeBlink);
					}
				}
				break;
			case eButtonID.FULL :
				{
					if (optionInfo.windowMode) {
						v.setType(typeBlink);
					} else {
						v.setType(GUIBlinkButtonListener.TYPE.OFFSET_FIX);
						v.setImageOffset(1);
					}
				}
				break;
			case eButtonID.T_NORMAL:
				{
					if (optionInfo.getTextSpeed()==OptionInfo.TextSpeed.NORMAL) {
						v.setType(GUIBlinkButtonListener.TYPE.OFFSET_FIX);
						v.setImageOffset(1);
					} else {
						v.setType(typeBlink);
					}
				}
				break;
			case eButtonID.T_FAST :
				{
					if (optionInfo.getTextSpeed()==OptionInfo.TextSpeed.FAST) {
						v.setType(GUIBlinkButtonListener.TYPE.OFFSET_FIX);
						v.setImageOffset(1);
					} else {
						v.setType(typeBlink);
					}
				}
				break;
			case eButtonID.T_LINE:
				{
					if (optionInfo.getTextSpeed()==OptionInfo.TextSpeed.LINE) {
						v.setType(GUIBlinkButtonListener.TYPE.OFFSET_FIX);
						v.setImageOffset(1);
					} else {
						v.setType(typeBlink);
					}
				}
				break;
			case eButtonID.T_PAGE :
				{
					if (optionInfo.getTextSpeed()==OptionInfo.TextSpeed.PAGE) {
						v.setType(GUIBlinkButtonListener.TYPE.OFFSET_FIX);
						v.setImageOffset(1);
					} else {
						v.setType(typeBlink);
					}
				}
				break;
			case eButtonID.BGM_OFF:
				{
					if (optionInfo.bgmOn) {
						v.setType(typeBlink);
					} else {
						v.setType(GUIBlinkButtonListener.TYPE.OFFSET_FIX);
						v.setImageOffset(1);
					}
				}
				break;
			case eButtonID.VOICE_OFF:
				{
					if (optionInfo.voiceOn) {
						v.setType(typeBlink);
					} else {
						v.setType(GUIBlinkButtonListener.TYPE.OFFSET_FIX);
						v.setImageOffset(1);
					}
				}
				break;
			case eButtonID.SE_OFF:
				{
					if (optionInfo.seOn) {
						v.setType(typeBlink);
					} else {
						v.setType(GUIBlinkButtonListener.TYPE.OFFSET_FIX);
						v.setImageOffset(1);
					}
				}
				break;
			case eButtonID.KEY_CONFIG:
				{
					if (info.isEnableJoystick()) {
						v.setType(typeBlink);
					} else {
						// 常に無効
						v.setType(GUIBlinkButtonListener.TYPE.OFFSET_FIX);
						v.setImageOffset(0);
					}
				}
				break;
			case eButtonID.BACK:
				{
					v.setType(BT_TYPE_BACK);
					v.setBlinkSpeed(4);
				}
				break;
			default:
				assert(false);
			}

			bt.setEvent(v);
		}
		
		// スライダーの生成
		onInitSlider();
		
		initKeyGroup();
		
		// フォーカスデフォルト設定
		m_keyGroup.focus(button[eButtonID.BACK]);
	}
	
	/// スライダーバーの生成
	void onInitSlider() {
		static const int[][] SLIDER_POS = [
			[214,199],
			[214,239],
			[214,279],
		];
		static int BAR_OFFSETX = 6;
		static int BAR_OFFSETY = 24;
		static int BAR_LENGTH = 194;

		int[] vol;
		vol ~= optionInfo.getBgmVol();			
		vol ~= optionInfo.getVoiceVol();			
		vol ~= optionInfo.getSeVol();			
		
		bool[] volOn;
		volOn ~= optionInfo.bgmOn;
		volOn ~= optionInfo.voiceOn;
		volOn ~= optionInfo.seOn;
		
		m_volBar = null;
		m_baseTexOn = new Texture();
		m_barTexOn = new Texture();
		m_baseTexOff = new Texture();
		m_barTexOff = new Texture();
		m_baseTexOn.load("img/option/op_vol_bar_on.png");
		m_baseTexOff.load("img/option/op_vol_bar_off.png");
		m_barTexOn.load("img/option/op_bt_l_on.png");
		m_barTexOff.load("img/option/op_bt_l_off.png");
		
		for (int i = 0; i < 3; ++i) {
			Slidebar sb = new Slidebar();
			sb.setMouse(info.mouse);
			sb.setKey(info.key);
			
			if ( volOn[i] ) {
				sb.setBaseTexture(m_baseTexOn);
				sb.setBarTexture(m_barTexOn);
			} else {
				sb.setBaseTexture(m_baseTexOff);
				sb.setBarTexture(m_barTexOff);
			}
			
			sb.setXY(SLIDER_POS[i][0], SLIDER_POS[i][1]);
			sb.setSliderOffset(BAR_OFFSETX, BAR_OFFSETY);
			sb.setLength(BAR_LENGTH);
			sb.setSlidePos( vol[i] / 100.0f );
			
			m_volBar ~= sb;
		}
	}
	

	/// 解像度変更に対してリソースのリロードを行う
	void reloadResources() {
		info.screen.disableBlend();
		Texture.restoreAll();

		// 背景画像のリロード		
		reloadTextureLoader(info.tl_bg, "img/back/list.lst");
		
		info.screen.enableBlend();
		info.screen.blendSrcAlpha();
	}
	
	/// TextureLoader の再読込
	static void reloadTextureLoader(TextureLoader tl, char[] filename) {
		tl.releaseAll();
		tl.releaseFileList();
		tl.loadDefRW(FileSys.read(filename));
	}
	
	/// スライダーバーのテクスチャーを入れ替える
	void replaceTexture(Slidebar sb, Texture baseTex, Texture barTex) {
		sb.setBaseTexture(baseTex);
		sb.setBarTexture(barTex);
	}
	
	/// KeyCibfugダイアログを表示する
	void createKeyConfigDialog() {
		m_keyConfDlg = KeyConfigDialog.createDialogBox(
						info.createDialogResources(),
						KEY_CONF_DLG_DEF_FILENAME,
						MouseInputNullDevice.getInstance(),
						info.joystick,
						4);
		m_showDlg = true;
	}
	
	/// キーコンフィグを保存する
	void saveKeyConfigData(char[] deviceName, int[] keyData) 
	in
	{
		assert( !(info.keyConfig is null) );
	}
	body
	{
		info.keyConfig.setDeviceName(deviceName);
		foreach (int i, int keyNo; keyData) {
			int[] tmp = new int[1];
			tmp[0] = keyNo;
			info.keyConfig.setKeyData(i, tmp);
		}
	}
	
	/// キーグループを初期化する
	void initKeyGroup() {
		m_keyGroup.add(button[eButtonID.WINDOW]);
		m_keyGroup.add(button[eButtonID.FULL]);
		m_keyGroup.add(button[eButtonID.T_NORMAL]);
		m_keyGroup.add(button[eButtonID.T_FAST]);
		m_keyGroup.add(button[eButtonID.T_LINE]);
		m_keyGroup.add(button[eButtonID.T_PAGE]);
		m_keyGroup.add(m_volBar[0]);
		m_keyGroup.add(button[eButtonID.BGM_OFF]);
		m_keyGroup.add(m_volBar[1]);
		m_keyGroup.add(button[eButtonID.VOICE_OFF]);
		m_keyGroup.add(m_volBar[2]);
		m_keyGroup.add(button[eButtonID.SE_OFF]);
		m_keyGroup.add(button[eButtonID.KEY_CONFIG]);
		m_keyGroup.add(button[eButtonID.BACK]);
	}
	
	/// ボリューム操作を行う委譲を作成
	void initDelegate() {
		m_setVol[0] = &setBGMVolume; 
		m_setVol[1] = &optionInfo.setVolumeVoice;			
		m_setVol[2] = &optionInfo.setVolumeSE;			
	}
	
	/// BGMボリュームの設定
	void setBGMVolume(int vol) {
		optionInfo.setVolumeBGM(vol);
		int bgmNo = info.bgmloader.getBGMNo();
		if ( 0 <= bgmNo && info.bgmloader.isPlay(bgmNo) ) {
			info.bgmloader.get(bgmNo).setVolume(vol);
		}
	}
	


private:
	static final const char[] KEY_CONF_DLG_DEF_FILENAME = "img/dialog/dialog_keyconfig.txt";
	static int[] btType = [
		eButtonID.BGM_OFF,
		eButtonID.VOICE_OFF,
		eButtonID.SE_OFF,
	];

	// ボタンの名前付け
	enum eButtonID : int { 
				WINDOW,FULL,// ウィドウモード
				T_NORMAL,T_FAST,T_LINE,T_PAGE,	// 文章速度
				BGM_OFF,	// bgm on/off
				VOICE_OFF,	// voice on/off
				SE_OFF,		//  se on/off
				KEY_CONFIG,	// キー設定
				BACK,		// 終了、タイトル、戻る
	};

	// ボタンの名前付け
	enum eSliderID : int { 
		BGM,
		VOICE,
		SE,
	};
	
	static final GUIBlinkButtonListener.TYPE BT_TYPE_BACK = 
		GUIBlinkButtonListener.TYPE.DEFAULT	| GUIBlinkButtonListener.TYPE.BLINK_FIX;

	static const final int volChipWidth = 19;
	
	GameInfo info;
	MouseInput m_mouse;
	OptionInfo optionInfo;
	void delegate(int)[3] m_setVol;
	
	Texture m_titleTex;
	RootCounterS m_tox;	//!< タイトルテクスチャのスライドインオフセット
	
	Texture bg;
	Texture m_baseTexOn;
	Texture m_baseTexOff;
	Texture m_barTexOn;
	Texture m_barTexOff;
	
	TextureLoader tl;
	bool m_keyPush;
	KeyGroup m_keyGroup;
	GUIButton[] button;
	Slidebar[] m_volBar;

	RootCounterS alpha;

	bool init;
	
	// keyConfig 用ダイアログ
	bool m_showDlg;
	KeyConfigDialog m_keyConfDlg;
}
