module kyojintati4d.tasktelopkyojin;

private import std.stream;

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

private import kyojintati4d.myapp;
private import kyojintati4d.gameinfo;

private import yamalib.draw.spreadstring;
private import yamalib.draw.slideshadedraw;
private import yamalib.counterfsp;
private import yamalib.log.log;

/***
	シナリオテロップクラス
*/
class TaskTelopKyojin : GameTaskBase {

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

		if (!init) {
			onInit();
//			info.screen.setClearColor(255,255,255);
			init = true;
		}
		
		timer.update();

		switch (sceneNo) {
		case SCENE_ID.FADE_IN:
			alpha.inc();
			if (alpha.isEnd()) {
				sceneNo = SCENE_ID.OPENING;
			}
			break;

		case SCENE_ID.OPENING:
			if (timer.get() > OPENING_END_TIME) {
				bool allEnd = true;
				// 全部フェードアウトするまで待つ
				foreach(spreadStringBlur;spreadStringBlurs) {
					spreadStringBlur.onMove(info.screen);
					if (!spreadStringBlur.isEndAlpha()) {
						 allEnd = false;
						 break;
					}
				}
				if (allEnd) {
					// 次のシーンのセットアップ
					foreach(i, spreadStringBlur;spreadStringBlurs) {
						spreadStringBlur.onMove(info.screen);
						if (spreadStringBlur.isEndAlpha()) {
							spreadStringBlur.reset();
							spreadStringBlur.setCounterBase(0.96f);
							// 文字列を設定
							spreadStringBlur.setStringUnicode(messages[rand.get(messages.length)]);
							// yを設定
							spreadStringBlur.setY((i + 1) * 120);
							spreadStringBlur.setX(320);
							spreadStringBlur.getFront.setRad((i % 2) ? 256 : 0);
							spreadStringBlur.getBack.setRad((i % 2) ? 256 : 0);
							spreadStringBlur.getEssence().frontAlpha.set(200, 15, 5);
							spreadStringBlur.getEssence().backAlpha.set(150, 0, 1);
						}
					}
					sceneNo = SCENE_ID.END_OPNING;
				}
			} else {
				foreach(spreadStringBlur;spreadStringBlurs) {
					spreadStringBlur.onMove(info.screen);
					if (spreadStringBlur.isEndAlpha()) {
							reloadTelop1(spreadStringBlur);
					}
				}
			}
			break;
			
		case SCENE_ID.END_OPNING:	// セクション
			bool allEnd = true;
			// 全部フェードアウトするまで待つ
			foreach(spreadStringBlur;spreadStringBlurs) {
				spreadStringBlur.onMove(info.screen);
				if (!spreadStringBlur.isEndAlpha()) {
					 allEnd = false;
				}
			}
			if (allEnd) {
				sceneNo = SCENE_ID.SECTION_TELOP;
				shadeDraw.onMove(info.screen);
			}
			break;
		case SCENE_ID.SECTION_TELOP:
			shadeDraw.onMove(info.screen);
			if ( shadeDraw.isEnd() ) {
				jumpScenario();
			}
			break;
			
		default:
			break;
		}
				

		return 0;	
	}
	
	/// 描画処理
	override int onDraw(Object o) {
		info = cast(GameInfo) o;
		
		switch (sceneNo) {
		case SCENE_ID.FADE_IN:
			info.screen.setClearColor(0,0,0);
			info.screen.clear();
			info.screen.blendSrcAlpha();
			info.screen.setColor(255, 255, 255, alpha.get());
			info.screen.blt(imgBackup, 0, 0);
			break;
			
		case SCENE_ID.OPENING:
			info.screen.setClearColor(0,0,0);
			info.screen.clear();
			info.screen.blendSrcAlpha();
			info.screen.setColor(190,190,190);
			foreach(spreadStringBlur;spreadStringBlurs) {
				spreadStringBlur.onDraw(info.screen);
			}
			break;

		case SCENE_ID.END_OPNING:
			info.screen.setClearColor(0,0,0);
			info.screen.clear();
			info.screen.blendSrcAlpha();
			info.screen.setColor(190,190,190);
			foreach(spreadStringBlur;spreadStringBlurs) {
				spreadStringBlur.onDraw(info.screen);
			}
			break;

		case SCENE_ID.SECTION_TELOP:
			info.screen.setClearColor(0,0,0);
			info.screen.clear();
			info.screen.blendSrcAlpha();
			info.screen.setColor(255,255,255);
			shadeDraw.onDraw(info.screen);
			break;

		case SCENE_ID.END:
			info.screen.setClearColor(0,0,0);
			info.screen.clear();
			info.screen.setColor(255,255,255);
			break;
		default:
			break;
		}


		return 0;
	}
	
	int drawRad = 0;
	
	/// タスクが使用したインスタンスを破棄し、ＧＣを起動する
	override void destroy() {
		foreach (spreadStringBlur; spreadStringBlurs) {
			spreadStringBlur.reset();
		}
		foreach(fl; fontLoaders) {
			fl.releaseAll();
		}
		
		Log.print("%s#destroy : destroyed.", super.toString());
	}	
	
	override int task(Object o) {
		return 0;
	}
	
