module kyojintati4d.taskdevroom;

private import std.stream;
private import std.string;
private import std.utf;

private import y4d;
private import y4d_aux.filesys;
private import y4d_aux.lineparser;
private import y4d_draw.sprite;
private import y4d_draw.drawbase;

private import kyojintati4d.myapp;
private import kyojintati4d.val.kyojinconst;
private import kyojintati4d.gameinfo;
private import kyojintati4d.bookmark;

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

private import yamalib.draw.textdraw;
private import yamalib.draw.scenariodraw;

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

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

			m_mouse.update();

			// キー操作によるフォーカシング
			if ( info.key.isPush(1) ) {
				m_keyGroup.prev();
			} else if ( info.key.isPush(2) ) {
				m_keyGroup.next();
			}
			
			// scenario コンポーネント動作
			if (0 <= m_selectedIndex) {
				onMoveScenario();
			}
			onMoveMenu();
			return 0;
		} catch (Exception e) {
			Log.printFatal("RuntimeException %s#onMove : [%s] [%s]", 
				super.toString(), e.toString(), e.msg);
			throw e;
		}
	}
	
	/// 描画の処理を行います
	int onDraw(Object o) {
		try {
			info = cast(GameInfo) o;

			if (!m_init) {
				onInit();
				info.screen.blendSrcAlpha();
				m_init = true;
			}

			// 背景消し
			info.screen.clear();
			Color4ub colorOrg = info.screen.getColor4ub();
			// 背景描画
			info.screen.setColor(255,255,255,255);
			info.screen.blendSrcAlpha();
			info.screen.blt(m_imgBg,0,0);
			
			info.screen.blt(m_imgScenarioFrame, SCENARIO_COM_POS.x, SCENARIO_COM_POS.y);
			
			// シナリオ描画
			if (0 <= m_selectedIndex) {
				info.screen.setColor(255,255,255,255);
				info.screen.blendSrcAlpha();
				onDrawScenario();
			}

			// メニュー描画
			info.screen.setColor(255,255,255,255);
			info.screen.blendSrcAlpha();
			onDrawMenu();
			
			// カラー戻し
			info.screen.setColor(colorOrg);
			
			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_scriptFilePath = null;
		m_nameList = null;
		
		Texture.safeRelease(m_imgBg);
		Texture.safeRelease(m_imgScenarioFrame);
		
		foreach(t;m_imgNames) {
			Texture.safeRelease(t);
		}
		Texture.safeRelease(m_imgExit);
		m_scenarioDraw = null;
		
		m_menuButtons = null;
		m_returnButton = null;

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

	/// コンストラクタ
	this() {
		// KeyGroup
		m_keyGroup = new KeyGroup();
		// 背景用のアルファ
		m_bgAlpha = new RootCounterS();
		m_selectedIndex = -1;
	}
	
	/// 静的コンストラクタ
	static this() {
	}


private:
	/// 矩形内にその点は存在するか
	static bool ptInRect(int px, int py, int left, int top, int right, int bottom) {
		return cast(bool) (px >= left && px < right
			&& py >= top && py < bottom);
	}

	/// シナリオコンポーネントの描画位置
	static final const PointInt SCENARIO_COM_POS = {x:180, y:20};

	/// シナリオ選択ボタンの位置
	static final const PointInt[] MENU_POS = [
		{x:0,y:20},
		{x:0,y:56},
		{x:0,y:92},
		{x:0,y:128},
		{x:0,y:164},
		{x:0,y:200},
		{x:0,y:236},
		{x:0,y:272},
		{x:0,y:308},
		{x:0,y:344}
	];
	
	static final const PointInt SCENARIO_VIEW_NULL_BT_POS = {x:600,y:390};

	/// 戻るの位置
	static final const PointInt MENU_EXIT_POS = {x:30,y:435};
	
	/// シナリオリソースのパステンプレート(背景リスト)	
	static final const char[] PATH_BG = "img/devroom/{0}/bg/bg.lst";
	/// キャラクターリスト
	static final const char[] PATH_CHARA_LIST = "img/devroom/{0}/chara.lst";
	/// キャラクターマップリスト
	static final const char[] PATH_CHARA_MAP_LIST = "img/devroom/{0}/chara_map.lst";
	/// シナリオスクリプト本体
	static final const char[] PATH_SCENARIO_FILE = "img/devroom/{0}/scenario.html";
	static final const char[] PATH_SE_LIST_FILE = "img/devroom/{0}/se/se.lst";
	
	/// 戻るボタンの位置
	static final const PointInt RETURN_BT_POS = {x:0, y:420};
	/// 名前を描画する拡大率
	static final const float NAME_RATE = 1.0f;
	/// メニュー１つの高さ
	static final const int MENU_HEIGHT = 36;
	/// シナリオコンポーネントの大きさ
	static final const RectInt SCENARIO_VIEW_RECT = {
			left:180,top:20,right:627,bottom:400
		};
	
	
	/// マウスは今、シナリオビュー内にあるか
	bool mouseInSecenarioView() {
		int mx,my;
		m_mouse.getPos(mx,my);
		return ptInRect( mx, my, 
			SCENARIO_VIEW_RECT.left, SCENARIO_VIEW_RECT.top, 
			SCENARIO_VIEW_RECT.right, SCENARIO_VIEW_RECT.bottom);
	}
	
	/// 初期化
	void onInit() {
		// メモリー状況をプリント
		GameInfo.printMemoryState();
		
		// マウス
		m_mouse = info.keyDecolateMouse;
		m_key = info.key;

		// 背景画像読み込み
		m_imgBg = new Texture();
		m_imgBg.load("img/devroom/staff_bg_3.png");
		
		m_imgScenarioFrame = new Texture();
		m_imgScenarioFrame.load("img/devroom/staff_fr.png");
		
		// コンテンツ名（開発者名）とそのパスキーを読み込む
		listScliptFilePath();
		// メニューに表示する名前テクスチャの作成
		createNameTexture();
		
		// 各ボタンの初期化
		onInitButtons();
		
		// シナリオコンポーネントの初期化
//		initScenario();
		
		Log.printLook("onInit FINISH");
	}
	
	/// シナリオコンポーネントを動作させる
	void onMoveScenario() {
		try {
			if ( !mouseInSecenarioView() ) {
				return;
			}
			bool bInputCancel = false;
			bool bShowYesNo = info.isShowYesNo;
			bool selectWaiting = m_scenarioDraw.isSelectWait();
			m_mouse.update();
	
			bool drawObject = !(m_key.isPress(11) || m_key.isPress(12)); // 左右Ctrl 
			m_scenarioDraw.setDrawText(drawObject);
			m_scenarioDraw.onMove(info.screen);
			
			if (!bInputCancel && !selectWaiting) {
				if ( m_mouse.isLButtonUp() ) {
					m_scenarioDraw.setNext(true);
				} else if ( m_mouse.isRButtonUp() ) {
					m_scenarioDraw.setCancelNowText(true);
				}
			}
	
		} catch (Exception e) {
			Log.printFatal("RuntimeException %s#onMoveScenario : [%s] [%s]", 
				super.toString(), e.toString(), e.msg);
			throw e;
		}
	}
	/// シナリオコンポーネントの描画
	void onDrawScenario() {
		if (!m_scenarioDraw.isEnd()) {
			m_scenarioDraw.onDraw(info.screen);
		}
	}
	
	/// メニューボタンの動作
	void onMoveMenu() {
		if ( mouseInSecenarioView() ) {
			return;
		}
		// シナリオ選択ボタン
		foreach (int i,GUIButton bt; m_menuButtons) {
			if (m_imgNames.length <= i) {
				break;
			}
			bt.onMove(info.screen);
			if (bt.isLClick()) {
				m_selectedIndex = i;
				initScenario(m_scriptFilePath[i]);
				// 右クリック
				break;
			}
		}

		// 戻るボタン
		m_returnButton.onMove(info.screen);
		if (m_returnButton.isLClick()) {
			info.gameSceneTransiter.returnScene();
			
			// シナリオとかで鳴ってる音を消そう
			Sound.stopAll();
			
			// このタスクのせいではないんだが、ならしておかないと怒るだろうなぁ
			if (!info.bgmloader.get(0).isPlay()) {
				info.bgmloader.get(0).setLoop(-1);
				info.bgmloader.get(0).setVolume(20);
				info.bgmloader.get(0).play();
			}
		}
		
	}
	/// メニューボタンの動作
	void onDrawMenu() {
		// 名前の描画
		foreach (int i, Texture t; m_imgNames) {
			info.screen.bltRotate(t, 10, MENU_POS[i].y + 15, 0, NAME_RATE, 0);
		}

		// アクティブメニュー -1はアクティブなし
		if ( 0 <= m_selectedIndex ) {
			info.screen.blt(m_imgActMenu, 0, MENU_POS[m_selectedIndex].y);
		}

		// 戻るボタン
		m_returnButton.onDraw(info.screen);
		info.screen.blt(m_imgExit, MENU_EXIT_POS.x, MENU_EXIT_POS.y);
	}
	
	/// 各ボタンの生成
	void onInitButtons() {
		auto tl = new TextureLoader();
		tl.loadDefFile("img/devroom/menu.lst");
		m_imgActMenu = tl.get(1);
		foreach (int i, inout PointInt pos; MENU_POS) {
			// メニュー作成
			auto bt = new GUIButton();
			bt.setMouse(this.m_mouse);
			bt.setXY(pos.x, pos.y + 10);
			auto v = new GUINormalButtonListener();
			v.setTextureLader(tl,0);
			// on/off + focus
			v.setType(9);
			bt.setEvent(v);
			m_menuButtons ~= bt;
			
			if (m_imgNames.length > i) {
				// プレースフォルダとして１０まであるが、実際には設定ファイルに記された
				// 数だけ読み込む
				// keyGroupに登録
				m_keyGroup.add(bt);
			}
		}

		m_returnButton = new GUIButton();
		m_returnButton.setMouse(this.m_mouse);
		m_returnButton.setXY(RETURN_BT_POS.x, RETURN_BT_POS.y);
		auto v = new GUINormalButtonListener();
		v.setTextureLader(tl, (MENU_POS.length+1) * 2);
		// on/off + focus
		v.setType(9);
		m_returnButton.setEvent(v);

		// keygroup に登録
		m_keyGroup.add(m_returnButton);
		
		// Scenarioフォーカス用
		m_keyGroup.add( createNullButton() );
	}
	
	// ScenarioのViewにフォーカスさせるためのnullボタンを生成する
	GUIButton createNullButton() {
		auto bt = new GUIButton();
		auto v = new GUINullButtonListener();
		bt.setMouse(this.m_mouse);
		bt.setEvent(v);
		bt.setXY(SCENARIO_VIEW_NULL_BT_POS.x, SCENARIO_VIEW_NULL_BT_POS.y);
		return bt;
	}
	
	
	/// シナリオオブジェクトの初期化
	void initScenario(char[] pathKey) {
		char[] baseDevName = pathKey;
		
		m_scenarioDraw = new ScenarioDrawEx(
			std.string.replace(PATH_CHARA_LIST,"{0}", baseDevName), 
			std.string.replace(PATH_CHARA_MAP_LIST,"{0}", baseDevName) );
			
		// se読込
		auto seLoader = new SoundLoader();
		seLoader.loadDefFile(std.string.replace(PATH_SE_LIST_FILE,"{0}", baseDevName));
			
		m_context = new TextDrawContext();
		m_scenarioInfo = new ScenarioInfo();
		
		m_context.width = 380;
		m_context.viewWidth = 448;
		
		char[] strText = cast(char[]) FileSys.read( std.string.replace(PATH_SCENARIO_FILE,"{0}", baseDevName) );
		m_context.setText( toWCS(strText) );
		m_scenarioInfo.storyNo = 0;
		
		// 使用するテクスチャの読込
		auto shilTextureLoader = new TextureLoader();
		shilTextureLoader.loadDefRW(FileSys.read( std.string.replace(PATH_CHARA_LIST,"{0}", baseDevName) ));
		auto bgTextureLoader = new TextureLoader();
		bgTextureLoader.loadDefRW(FileSys.read( std.string.replace(PATH_BG,"{0}", baseDevName) ));
		
		
		m_scenarioDraw.setBackFillter(true);	// 背景暗幕を使用しない
		m_scenarioDraw.setMouse( m_mouse );
		m_scenarioDraw.setKey( info.key );
		m_scenarioDraw.setScenarioInfo(m_scenarioInfo);
		m_scenarioDraw.setTextDrawContext(m_context);
		m_scenarioDraw.setBGLoader(bgTextureLoader);
		m_scenarioDraw.setSilhouetteLoader(shilTextureLoader);
		m_scenarioDraw.setBGMLoader(info.bgmloader);
		m_scenarioDraw.setSELoader(seLoader);
		m_scenarioDraw.setVoiceLoader(info.voiceloader);
		m_scenarioDraw.setFontLoader(info.fontloader, KyojinConst.C_FONT_NO_DEVROOM, KyojinConst.C_FONT_NO_RUBI);
		m_scenarioDraw.setOffset(204,40);
		m_scenarioDraw.setBgCharaOffset(180,20);
		m_scenarioDraw.setDialogResources( info.createDialogResources() );
		// オプション情報の反映は、各Loaderが設定されたあと
		m_scenarioDraw.setOptionInf(info.optionInfo);
		
		// プロンプトカーソルのセット
		Texture t = new Texture();
		t.load( FileSys.makeFullName("img/scenario/carsor.png") );
		m_scenarioDraw.setPromptCarsor(t);
		// 改ページの画像
		initNewPageSprite();

		// 背景フィルター
		auto bgFillter = new Texture();
		bgFillter.load(FileSys.makeFullName("img/devroom/bg_fillter.png"));
		m_scenarioDraw.setBackFillter(bgFillter);
	}
	
	/// スクリプトファイルパスの場所を取得する
	void listScliptFilePath() {
		ubyte[] mem = cast(ubyte[]) FileSys.read("img/devroom/name_list.txt");
		std.stream.MemoryStream m = new std.stream.MemoryStream(mem);
		LineParser lineParser = new LineParser();
		while (!m.eof) {
			char[] linebuf = m.readLine();
			lineParser.setLine(linebuf);
			char[] devName = lineParser.getStr();
			if (devName.length == 0 || devName is null) {
				continue;
			} 
			char[] pathKey = lineParser.getStr();
			if (pathKey.length == 0 || pathKey is null) {
				continue;
			}
			
			m_nameList ~= devName;
			m_scriptFilePath ~= pathKey;
		}
	}
	
	/// 改ページ表示用のスプライトをロードする
	void initNewPageSprite() {
		SpriteLoader spriteLoader = new SpriteLoader();
		SpriteEx spriteEx = new SpriteEx();
		spriteLoader.load( FileSys.makeFullName("img/scenario/newpage.sdf") );
		spriteEx.setSprite( spriteLoader.getSprite() );
		m_scenarioDraw.setNewPageSprite( spriteEx );
	}

	/// シナリオスクリプトを読み込み、設定します	
	void loadScenario(char[] scriptFilename) {
		char[] strText = cast(char[]) FileSys.read(scriptFilename);
		m_context.setText( toWCS(strText) );
		m_scenarioDraw.onLoad( m_scenarioInfo, m_context, true );
	}
	
	/// メニューに表示する名前を作成する
	void createNameTexture() {
		foreach(str;m_nameList) {
			auto t = new Texture();
			t.setSurface( info.fontloader.get(KyojinConst.C_FONT_MAIN).drawBlendedUTF8( str ) );
			m_imgNames ~= t;
		}
		
		// exit
		m_imgExit = new Texture();
		m_imgExit.setSurface( info.fontloader.get(KyojinConst.C_FONT_MAIN).drawBlendedUnicode( "EXIT", false ) );
	}
	

private:
	GameInfo info;
	MouseInput m_mouse;	//!< 統一的に使用するマウス
	KeyInputBase m_key;
	bool m_init = false;	//!< 初期化フラグ

	bool m_destroyTask;	//!< タスク終了フラグ
	bool m_mainMenu;	//!< 今表示しているのはメインメニューか
	bool m_switingMenu;	//!< メニュー切り替え中か？
	bool m_afterIn;		//!< スライドイン中
	int m_lastSelect;	//!< 最後に選択されたメニューを保持しておき、それをアクティブにする
	GUIButton[] m_menuButtons;	//!< メニューボタンの配列
	GUIButton m_returnButton;
	KeyGroup m_keyGroup;	//!< キーグループ

	char[][] m_scriptFilePath;
	char[][] m_nameList;
	Texture m_imgBg;
	Texture m_imgScenarioFrame;
	Texture[] m_imgNames;
	Texture m_imgExit;
	Texture m_imgActMenu;
	int m_selectedIndex;

	ICounter m_bgAlpha;
	
	bool m_into;
	
	TextDrawContext m_context;		//!< 描画コンテキスト
	ScenarioDrawEx m_scenarioDraw;	//!< ScenarioDrawコンポーネント
	ScenarioInfo m_scenarioInfo;
	
}
