module kyojintati4d.taskendingkyojin;

private import SDL;

private import std.utf;

private import y4d;
private import y4d_aux.filesys;
private import y4d_draw.texturebase;
private import y4d_draw.transbltter;

private import kyojintati4d.myapp;
private import kyojintati4d.gameinfo;
private import kyojintati4d.component.rhythm.keyconfigdialon;
private import kyojintati4d.component.ending.scenebase;
private import kyojintati4d.component.ending.scene01;
private import kyojintati4d.component.ending.scene02;
private import kyojintati4d.component.ending.scene03;
private import kyojintati4d.component.ending.scene04;
private import kyojintati4d.component.ending.scene05;

private import yamalib.draw.camerawork;
private import yamalib.draw.filmnoise;
private import yamalib.draw.drawassist;
private import yamalib.counterfsp;
private import yamalib.log.log;


// 去人パートエンディングタスク
class TaskEndingKyojin : GameTaskBase {
	
	/// 移動処理
	override int onMove(Object o) {

		GameInfo info = cast(GameInfo) o;
		if (!init) {
			onInit(info);
			// FPS を 30にする 終わったら元に戻すこと！
			info.getFpsTimer().setFps(30);
			init = true;
		}
		mouse.update();
		textuaryTempo1.onMove(info.screen);

		// わけのわからんヒットされたら、hitCounter に教えてやる
		if (textuaryTempo1.isInvalidHit) {
			EndingSceneBase.gamePointcalculator.calcHitPoint(HitStatus.ERROR);
		}
		
		if (!startScene01 && scene01.isStart()) {
			activeScene ~= scene01;
Log.print("START SCENE [%s] %s", masterTimer.get(), scene01.toString);
			startScene01 = true;		
		}
		
		if (!startScene02 && scene02.isStart()) {
			activeScene ~= scene02;
Log.print("START SCENE [%s] %s", masterTimer.get(), scene02.toString);
			startScene02 = true;		
		}

		if (!startScene03 && scene03.isStart()) {
			activeScene ~= scene03;
Log.print("START SCENE [%s] %s", masterTimer.get(), scene03.toString);
			startScene03 = true;		
		}
		if (!startScene04 && scene04.isStart()) {
			activeScene ~= scene04;
Log.print("START SCENE [%s] %s", masterTimer.get(), scene04.toString);
			startScene04 = true;		
		}
		if (!startScene05 && scene05.isStart()) {
			textuaryTempo1.fadeStop(2500);
			activeScene ~= scene05;
Log.print("START SCENE [%s] %s", masterTimer.get(), scene05.toString);
			startScene05 = true;		
		}

		// シーン
		EndingSceneBase[] aliveScene;
		foreach(inout scene; activeScene) {
			if (scene is null) {
				continue;
			}
			scene.onMove(info.screen);
			if (scene.isEnd()) {
Log.print("END SCENE %s", scene.toString);
				scene.release();
				scene = null;
			} else {
				aliveScene ~= scene;
			}
		}
		activeScene = aliveScene;
		
		if (scene05.isEnd) {
			// フェードアウトしてシーン終了
			fadeCounter.inc();
			if (fadeCounter.isEnd()) {
				// ５万点以上なら、デバッグモードON
				if (!m_autoPlay && 20_000 <= EndingSceneBase.gamePointCal.totalPoint) {
					info.useTestMusic = true;
				}
				// 終わったので 60 に戻す！
				info.getFpsTimer().setFps(60);
				finishScene(info);
				return -1;
			}
		}
		return 0;
	}
	
	
	/// 描画処理
	override int onDraw(Object o) {

		GameInfo info = cast(GameInfo) o;
		info.screen.clear();

		// シーン
		foreach(scene; activeScene) {
			scene.onDraw(info.screen);
		}

		info.screen.blendAddColorAlpha();
		textuaryTempo1.onDraw(info.screen);
		info.screen.blendSrcAlpha();
		
		// スコア表示
		if (m_showScore) {
			onDrawScore(info.screen, 0, 0);
		}

		// 時間表示
		if (m_showScore) {
			onDrawTime(info.screen, 450, 0);
		}

		return 0;
	}
	
	int task(Object o) {
		return 0;
	}

	/// 占有しているメモリを解放する
	override void destroy() {
//		textuaryTempo1.release();
		statusImgLoader.releaseAll();
		bgmLoader.releaseAll();
	}
	
private:

