module y4d_draw.surfacefontrepository;

public import y4d_draw.fontloader;
public import y4d_draw.surface;
//public import y4d_draw.surfacevector;
public import y4d_draw.font;

///	文字テクスチャーのキャッシュ用クラス
/**

<PRE>
	FontLoader loader = new FontLoader;
	loader.loadDefRW("msmincho.ttc , 0 , 50 , 0\n");

	FontRepository fr = new FontRepository;
	fr.setLoader(loader,0);
	fr.setMax(100);

	//	メインループにて

		SurfaceVector fonttv = fr.getSurface("この文字列描画どや！");
		//	↑font repositoryから取り出すので、超ハヤー（ﾟДﾟ）

//		fonttv.setSurface(
//			loader.get(0).drawBlendedUnicode("この文字列描画どや！"));
		//	↑毎フレーム文字列フォントを生成するとすごく負荷がかかる

		screen.setColor(255,0,0);

		screen.blt(fonttv,30,100);
		screen.resetColor();

</PRE>

*/
class SurfaceFontRepository {

	///	キャッシュする文字の数
	/**
		一画面に描画しうる最大文字数より大きな値にしておかないと
		描画している最中に解放されてしまいます。

		300ぐらいが適当だと思いますが、文字をたくさん描画する場合は
		その数に合わせて調整されることをお勧めします。
	*/
	void	setMax(int max) {
		fonts = new Info[max];
		sp = 0;
	}

	///	ひとつの文字に対する情報
	struct Info {
		wchar w;			//!< キャッシュしている文字
		FontLoader loader;	//!< 使用しているフォントローダー
		int   no;			//!< フォントナンバー(FontLoaderのナンバー)
		Surface surface;	//!< そのテクスチャ(null = 未生成)
		ulong time;			//!< このSurfaceを参照された最後の時間
	}

	///	フォントローダーとその使用するナンバーを指定設定する
	/**
		以降、getSurfaceでは、このフォントが読み込まれる。
	*/
	void setLoader(FontLoader loader_,int no_){
		loader = loader_;
		no	   = no_;
	}

	///	文字に対応するフォントを取得
	/**
		キャッシュから文字をかき集めるので、ここでかき集めた
		文字列(テクスチャ)はいずれ解放されるので、使用するのは
		その描画フレームで限りにすること。
	*/
	Surface getSurface(wchar w)
	{
		if (!loader) return null; // うんこーヽ(`Д´)ノ

		//	探してみる
		Info * info;
		for(int i=0;i<sp;++i){
			info = &(fonts[i]);
			if ((info.w == w) && (info.loader is loader) && (info.no == no)){
				//	みっけ！
				goto Exit;
			}
		}
		//　見つからなかったので生成してみる
		if (sp==fonts.length){
			//	場所が空いてないので、一番最後に参照された
			//	オブジェクトを解放する
			ulong t = ulong.max;
			int n;
			for(int i=0;i<sp;++i){
				if (fonts[i].time < t) {
					info = &fonts[i]; t = info.time;
				}
			}
			Surface tt = info.surface;
			if (tt) tt.release(); // 一応解放しておく
		} else {
			info = &fonts[sp++];
		}
		info.w = w;
		info.loader = loader;
		info.no = no;
		Surface surface = new Surface;

		wchar[] ww; ww~=w;
		Font font = loader.get(no);
		if (font) {
			surface = font.drawBlendedUnicode(ww);
		} else {
			// なんやー。読み込まれへんかったわ
		}
		info.surface = surface;
Exit:;
		//	これ参照したので、時刻をずらしておく。
		info.time = ++timer;
		return info.surface;
	}
/*
	/// 文字列に対する文字ベクタを取得
	SurfaceVector getSurface(wchar[] str)
	{
		if (!loader) return null; // うんこーヽ(`Д´)ノ

		SurfaceVector tv = new SurfaceVector;
		foreach(wchar w;str){
			Surface surface = getSurface(w);
			tv.add(surface,cast(int)tv.getWidth(),0);
			//	右に連結していく
		}
		tv.update();	// これ呼び出しておかないと
						//	情報が更新されないんだな(´Д`)
		return tv;
	}
*/
	///	保持しているフォントを解放する
	void release() {
		if (fonts) {
			//	明示的に解放しておくか..
			for(int i=0;i<sp;++i) {
				Surface t = fonts[i].surface;
				if (t) t.release();
			}
			fonts = null;
			sp = 0;
		}
	}
	
	/// デバッグ
	void debugPrint() {
		foreach ( int i, inout Info info; fonts ) {
			if ( info.surface )
				printf("%d: %c, width %f, height %f\n", i,info.w, info.surface.getWidth(), info.surface.getHeight());
			else 
				printf("no surface\n");
		}
	}

private:
	Info[]	fonts;		//	使用しているフォントキャッシュ
	int			sp;		//	ここまで使用している fonts[sp]は含まない。
	FontLoader loader;	//	読み込み
	int		no;			//	選択されているフォントナンバー
	ulong	timer;		//	時刻
}

