module kyojintati4d.tasklogo;

private import SDL;

private import std.stream;

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

private import kyojintati4d.myapp;
private import kyojintati4d.gameinfo;
private import yamalib.math.spline;

private import yamalib.counterfsp;
private import yamalib.log.log;



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

	/// 移動の処理を行います
	override int onMove(Object o) {
		try {
			info = cast(GameInfo)o;
			
			if (!m_init) {
				onInit();
				m_init = true;
			}
	
			switch (m_process) {
			case PROCESS.K2C_LOGO:
				m_alpha.inc();
				
				if ( m_alpha.isEnd() ) {
					m_waitCount++;
					if ( WAIT_TIME <= m_waitCount ) {
						m_waitCount = 0;
						m_process = PROCESS.CAUTION;
						m_alpha.reset();
						info.screen.setClearColor(0,0,0);
					}
				}
				
				break;
			case PROCESS.CAUTION:
				m_alpha.inc();
				
				if ( m_alpha.isEnd() ) {
					++m_waitCount;
					if ( WAIT_TIME_CAUTION <= m_waitCount ) {
						m_waitCount = 0;
						m_process = PROCESS.FADE_OUT;
						m_alpha.set(255, 0, 2);
					}
				}
				
				break;
			case PROCESS.FADE_OUT:
				m_alpha.inc();
				if ( m_alpha.isEnd() ) {
					info.gameSceneTransiter.jumpScene(KyojinConst.Task.Task_Title);
					// マウスカーソルを戻す
					info.mouse.show();
					return -1;
				}
				break;
			default:
				assert(false);
			}
			
			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;
			// 非0を返せば、このタスクは消される。
			
			info.screen.clear();
			
			switch (m_process) {
			case PROCESS.K2C_LOGO:
				info.screen.setColor(255,255,255,m_alpha.get());
				info.screen.blt(m_imgK2c, 0, 0);
				break;
			case PROCESS.CAUTION:
				info.screen.setColor(255,255,255,255 - m_alpha.get());
				info.screen.blt(m_imgK2c, 0, 0);
				info.screen.setColor(255,255,255,m_alpha.get());
				info.screen.blt(m_imgCaution, 0, 0);
				break;
			case PROCESS.FADE_OUT:
				info.screen.setColor(255,255,255,m_alpha.get());
				info.screen.blt(m_imgCaution, 0, 0);
				break;
			default:
				assert(false);
			}
			
			
			return 0;
		} catch (Exception e) {
			Log.printFatal("RuntimeException %s#onDraw : [%s] [%s]", 
				super.toString(), e.toString(), e.msg);
			throw e;
		}
	}
	
	/// タスク破棄
	override void destroy() {
		// ここでGC;
		Texture.safeRelease(m_imgK2c);
		Texture.safeRelease(m_imgCaution);
		
		m_alpha = cast(RootCounterS) null;
		Log.print("%s#destroy : destroyed.", super.toString());
	}

	/// onMove+onDraw
	override int task(Object o) {
		return 0;
	}
	
	/// コンストラクタ
	this() {
		m_process = PROCESS.K2C_LOGO;
	}
	
private:
	enum PROCESS : int {K2C_LOGO,CAUTION,FADE_OUT};
	static const uint WAIT_TIME = 60;
	static const uint WAIT_TIME_CAUTION = 120;

	/// 初期化処理
	void onInit() {
		// メモリー状況をプリント
		GameInfo.printMemoryState();
		m_imgK2c = new Texture();
		m_imgK2c.load(cast(char[]) "img/logo/logo01.png");
		m_imgCaution = new Texture();
		m_imgCaution.load(cast(char[]) "img/logo/logo02.png");
		m_alpha = new RootCounterS();
		m_alpha.set(0,255,1);
		
		info.screen.setClearColor(255,255,255);
	}

private:
	GameInfo info;
	bool m_init;
	Texture m_imgK2c;
	Texture m_imgCaution;
	RootCounterS m_alpha;
	uint m_waitCount;
	PROCESS m_process;
}

/+

/// ロゴタスクで使用する座標クラス
private class POINT {
	this() {}
	this(int x,int y) {
		this.x = x;
		this.y = y;
	}

	int x;
	int y;
}

/// 残像クラス
private class Afterimage {

	/// コンストラクタ
	this() {
		alpha = new RootCounterS(64,0,fadeRate);
	}