	/// 初期化処理
	void onInit(GameInfo info) {
		
		Log.print("ENDING SETUP START");
		// 動作オプション
		if (info.endingOptionFlg.length >= 1) {
			// オートプレイ
			m_autoPlay = info.endingOptionFlg[0];
		}
		if (info.endingOptionFlg.length >= 2) {
			// ガイド表示
			m_showAimMark = info.endingOptionFlg[1];
		}
		if (info.endingOptionFlg.length >= 3) {
			// ムービー表示
			m_useMovie = info.endingOptionFlg[2];
		}
		if (info.endingOptionFlg.length >= 4) {
			// タイム表示し
			m_showTime = info.endingOptionFlg[3];
		}
		if (info.endingOptionFlg.length >= 5) {
			// スコア表示
			m_showScore = info.endingOptionFlg[4];
		}

		// パフォーマンス測定 これやると環境によっておかしくなる
//		long drawPerformance = getDrawPerformance(info.screen);
//		Log.print("DRAW PERFORMANCE:%s", drawPerformance);
//		if (drawPerformance < 10000) {
//			// ムービーON
//		}

		initialize();
		
		// ヒットヒストリーを初期化
		EndingSceneBase.gamePointcalculator.clearStatusHistory();
		
		// リソース読み込み
		statusImgLoader = new TextureLoader();

		statusImgLoader.loadDefRW(cast(char[]) "img2\\ending\\status.lst");
		

		bgmLoader = new SoundLoader();
		bgmLoader.loadDefRW(cast(char[])"snd\\bgm\\ed_test\\ending.ogg\nsnd\\bgm\\ed_test\\ed2.ogg\nsnd\\bgm\\ed_test\\ed3.ogg\nsnd\\bgm\\ed_test\\ed4.ogg");
		
		startPart = 0;

		// ボリューム０で再生しておく
		bgmLoader.get(startPart).setVolume(0);
		bgmLoader.playBGM(startPart);

		mouse = info.keyDecolateMouse;

		// フォントリポジトリをセット
		setupFontRepository(info);
		
		// テンポ用テキストの見込み
		tempoText = .toWCS(cast(char[]) FileSys.read(cast(char[]) "img2/ending/tempo_text.txt"));
		// ならしておく
		foreach(wch; tempoText) {
			m_fontRep.getTexture(wch);
		}

		textuaryTempo1 = new TextuaryTempo();
		setupTextuaryTempo(textuaryTempo1, createTempoData());
//		textuaryTempo2 = new TextuaryTempo();
//		setupTextuaryTempo(textuaryTempo2);

		// OSスワップとかGCを考慮して 5秒待つ
		SDL_Delay(5_000);

		textuaryTempo1.reset();

		// BGM再生		
		bgmLoader.get(startPart).setVolume(info.optionInfo.getBgmVol());
		bgmLoader.playBGM(startPart);
		SDL_Delay(250);
		Log.print("BGM VOLUME:%s", bgmLoader.get(startPart).getVolume());

		switch(startPart) {
		case 0:
			masterTimer.reset();
			break;
		case 1:
			masterTimer.set(64_900 + EndingSceneBase.MUSIC_OFFSET_TIME);
			break;
		case 2:
			masterTimer.set(88_491 + EndingSceneBase.MUSIC_OFFSET_TIME);
			break;
		case 3:
			masterTimer.set(152_741 + EndingSceneBase.MUSIC_OFFSET_TIME);
			break;
		case 4:
			masterTimer.set(195_704 + EndingSceneBase.MUSIC_OFFSET_TIME);
			break;
		default:
			assert(true);
			break;
		}
		Log.print("ENDING SETUP FINISH");
	}
	
	// 全ムービーファイルの列挙
	static const char[][] ALL_MOVIE_FILE = [
	       "img2\\ending\\movie\\akirako.mpg",
	       "img2\\ending\\movie\\arise.mpg",
	       "img2\\ending\\movie\\ayako.mpg",
	       "img2\\ending\\movie\\eijii.mpg",
	       "img2\\ending\\movie\\eizou.mpg",
	       "img2\\ending\\movie\\huura.mpg",
	       "img2\\ending\\movie\\itsuka.mpg",
	       "img2\\ending\\movie\\kana.mpg",
	       "img2\\ending\\movie\\mari.mpg",
	       "img2\\ending\\movie\\nora.mpg",
	       "img2\\ending\\movie\\nozomi.mpg",
	       "img2\\ending\\movie\\risa.mpg",
	       "img2\\ending\\movie\\usami.mpg",
       ];
	// 動画ファイルに対する名前付け。↑とリンクする名前
	enum MOVIE_CHARA {
		AKIRAKO, 
		ARISE, 
		AYAKO,
		EIJI, 
		EIZOU, 
		HURA, 
		ITSUKA, 
		KANA, 
		MARI, 
		NORA, 
		NOZOMI, 
		RISA, 
		USAMI
	};
	