private:
	static const long OPENING_END_TIME = 15_560;
	static const char[] MESSAGE_TELOP1 = "img2\\eyecatch\\telop1.txt";
	static const char[] MESSAGE_TELOP2 = "img2\\eyecatch\\telop2.txt";
	static const char[] MESSAGE_TELOP3 = "img2\\eyecatch\\telop3.txt";
	static const char[] TELOP_CONF1 = "img2\\eyecatch\\conf1.txt";
	static const char[] TELOP_CONF2 = "img2\\eyecatch\\conf2.txt";
	static const char[] TELOP_CONF3 = "img2\\eyecatch\\conf3.txt";

	enum SCENE_ID {FADE_IN,OPENING, END_OPNING, SECTION_TELOP, END};

	static Rand rand;
	
	GameInfo info = null;
	bool init = false;
	SpreadStringBlur[] spreadStringBlurs;
	RootCounterS clearColorCounter;
	RootCounter rotCounter;
	Texture imgBg;
	Texture imgBackup;
	SCENE_ID sceneNo = SCENE_ID.FADE_IN;
	FixTimer timer;
	// 展開描画クラス
	FontLoader[] fontLoaders;
	wchar[][] messages;
	RootCounterS alpha;

	// パラグラフタイトル用描画クラス
	SlideShadeDraw shadeDraw;

	/// テロップ１での文字列リロード設定
	void reloadTelop1(SpreadStringBlur spreadStringBlur) {
		spreadStringBlur.reset();
		// 文字列を設定
		spreadStringBlur.setStringUnicode(messages[rand.get(messages.length)]);
		// yを設定
		spreadStringBlur.setY(50 + rand.get(400));
		spreadStringBlur.setX(150 + rand.get(240));
		// 角度を設定
		drawRad += 14;
		bool reverce = (drawRad % 2 == 0);
		spreadStringBlur.getFront.setRad(reverce ? drawRad + 256 : drawRad);
		spreadStringBlur.getBack.setRad(reverce ? drawRad + 256 : drawRad);
	}
	
	/// シナリオタスクに遷移する
	void jumpScenario() {
		// すべてのスタックを破棄		
		info.gameSceneTransiter.exitScene();
		
		// 強制バックアップを行う
		info.gameSceneTransiter.setTransitType( GameSceneTransiter.C_NO_EFFECT, 1, true );
		info.gameSceneTransiter.callScene(KyojinConst.Task.Task_Scenario);
	}


	/// 初期化処理
	void onInit() {
		if (rand is null) {
			rand = new Rand();
			rand.randomize();
		}
		
		int[] v = info.getData();
		if (v.length > 1) {
			info.selectedStory = v[1];
		}
		
		imgBackup = info.gameSceneTransiter.getBackupTexture();
		alpha = new RootCounterS();
		alpha.set(255, 0, 1);
		
		switch (info.selectedStory) {
		case KyojinConst.ScenarioID.KYOJIN01:
			messages = loadMessage(cast(char[]) MESSAGE_TELOP1);
			shadeDraw = SlideShadeDraw.createInstance(cast(char[]) TELOP_CONF1);
			break;
		case KyojinConst.ScenarioID.KYOJIN02:
			messages = loadMessage(cast(char[]) MESSAGE_TELOP2);
			shadeDraw = SlideShadeDraw.createInstance(cast(char[]) TELOP_CONF2);
			break;
		case KyojinConst.ScenarioID.KYOJIN03:
			messages = loadMessage(cast(char[]) MESSAGE_TELOP3);
			shadeDraw = SlideShadeDraw.createInstance(cast(char[]) TELOP_CONF3);
			break;
		}
		

		// フォントのロード
		FontRepository frontRep = createFontRepository(cast(char[]) "./fonts/FS-Mincho.ttf", 40, 0, 150);
		FontRepository backRep = createFontRepository(cast(char[]) "./fonts/FS-Mincho.ttf", 10, 0, 150);

		// フォントリポジトリを埋めておく
		for (int i = 0; i < 150; ++i) {
			frontRep.getTexture(messages[rand.get(messages.length)]);
			backRep.getTexture(messages[rand.get(messages.length)]);
		}

		// インスタンス生成
		spreadStringBlurs ~= createSpread1(frontRep, backRep);
		spreadStringBlurs ~= createSpread2(frontRep, backRep);
		spreadStringBlurs ~= createSpread3(frontRep, backRep);
	
		// 描画スタートタイミングをずらす	
		for (int i = 1; i < spreadStringBlurs.length; ++i) {
			spreadStringBlurs[i].setStartWait(333 * i);
		}
		
		// クリアカラーカウンター
		clearColorCounter = new RootCounterS();
		clearColorCounter.set(255, 255, 1);
		
		// 回転カウンター
		rotCounter = new RootCounter();
		rotCounter.set(0, 512, -5);

		imgBg = new Texture();
		imgBg.load(cast(char[]) "img2/eyecatch/bg.png");
	
		timer = new FixTimer();
		timer.reset();
		
	}
	
	
	SpreadStringBlur createSpread1(FontRepository frontRep, FontRepository backRep) {
		int rad = 0; //480;
		int step = 256;
		int startWidth = -30;
		int endWidth = 20;
		// エッセンス生成
		auto essence = new SpreadStringBlur.EssencePram();
		essence.frontFont = frontRep;
		essence.backFont = backRep;
		essence.spreadStartWidth = startWidth;
		essence.spreadEndWidth = endWidth;
		essence.spreadSpeed = step;
		essence.rad = rad;
		essence.frontRate = 2.0f;
		essence.backRate = 8.0f;
		{
			auto alphaCounter = new RootCounterS();
			alphaCounter.set(200, 15, 26);
			essence.frontAlpha = alphaCounter;
		}
		{
			auto alphaCounter = new RootCounterS();
			alphaCounter.set(150, 15, 5);
			essence.backAlpha = alphaCounter;
		}
		auto instance = new SpreadStringBlur(essence);
		instance.setStringUnicode(messages[rand.get(messages.length)]);
		instance.setPosXY(320,100);
		return instance;
	}

	SpreadStringBlur createSpread2(FontRepository frontRep, FontRepository backRep) {
		int rad = 256;
		int step = 256;
		int startWidth = -30;
		int endWidth = 20;
		// エッセンス生成
		auto essence = new SpreadStringBlur.EssencePram();
		essence.frontFont = frontRep;
		essence.backFont = backRep;
		essence.spreadStartWidth = startWidth;
		essence.spreadEndWidth = endWidth;
		essence.spreadSpeed = step;
		essence.rad = rad;
		essence.frontRate = 2.0f;
		essence.backRate = 8.0f;
		{
			auto alphaCounter = new RootCounterS();
			alphaCounter.set(200, 15, 26);
			essence.frontAlpha = alphaCounter;
		}
		{
			auto alphaCounter = new RootCounterS();
			alphaCounter.set(150, 15, 5);
			essence.backAlpha = alphaCounter;
		}
		auto instance = new SpreadStringBlur(essence);
		instance.setStringUnicode(messages[rand.get(messages.length)]);
		instance.setPosXY(320,150);
		return instance;
	}

	SpreadStringBlur createSpread3(FontRepository frontRep, FontRepository backRep) {
		int rad = 0;
		int step = 256;
		int startWidth = -30;
		int endWidth = 20;
		// エッセンス生成
		auto essence = new SpreadStringBlur.EssencePram();
		essence.frontFont = frontRep;
		essence.backFont = backRep;
		essence.spreadStartWidth = startWidth;
		essence.spreadEndWidth = endWidth;
		essence.spreadSpeed = step;
		essence.rad = rad;
		essence.frontRate = 2.0f;
		essence.backRate = 8.0f;
		{
			auto alphaCounter = new RootCounterS();
			alphaCounter.set(200, 15, 26);
			essence.frontAlpha = alphaCounter;
		}
		{
			auto alphaCounter = new RootCounterS();
			alphaCounter.set(150, 15, 5);
			essence.backAlpha = alphaCounter;
		}
		auto instance = new SpreadStringBlur(essence);
		instance.setStringUnicode(messages[rand.get(messages.length)]);
		instance.setPosXY(320,300);
		return instance;
	}

	FontRepository createFontRepository(char[] fontFilename, int fontSize, int fontIndex, int max) {
		FontLoader fontLoader = SpreadString.createFontLoader(fontFilename, fontSize, fontIndex);
		fontLoaders ~= fontLoader;
		return SpreadString.setupFontRepository(fontLoader, 0, max);
	}


	wchar[][] loadMessage(char[] filename, int maxLength = 15) {
		char[] strText = cast(char[]) FileSys.read(filename);
		char[] normalText = cast(char[]) std.regexp.sub(strText, "s/<.*?>//g", "");
		wchar[][] result;
		std.stream.MemoryStream m = new std.stream.MemoryStream(cast(ubyte[]) normalText);
		while (!m.eof) {
			wchar[] wc = .toWCS(cast(char[]) m.readLine());
			if (wc is null) {
				continue;
			}
			if (wc.length > maxLength) {
				result ~= wc[0..maxLength];
			} else {
				result ~= wc;
			}
		}
		return result;
	}

}