	/// コンストラクタ
	this(Texture t_,int x_,int y_) {
		this();
		setXY(x_,y_);
		setTexture(t_);
	}

	/// 描画位置の設定
	void setXY(int x_,int y_) {
		x = x_;
		y = y_;
	}

	/// 描画テクスチャの設定
	void setTexture(Texture t_) {
		t = t_;
	}

	/// フェードアウト速度の設定
	void setFadeRate(int rate) {
		fadeRate = rate;
		alpha.set(255,0,fadeRate);
	}

	/// 描画処理
	void onDraw(Screen screen) {
		if (alpha.isEnd()) return;

		alpha++;
		screen.setColor(255,255,255,alpha.get());
		screen.blt(t,x,y);
		screen.resetColor();
	}

private:
	Texture t;
	int x,y;
	RootCounterS alpha;

	int fadeRate = 6;
}

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

	/// コンストラクタ
	this() {
		rand = new Rand();
		rand.randomize();
		counter = new RootCounterS;
	}

	/// 移動の処理を行います
	override int onMove(Object o) {
		try {
			info = cast(GameInfo)o;
			
			info.mouse.update();
	
			if( !moveInit ) {
				onInit();
				// マウスカーソルを消す
				info.mouse.hide();
				moveInit = true;
			}
			
			switch( state ) {
	
			// サウンド再生
			case 0:
				{
					s_on.play();
					state++;
				}
				break;
	
			// Kイン
			case 1:
				{
					addfade += (4 * FSP_RATE);
					if(addfade>255) {
						state++;
						addfade = 0;
						s_on.stop();
						s_on.play();
					}
				}
				break;
	
			// 2イン
			case 2:
				{
					addfade += (4 * FSP_RATE);
					if(addfade>255) {
						state++;
						addfade = 0;
						s_on.stop();
						s_on.play();
					}
				}
				break;
	
			// Cイン
			case 3:
				{
					addfade += (4 * FSP_RATE);
					if(addfade>255) {
						state++;
						addfade = 0;
					}
				}
				break;
	
			// 移動～
			case 4:
				{
					vPtQ ~= vPt[counter.get()];
	
					counter++;
					if( counter.isEnd() ) {
						lastpoint = counter.get();
						counter.set(0,int.max,1);
						state++;
					}
	                afterK ~= new Afterimage(t_k,vPtQ[length-DELAY].x,		vPtQ[length-DELAY].y);
	                after2 ~= new Afterimage(t_2,vPtQ[length-DELAY*2].x+55,	vPtQ[length-DELAY*2].y);
	                afterC ~= new Afterimage(t_c,vPtQ[length-DELAY*3].x+110,vPtQ[length-DELAY*3].y);
				}
				break;
	
			// 整列
			case 5:
				{
					vPtQ ~= vPt[length-1];
	                afterK ~= new Afterimage(t_k,vPtQ[length-DELAY].x,		vPtQ[length-DELAY].y);
	                after2 ~= new Afterimage(t_2,vPtQ[length-DELAY*2].x+55,	vPtQ[length-DELAY*2].y);
	                afterC ~= new Afterimage(t_c,vPtQ[length-DELAY*3].x+110,vPtQ[length-DELAY*3].y);
	
					counter++;
					if( counter.get() > DELAY*3+20 ) {
						state++;
						addfade = 0;
						s_in.play();
					}
				}
				break;
	
			// 背景ＩＮ
			case 6:
				{
					addfade += (2 * FSP_RATE);
					if( addfade > 255 ) {
						state++;
						counter.set(0,255,1);
						s_attention.play();
					}
	
				}
				break;
	
			// 維持
			case 7:
				{
					counter++;
					if( counter.isEnd() ) {
						state++;
						addfade = 255;
	
						// タイトルＢＧＭの再生
						info.bgmloader.get(0).setLoop(-1);
						info.bgmloader.get(0).setVolume(20);
						info.bgmloader.get(0).play();
	
					}
				}
				break;
	
			// 終了
			case 8:
				{
					addfade -= (4 * FSP_RATE);
					if(addfade <= 0) {
						addfade = 0;
						destroy();
						
						info.gameSceneTransiter.jumpScene(KyojinConst.Task.Task_Title);
						// マウスカーソルを戻す
						info.mouse.show();
//						info.gameSceneTransiter.jumpScene(KyojinConst.Task.Task_Demo);
						return -1;
					}
				}
				break;
			default :
				assert(false);
			}		
			
			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( !drawInit ) {
				drawInit = true;
				info.screen.setClearColor(255,255,255);
			}
	
			// 開始～
			info.screen.clear();
	
			switch( state ) {
	
			// サウンド再生
			case 0:
				{
					s_on.play();
					state++;
				}
				break;
	
			// Kイン
			case 1:
				{
					info.screen.setColor(255,255,255,addfade);
					info.screen.blendSrcAlpha();
					info.screen.blt(t_k,vPt[0].x,vPt[0].y);
				}
				break;
	
			// 2イン
			case 2:
				{
					info.screen.setColor(255,255,255,255);
					info.screen.blt(t_k,vPt[0].x,vPt[0].y);
	
					info.screen.setColor(255,255,255,addfade);
					info.screen.blendSrcAlpha();
					info.screen.blt(t_2,vPt[0].x+55,vPt[0].y);
				}
				break;
	
			// Cイン
			case 3:
				{
					info.screen.setColor(255,255,255,255);
					info.screen.blt(t_k,vPt[0].x,vPt[0].y);
					info.screen.blt(t_2,vPt[0].x+55,vPt[0].y);
	
					info.screen.setColor(255,255,255,addfade);
					info.screen.blendSrcAlpha();
					info.screen.blt(t_c,vPt[0].x+110,vPt[0].y);
				}
				break;
	
			// 移動～
			case 4:
				{
					info.screen.blt(t_c,vPtQ[length-DELAY*3].x+110,	vPtQ[length-DELAY*3].y);
					info.screen.blt(t_2,vPtQ[length-DELAY*2].x+55,	vPtQ[length-DELAY*2].y);
					info.screen.blt(t_k,vPtQ[length-DELAY].x,		vPtQ[length-DELAY].y);
	
					for(int i=afterC.length-1; 0<=i; --i) {
						afterC[i].onDraw(info.screen);
					}
					for(int i=after2.length-1; 0<=i; --i) {
						after2[i].onDraw(info.screen);
					}
					for(int i=afterK.length-1; 0<=i; --i) {
						afterK[i].onDraw(info.screen);
					}
				}
				break;
	
			// 整列
			case 5:
				{
					info.screen.blt(t_c,vPtQ[length-DELAY*3].x+110,	vPtQ[length-DELAY*3].y);
					info.screen.blt(t_2,vPtQ[length-DELAY*2].x+55,	vPtQ[length-DELAY*2].y);
					info.screen.blt(t_k,vPtQ[length-DELAY].x,		vPtQ[length-DELAY].y);
	
					for(int i=afterC.length-1; 0<=i; --i) {
						afterC[i].onDraw(info.screen);
					}
					for(int i=after2.length-1; 0<=i; --i) {
						after2[i].onDraw(info.screen);
					}
					for(int i=afterK.length-1; 0<=i; --i) {
						afterK[i].onDraw(info.screen);
					}
	
				}
				break;
	
			// 背景ＩＮ
			case 6:
				{
					info.screen.setColor(255,255,255,addfade);
					info.screen.blendSrcAlpha();
					info.screen.blt(t_bg,0,0);
	
					info.screen.resetColor();
					info.screen.blt(t_c,vPtQ[length-DELAY*3].x+110,vPtQ[length-DELAY*3].y);
					info.screen.blt(t_2,vPtQ[length-DELAY*2].x+55, vPtQ[length-DELAY*2].y);
					info.screen.blt(t_k,vPtQ[length-DELAY].x,		vPtQ[length-DELAY].y);
				}
				break;
	
			// 維持
			case 7:
				{
					info.screen.blt(t_bg,0,0);
					info.screen.blt(t_c,vPtQ[length-DELAY*2].x+110,vPtQ[length-DELAY*2].y);
					info.screen.blt(t_2,vPtQ[length-DELAY].x+55, 	vPtQ[length-DELAY].y);
					info.screen.blt(t_k,vPtQ[length-1].x,			vPtQ[length-1].y);
				}
				break;
	
			case 8:
				{
					info.screen.setColor(255,255,255,addfade);
					info.screen.blt(t_bg,0,0);
					info.screen.blt(t_c,vPtQ[length-DELAY*3].x+110,vPtQ[length-DELAY*3].y);
					info.screen.blt(t_2,vPtQ[length-DELAY*2].x+55, vPtQ[length-DELAY*2].y);
					info.screen.blt(t_k,vPtQ[length-DELAY].x,		vPtQ[length-DELAY].y);
				}
				break;
			default:
				assert(false);
	
			}
	
			// 非0を返せば、このタスクは消される。
			return 0;
		} catch (Exception e) {
			Log.printFatal("RuntimeException %s#onDraw : [%s] [%s]", 
				super.toString(), e.toString(), e.msg);
			throw e;
		}
	}
	
	/// タスク破棄
	override void destroy() {
		// ここでGC;
		Texture.safeRelease(t_bg);
		Texture.safeRelease(t_k);
		Texture.safeRelease(t_2);
		Texture.safeRelease(t_c);
		
		counter = null;
		vPt = null;
		vPtQ = null;
		afterK = null;
		after2 = null;
		afterC = null;
		Sound.safeRelease(s_on);
		Sound.safeRelease(s_in);
		Sound.safeRelease(s_attention);
		
		timer = null;
		rand = null;

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

	/// onMove+onDraw
	override int task(Object o) {
		return 0;
	}
	
private:
	/// 初期化処理
	void onInit() {
		// メモリー状況をプリント
		GameInfo.printMemoryState();

		y4d_result res;
		
		FSP_RATE = KyojinConst.C_FSP_DEFAULT / KyojinConst.C_FSP_NOW;
		
		Log.print("LogTask - SpeedRate %d", FSP_RATE);

		t_bg = new Texture;
		t_k = new Texture;
		t_2 = new Texture;
		t_c = new Texture;

		res = t_bg.load(FileSys.makeFullName("img/logo/logo_back.png"));

		t_k.load(FileSys.makeFullName("img/logo/logo_k.png"));
		t_2.load(FileSys.makeFullName("img/logo/logo_2.png"));
		t_c.load(FileSys.makeFullName("img/logo/logo_c.png"));

		s_on = new Sound;
		s_in = new Sound;
		s_attention = new Sound;
		s_on.load(FileSys.makeFullName("snd/logo_on.ogg"),0);
		s_in.load(FileSys.makeFullName("snd/logo_in.ogg"),0);
		s_attention.load(FileSys.makeFullName("snd/attention.ogg"),0);

		PointInt[] point;
		loadPoint(point);
		Point[] ptsp = BSpline.calcBSpline( point, 2);

		// Ｂスプラインは先頭サンプルがないとへんな値がはいるから適当に捨てる
		for (int i = 10; i < ptsp.length; ++i) {
			vPt ~= new POINT(cast(int) ptsp[i].x, cast(int) ptsp[i].y);
		}
		delete ptsp;
		
		for(int i; i < DELAY*3; ++i) {
			vPtQ ~= vPt[0];
		}

		counter.set(0,vPt.length, DELAY);
	}
	
	/// 移動点をファイルから読み込む
	private static void loadPoint(inout PointInt[] ptResult) {
		std.stream.MemoryStream m = 
			new std.stream.MemoryStream( cast(char[]) FileSys.read("img/logo/point.txt") );
		LineParser lp = new LineParser();
		
		int count = 0;
		while (!m.eof) {
			char[] linebuf = m.readLine();
			if ( linebuf is null ) {
				continue;
			}
			
			lp.setLine(linebuf);
			while ( !lp.isEnd() ) {
				PointInt* pt = new PointInt();
				
				pt.x = cast(int) lp.getNum(int.min);
				pt.y = cast(int) lp.getNum(int.min);
				
				ptResult ~= *pt;
			}
		}
		
		m.close();
		
		return ptResult;
	}

private:
	/// 現在のＦＳＰと６０との比率
	static int FSP_RATE = 1;

	GameInfo info;

	bool moveInit;
	bool drawInit;

	FixTimer timer;
	Rand rand;
	RootCounterS counter;

	int lastpoint;

	byte state;
	int faderate;
	int addfade;
	int addRate;

	Afterimage[] afterK;
	Afterimage[] after2;
	Afterimage[] afterC;

	Texture t_bg;
	Texture t_k;
	Texture t_2;
	Texture t_c;

	Sound s_on;
	Sound s_in;
	Sound s_attention;

	POINT[] vPt;
	POINT[] vPtQ;

	static const int DELAY = 10 / 2;
}
+/