	// ムービーの一時テンポラリファイル
	FileSys.TmpFile[] movieFiles;
	
	/// テキストテンポオブジェクトのセットアップ
	void setupTextuaryTempo(TextuaryTempo textuaryTempo, TempoData[] tempoData) {
		textuaryTempo.mouse = mouse;
		textuaryTempo.fontRepository = m_fontRep;
		textuaryTempo.tempoData = tempoData;
		textuaryTempo.autoPlay = m_autoPlay;
		
		// 開始・終端の設定
		textuaryTempo.startPos.x = 900;
		textuaryTempo.startPos.y = 100;
		textuaryTempo.endPos.x = 50;
		textuaryTempo.endPos.y = 700;
		
		// 文字サイズ
		textuaryTempo.startRate = 0.5f;
		textuaryTempo.endRate = 2.5f;
		
		// 文字生成
		textuaryTempo.generateInterval = 100L;
		
		// 許容マージン
		textuaryTempo.hitMargin = 100L;
		
		// ヒットポイント到達時間
		textuaryTempo.arrivalTime = 1250L;

		if (m_showAimMark) {
			// 照準画像
			auto scopImg = new Texture();
			scopImg.load(cast(char[]) "img2/ending/scope.png");
			textuaryTempo.scopeImg = scopImg;
		}
		
		// タイマーを一元化する
		textuaryTempo.timer = masterTimer;
		textuaryTempo.alphaCounter.set(0, 200 ,1);
		
		// Scene05用に設定
		(cast(Scene05) scene05).setFontRepository(m_fontRep);
	}
	
	/** スコアを描画する */
	void onDrawScore(Screen screen, int x, int y) {
		int scorePoint = cast(int) EndingSceneBase.gamePointCal.totalPoint;
		char[] drawString = cast(char[]) "SCORE:" ~ std.string.toString(scorePoint);
		auto scorePointStr = std.utf.toUTF16( drawString );
		Texture[] pointTexture;
		foreach(w;scorePointStr) {
			pointTexture ~= m_fontRep.getTexture(w);
		}
		onDrawNumberTexture(screen, pointTexture, x, y, 1.0f);
	}
	
	/** 時間を表示 */
	void onDrawTime(Screen screen, int x, int y) {
		char[] drawString = cast(char[]) "TIME:" ~ std.string.toString(masterTimer.get());
		auto scorePointStr = std.utf.toUTF16( drawString );
		Texture[] pointTexture;
		foreach(w;scorePointStr) {
			pointTexture ~= m_fontRep.getTexture(w);
		}
		onDrawNumberTexture(screen, pointTexture, x, y, 1.0f);
	}
	
	/** テクスチャーを左詰で表示 */
	void onDrawNumberTexture(Screen screen, Texture[] textures, int x, int y, float sizeRate) {
		auto colorOrg = screen.getColor4ub();
		screen.setColor(255,255,255, 128);
		// スコアの描画
		float ox = 0.0f;
		foreach(texture;textures) {
			screen.bltRotate(texture, x + cast(int) ox, y, 0, sizeRate, 0);
			ox += texture.getWidth() * sizeRate + 3.0f;
		}
		screen.setColor(colorOrg);
	}
	
	
	/** 実行しているマシンの描画パフォーマンスを調べる */
	long getDrawPerformance(Screen screen) {
		auto performanceTimer = new Timer();
		auto img = new Texture();
		img.load(cast(char[]) "img2/ending/test.jpg");
		long loopCount = 0;
		performanceTimer.reset();
		while(performanceTimer.get() < 2000) {
			loopCount++;
			screen.blt(img, 0, 0);
		}
		screen.clear();
		return loopCount;
	}
	
	void setupFontRepository(GameInfo info) {
		m_fontRep = new FontRepository();
		m_fontRep.setLoader(info.fontloader, KyojinConst.C_FONT_NO_KYOJIN_MAIN_TEXT);
		m_fontRep.setMax(300);
	}
	
	/// テンポデータ
	TempoData[] createTempoData() {
		TempoData[] result;
		
		result ~=  new TempoData(tempoText, 
			timing1_1 
			~ timing1_2
			~ timing1_3
			~ timing1_4
			~ timing1_5
			~ timing1_6
			~ timing1_7

			~ timing2_1
			~ timing2_2

			~ timing3_1
			~ timing3_2
			~ timing3_3
			~ timing3_4
			~ timing3_5
			~ timing3_6
			~ timing3_7

			~ timing4_1
			~ timing4_2
			~ timing4_3
			~ timing4_4
			);

		return result;
	}

