module yamalib.draw.dizzytextdraw;

private import y4d;
private import yamalib.counterfsp;

/// ランダムテキスト表示
/**
	指定範囲を文字で埋め尽くし変わっていきます
*/
class DizzyTextDraw {

	/// コンストラクタ
	this() {
		// 文字貯蔵庫の生成
		fr = new FontRepository;
		fr.setMax(300);		// とりあえず 300 ぐらいか？

		rand = new Rand();
		rand.randomize();

		alpha = new RootCounterS;
		alpha.set(255,255,0);	// 無効

		// 手動で読み込み
		alphabet_str = cast(wchar[]) "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
		number_str = cast(wchar[]) "0123456789";
		mark_str = cast(wchar[]) ":;<=>?@[]^_!\"#$%&'()*+,-./`{|}";
		hankana_str = cast(wchar[]) "ｦｧｨｩｪｫｬｭｮｯｱｲｳｴｵｶｷｸｹｺｻｼｽｾｿﾀﾁﾂﾃﾄﾅﾆﾇﾈﾉﾊﾋﾌﾍﾎﾏﾐﾑﾒﾓﾔﾕﾖﾗﾘﾙﾚﾛﾜﾝ";

		enable_str ~= alphabet_str;
		enable_str ~= number_str;
		enable_str ~= mark_str;
		enable_str ~= hankana_str;

		blend = true;

		// 使用する文字
		hankana = true;
		mark = true;
		number = true;

	}

	void setFadeIn(int step) {
		int start = 0;
		if (!alpha.isEnd()) {
			start = alpha.get();
		}
		alpha.set(start,255,step);
	}

	void setFadeOut(int step) {
		int start = 255;
		if (!alpha.isEnd()) {
			start = alpha.get();
		}
		alpha.set(start,0,step);
	}

	bool isFade() { 
		return cast(bool) !alpha.isEnd(); 
	}

	void useHankana(bool b) { hankana = b; }
	void useMark(bool b) { mark = b; }
	void useNumber(bool b) { number = b; }
	void setColor(byte r,byte g,byte b) {
		this.r = r; this.g = g; this.b = b;
	}
	void setBlend(bool b) { blend = b; }

	/// 維持するフレーム数　大きいほど更新は遅い
	void setSpeed(uint i) {
		if (i==0) i=1;
		speed = i;
	}

	/// 表示する矩形 nullで画面全体
	void setDrawRect(Rect* rc) {
		if (rc == null) {
			drawrect = null;
		} else {
			drawrect = rc;
		}
	}

	/// ロードされたFontLoaderのセット no:使用する文字
	/**
		このとき文字幅と高さを計算して、FontRepositoryを構築する
	*/
	void setFontLoader(FontLoader loader,int no) {
		fr.setLoader(loader,no);

		// まとめた文字を生成し貯蔵庫に貯める
		tv = fr.getTexture(enable_str);

		// 平均文字幅と高さ
		fwidth = cast(int)(tv.getWidth() / enable_str.length);
		fheight = cast(int)tv.getHeight();
	}

	/// 毎回呼び出すナリ
	void onDraw(Screen screen) {
		int index;
		int sx,sy;
		alpha++;
		// なんぢゃそりゃ...
		if (alpha.get()<=0) return;

		if (drawrect != null) {
			sx = cast(int)(drawrect.getWidth() / fwidth);
			sy = cast(int)(drawrect.getHeight() / fheight);
		} else {
			sx = screen.getWidth() / fwidth;
			sy = screen.getHeight() / fheight;
			posx = posy = 0;
		}

		int i,j;
		wchar[] ww;
		// 描画するランダム文字を作って描画する
		screen.setColor(73,79,179,alpha.get());
		screen.blendSrcAlpha();
		if (flamecounter == speed) {
			rand_str = null;
			for (i=0; i<sy; ++i) {
				for (j=0; j<sx; ++j) {
					ww ~= getRandChara();
				}
				// 描画
				tv = fr.getTexture(ww);
				screen.blt(tv,posx,posy+i*fheight);

				rand_str ~= ww;
				ww = null;
			}
			flamecounter = 0;
		} else {
			for (i=0; i<rand_str.length; ++i) {
				tv = fr.getTexture(rand_str[i]);
				screen.blt(tv,posx,posy+i*fheight);
			}

		}
		screen.resetColor();
		flamecounter++;
	}

private:
	/// 設定条件より一文字文字を返す
	wchar getRandChara() {
		// ABC:26,123:10,mark:30,ﾊﾝｶﾅ:55
		// 0          36      66
		int charnum,index,last;

		// 描画できる文字の数
		charnum += alphabet_str.length;
		if (number) charnum += number_str.length;
		if (mark) charnum += mark_str.length;
		if (hankana) charnum += hankana_str.length;

		index = rand.get(charnum);

		last = alphabet_str.length;
		if (index > last) {
			last += number_str.length;
			if (number) {
				if (index > last) {
					last += mark_str.length;
					if (mark) {
						if (index > last) {
							if (!hankana) {
								// error
								return ' ';
							}
						}
					} else {
						index += mark_str.length;
					}
				}
			} else {
				index += number_str.length;
				last += mark_str.length;
				if (mark) {
					if (last > index) {
						if (!hankana) {
							// error
							return ' ';
						}
					}
				} else {
					index += mark_str.length;
				}
			}
		}

		return enable_str[index];
	}

protected:

	// Unicodeの文字コードなんてしらべてらんネ
	wchar[] hankana_str;
	wchar[] mark_str;
	wchar[] number_str;
	wchar[] alphabet_str;
	wchar[] enable_str;	//!< 使用する文字すべてを連結した文字列

	wchar[][] rand_str;	//!< 描画中の文字列配列

	FontRepository fr;	// 文字貯蔵庫
	Rand rand;
	TextureVector tv;	// 文字列を受け取る

	Rect* drawrect;		//!< 表示する矩形

	RootCounterS alpha;

	int posx,posy;		//!< 描画開始位置
	bool blend;
	bool hankana,mark,number;	//!< 使用する文字
	byte r,g,b;		//!< 描画色
	int fwidth,fheight;	//!< フォントの幅と高さ
	uint speed;		//!< 変更のタイミング
	uint flamecounter;	//!< フレームカウンタ
}
