module yamalib.draw.textdraw;

private import std.ctype; // tolower

private import y4d_draw.drawbase;
private import ytl.vector;
private import ytl.y4d_result;
private import ytl.exception;
private import yamalib.log.log;

/** 
	シナリオデータモデル
	yaneSDK2ndから持ってきたクラス
 */
class TextDrawContext {
public:

	/// コンストラクタ
	this() {
		baseSize	= 28;
		fontSize	= baseSize;
		bold		= false;
		italic	= false;
		underLine= false;
		strikeOut= false;
		width	= 530;
		blankHeight	= 2;						//	行間
		blankHeight2 = baseSize+blankHeight;	//	空行高さ
		lineNo	= 1;
		align1	= 0;
		align2	= 0;
		hInterval= 4; // 文字と文字との間隔
		pos = 0;
		viewWidth = 640;
	}

	int		viewWidth;		//	画面サイズ
	int		width;			//	最大で表示する横幅
	int		blankHeight;	//	行間
	int		blankHeight2;	//	空行の高さ
	int		hInterval;		//	文字と文字との間隔
	Color4ub rgbColorBk;		//	バックの文字の色(ディフォルトではCLR_INVALIDなので描画できない)

	int		baseSize;		//	基準となるフォントサイズ
	//		⇒これを設定するときは、直接変更せず、SetBaseFontSizeを使うこと
								//	font +1は↑の1.5倍。+2は2倍。+3は3倍。+4は4倍。
								//	font -1は↑の1/1.5倍。-2は1/2倍。-3は1/3倍。-4は1/4倍。

	//	文脈(タグ)によって自動的に設定される値
	int		fontNo;			//	フォントナンバー
	int		fontSize;		//	フォントサイズ
	Color4ub rgbColor;		//	文字の色

	//	<FONT>タグのネストのためにvectorです＾＾(stackでもいいけど)
	vector!(int)	fontNoOld;		//	</font>で戻すべきフォントナンバー
	vector!(int)	fontSizeOld;	//	</font>で戻すべきフォントサイズ
	vector!(Color4ub) rgbColorOld;		//	</font>で戻すべき文字色

	bool	bold;			//	太字
	bool	italic;			//	イタリック体
	bool	underLine;		//	アンダーライン
	bool	strikeOut;		//	取り消し線
	int		align1;			//	0:左寄せ(通常) 1:センター 2:右寄せ
	int		align2;			//	0:下寄せ(通常) 1:センター 2:上寄せ
	int		lineNo;			//	ラインナンバー

	//////////////////////////////////////////////////
	//	ユーザーが事前に設定すべき値

 	//	ベースフォントサイズ
	void	setBaseFontSize(int fontSize_) {
		baseSize	= fontSize_;
		fontSize	= baseSize;
		blankHeight2 = fontSize+blankHeight;	//	空行高さ
	}

	/// シナリオ全体の文字列を設定
	void	setText(wchar[] text) {
		str = text;
		pos = 0;
	}

	/// <HR> までの文字列を返す
	wchar[] getNextText() {
		
		if (backText) {
			backText = false;
			if ( pos != 0 ) {
				pos += 3;
			}
		}
		
		int startpos0 = pos;
		posOld = pos;
		
		if (pos >= str.length) return null;

		do {
CONTINUE:;
			wchar c = str[pos++];

			if (c=='<') {
				//	タグの取得
				//	前方へ '>'をサーチ
				int startpos = pos;
				while (true) {

					if (pos >= str.length) {
						throw new y4d_error(this,cast(char[]) "タグが閉じられていない");
					}

					wchar wc = str[pos];
					if (wc=='>') {
						wchar[] tag = str[startpos..pos];
						if (tag == "HR" || tag == "hr") {
							wchar[] ww = str[startpos0..++pos];
							return ww;
						} else {
							goto CONTINUE;
						}
					}
					pos++;
				}
			}

		} while (pos < str.length);
				
		return str[startpos0..pos];
	}
	
	/// 前の<HR> までの文字列を返す
	wchar[] getPreText() {
		
		if ( pos < 0 ) {
			// EOFまで達している
			pos = 0;
		}

		if ( !backText ) {
			getPrevHRPos();
		}

		if (pos == 0) return null;

		int endpos0 = pos;
		posOld = pos;
		
		do {
CONTINUE:;
			wchar c = str[pos--];

			if (c=='>') {
				//	タグの取得
				//	前方へ '>'をサーチ
				int tailpos = pos;
				while (true) {

					if (pos < 0) {
						throw new y4d_error(this,cast(char[]) "タグが閉じられていない");
					}

					wchar wc = str[pos];
					if (wc=='<') {
						wchar[] tag = str[pos+1..tailpos+1];

						if (tag == "HR" || tag == "hr") {
							backText = true;
							wchar[] ww = str[tailpos+2..endpos0];
							return ww;
						} else {
							goto CONTINUE;
						}
					}
					pos--;
				}
			}

		} while (pos >= 0);
				
		return str[0..endpos0];
	}
	
	/// バックログ中は呼ばないようにすること
	TextDrawContext clone() {
		auto instance = new TextDrawContext();
		instance.viewWidth = viewWidth;
		instance.width = width;
		instance.blankHeight = blankHeight;
		instance.blankHeight2 = blankHeight2;
		instance.hInterval = hInterval;
		instance.rgbColorBk = rgbColorBk;
		instance.fontNo = fontNo;
		instance.fontSize = fontSize;
		instance.rgbColor = rgbColor;
		instance.bold = bold;
		instance.italic = italic;
		instance.underLine = underLine;
		instance.strikeOut = strikeOut;
		instance.align1 = align1;
		instance.align2 = align2;
		instance.lineNo = lineNo;
		instance.setText(getText().dup);	// ディープコピーしておかないと
		instance.setTextOffset(getTextOffset());
		instance.setHeadTextOffset(getTextOffset());
		// メソッドない...
//		instance.setBackLogMode();
		return instance;
	}

	///	現在のテキスト解析位置を返す
	int		getTextOffset() { return pos; }
	int		getHeadTextOffset() { return posOld; }
	void	setHeadTextOffset(int pos_) { posOld = pos_; }
	void	setTextOffset(int pos_) { pos = pos_; }
	wchar[] getText() { return str; }
		
	/// バックログ用のフラグを戻す
	void resetBackLog() {
		backText = false;
	}

protected:
	wchar[]	str;	//	現在のコンテクスト位置
	int	pos;		// 読み完了したところまでの位置
	int posOld;		// 読み込んでいるページの最初の位置
	
	bool backText;
	
private :

	/// 以前の<HR>タグの位置を返却する
	int getPrevHRPos() {
		
		// まず現ページのＨＥＡＤポジションを検索
		do {
CONTINUE:;
			wchar c = str[pos--];
			
			if (c=='>') {
				int tailpos = pos;
				while (true) {
					if (pos < 0) {
						pos = 0;
						throw new y4d_error(this,cast(char[]) "タグが閉じられていない");
					}
					wchar wc = str[pos];
					if (wc == '<') {
						wchar[] tag = str[pos+1..tailpos+1];
						if (tag == "HR" || tag == "hr") {
							return pos;
						} else {
							goto CONTINUE;
						}
					}
					pos--;
				}
			}
			
		} while ( pos >= 0 );
		
		pos = 0;
		return 0;
	}
	
}

///	<If n>～<Endif>タグに対するリスナ
interface ScenarioIfListener {
public:
	//	⇒　これをオーバーライドして、nNoに対する真偽判定を返す関数を書く。
	bool Abstract_If(int nNo);
};