	HitEvent event;
	FontRepository m_fontRep;
	wchar[] tempoText;

	/** コンストラクタ */
	public this() {
		masterTimer = new FixTimer();
	}
	
	void initialize() {
		scene01 = new Scene01(masterTimer);
		scene01.cacheTexture();
		timing1_1 = scene01.timingData[0];
		timing1_2 = scene01.timingData[1];
		timing1_3 = scene01.timingData[2];
		timing1_4 = scene01.timingData[3];
		timing1_5 = scene01.timingData[4];
		timing1_6 = scene01.timingData[5];
		timing1_7 = scene01.timingData[6];

		scene02 = new Scene02(masterTimer);
		scene02.cacheTexture();
		timing2_1 = scene02.timingData[0];
		timing2_2 = scene02.timingData[1];

		//－－－－－－－－－－－－－
		scene03 = new Scene03(masterTimer, m_useMovie);
		scene03.cacheTexture();
		timing3_1 = scene03.timingData[0];
		timing3_2 = scene03.timingData[1];
		timing3_3 = scene03.timingData[2];
		timing3_4 = scene03.timingData[3];
		timing3_5 = scene03.timingData[4];
		timing3_6 = scene03.timingData[5];
		timing3_7 = scene03.timingData[6];

		scene04 = new Scene04(masterTimer);
		scene04.cacheTexture();
		timing4_1 = scene04.timingData[0];
		timing4_2 = scene04.timingData[1];
		timing4_3 = scene04.timingData[2];
		timing4_4 = scene04.timingData[3];

		scene05 = new Scene05(masterTimer);
		scene05.cacheTexture();
//		timing5_1 = scene05.timingData[0];
//		timing5_2 = scene05.timingData[1];
//		timing5_3 = scene05.timingData[2];
//		timing5_4 = scene05.timingData[3];
		
		// フェードアウト用
		fadeCounter = new RootCounterS(255, 0, 1);
	}

	/** エンディングタスクを終了してタイトルに戻る */
	void finishScene(GameInfo info) {
		info.mouse.show();
		// エンディング終了
		// すべてのスタックを破棄		
		info.gameSceneTransiter.exitScene();

		info.gameSceneTransiter.setTransitType( -1, 1, false );
		info.gameSceneTransiter.jumpScene(KyojinConst.Task.Task_Title);
		Log.print("%s#onMove : ALL SCENE FINISHED." , super.toString());
	}

	// フィールド
	
	bool taskEnd;
	RootCounterS fadeCounter;
	
	TimingData[] timing1_1;
	TimingData[] timing1_2;
	TimingData[] timing1_3;
	TimingData[] timing1_4;
	TimingData[] timing1_5;
	TimingData[] timing1_6;
	TimingData[] timing1_7;
	TimingData[] timing2_1;
	TimingData[] timing2_2;
	TimingData[] timing3_1;
	TimingData[] timing3_2;
	TimingData[] timing3_3;
	TimingData[] timing3_4;
	TimingData[] timing3_5;
	TimingData[] timing3_6;
	TimingData[] timing3_7;
	TimingData[] timing4_1;
	TimingData[] timing4_2;
	TimingData[] timing4_3;
	TimingData[] timing4_4;
	TimingData[] timing5_1;
	TimingData[] timing5_2;
	TimingData[] timing5_3;
	TimingData[] timing5_4;
	TimingData[] timing5_5;

	bool init;
	int startPart = 0;
	MouseInput mouse;
	final FixTimer masterTimer;
	TextuaryTempo textuaryTempo1;
	
	// 自動プレイ
	bool m_autoPlay = false;
	// タイム表示
	bool m_showTime = false;
	// 照準の表示
	bool m_showAimMark = false;
	// スコア
	bool m_showScore = false;
	
	bool m_useMovie = false;
	
	bool startScene01 = false;
	bool startScene02 = false;
	bool startScene03 = false;
	bool startScene04 = false;
	bool startScene05 = false;
	EndingSceneBase scene01;
	EndingSceneBase scene02;
	EndingSceneBase scene03;
	EndingSceneBase scene04;
	EndingSceneBase scene05;
	
	EndingSceneBase[] activeScene;
	
	// イベント用
	TextureLoader statusImgLoader;
	
	SoundLoader bgmLoader;
	
}

