module yamalib.gui.dialog;

private import std.string;
private import std.utf;

private import y4d_aux.widestring;
private import y4d_draw.font;
private import y4d_draw.fontloader;
private import y4d_draw.screen;
private import y4d_draw.texture;
private import y4d_draw.drawbase;
private import y4d_draw.sprite;

private import y4d_input.mouse;
private import y4d_input.keyinputbase;

private import ytl.y4d_result;

private import yamalib.auxil.properties;
//private import yamalib.auxil.propertiesw;
private import yamalib.draw.tiletexture;
private import yamalib.gui.guiparts;
private import yamalib.gui.guibutton;
private import yamalib.gui.keygroup;
private import yamalib.log.log;

/** 
	ダイアログボックスで使うフォント、画像を集めたエッセンスオブジェクト。
	一枚札的に使用し、ロードの回数を減らすことで俊敏になり、
	メモリへの負担を軽減させる。
 */
class DialogBoxResources {
	
	/// ダイアログの基本となるタイルを取得
	TileTexture dialogTile() {
		return this.m_dialogTile;
	}
	/// ダイアログの基本となるタイルを設定
	TileTexture dialogTile(TileTexture tile_) {
		return this.m_dialogTile = tile_;
	}
	/// 選択カーソルの基本となるタイルを取得
	TileTexture cursorTile() {
		return this.m_cursorTile;
	}
	/// 選択カーソルの基本となるタイルを設定
	TileTexture cursorTile(TileTexture tile_) {
		return this.m_cursorTile = tile_;
	}
	/// タイトルのタイルを取得
	TileTexture titleTile() {
		return this.m_titleTile;
	}
	/// タイトルのタイルを設定
	TileTexture titleTile(TileTexture tile_) {
		return this.m_titleTile = tile_;
	}
	/// ダイアログのメッセージを生成するフォントを取得
	Font messageFont() {
		return this.m_messageFont;
	}
	/// ダイアログのメッセージを生成するフォントを設定
	Font messageFont(Font font_) {
		return this.m_messageFont = font_;
	}

	/// ダイアログのボタンのラベルに使用するフォントローダーの取得
	FontLoader getButtonLabelFontLoader() {
		return this.m_buttonLabelFontLoader;
	}
	/// 使用すべき、フォントのインデックス番号を取得
	int getButtonLabelFontLoaderNo() {
		return this.m_buttonLabelFontLoaderNo;
	}
	/// ダイアログのボタンのラベルに使用するフォントローダーの設定
	void setButtonLabelFontLoader(FontLoader tl_, int no) {
		this.m_buttonLabelFontLoader = tl_;
		m_buttonLabelFontLoaderNo = no;
	}

	/// コンストラクタ
	this() {
	}
	
private:
	TileTexture m_dialogTile;	//!< ダイアログの基本タイル
	TileTexture m_titleTile;	//!< ダイアログ上部の、タイトルのタイル
	TileTexture m_cursorTile;	//!< ダイアログボックス内選択肢のカーソルタイル
	FontLoader m_buttonLabelFontLoader;
	int	m_buttonLabelFontLoaderNo;
	Font	m_messageFont;
}


/**
	汎用ダイアログボックスクラス
*/
class DialogBox : IGUIParts {
	
	/// ボタンのタイプ
	enum TYPE {
		ONE_BUTTON,		//!< ＯＫ
		TWO_BUTTON,		//!< はい、いいえ
		THREE_BUTTON,	//!< はい、いいえ、キャンセル
		SELECTION		//!< 選択肢用
	};
	
	/// タイトルバーのタイプ
	enum TITLE : int {
		WARNING,
		CAUTION,
		INFORMATION,
		SELECTION,
		ERROR,
	};
	
	/// 描画位置オフセット
	enum POS_OFFSET {
		LEFT_TOP,
		CENTER,
	};
	
	/// 指定ファイルとフォントからダイアログボックスを生成する
	static DialogBox createDialogBox(
		DialogBoxResources dlgRes,
		char[] filename, 
		MouseInput mouse,
		KeyInputBase key=null,
		int prevKeyNo=3,
		int nextKeyNo=4 ) 
	{
		
		Properties prop = Properties.getInstance(filename);
		
		int sx = cast(int) prop.getPropertyNum( cast(char[]) C_PROP_KEY_SIZEX, 320 );
		int sy = cast(int) prop.getPropertyNum( cast(char[]) C_PROP_KEY_SIZEY, 240 );
		char[] msg = prop.getProperty(cast(char[]) C_PROP_KEY_MESSAGE);
		int mox = cast(int) prop.getPropertyNum( cast(char[]) C_PROP_KEY_MESSAGE_OX, 0 );
		int moy = cast(int) prop.getPropertyNum( cast(char[]) C_PROP_KEY_MESSAGE_OY, 0 );
		char[] actCol = prop.getProperty(cast(char[]) C_PROP_KEY_BUTTON_ACTIVE);;
		char[] nonActCol = prop.getProperty(cast(char[]) C_PROP_KEY_BUTTON_NON_ACTIVE);
		char[][] buttonNm = getButtonText(prop);
		int titleType = cast(int) prop.getPropertyNum( cast(char[]) C_PROP_KEY_TITLE_TYPE, 0 );
		int dlgAlpha = cast(int) prop.getPropertyNum( cast(char[]) C_PROP_KEY_DLG_ALPHA,  255 );
		prevKeyNo = cast(int) prop.getPropertyNum( cast(char[]) C_PROP_KEY_TAB_PREV,  prevKeyNo );
		nextKeyNo = cast(int) prop.getPropertyNum( cast(char[]) C_PROP_KEY_TAB_NEXT,  nextKeyNo );
		
		// ダイアログボックスの表示位置
		int dx = cast(int) prop.getPropertyNum( cast(char[]) C_PROP_KEY_POSX, 0 );
		int dy = cast(int) prop.getPropertyNum( cast(char[]) C_PROP_KEY_POSY, 0 );
		// 上の座標は何を意味するか(左上、中央)
		int pos_base = cast(int) prop.getPropertyNum( cast(char[]) C_PROP_KEY_POS_BASE, 0 );


/+		
		PropertiesW prop = PropertiesW.getInstance(filename);
		
		int sx = cast(int) prop.getPropertyNum( .toUTF16(C_PROP_KEY_SIZEX), 320 );
		int sy = cast(int) prop.getPropertyNum( .toUTF16(C_PROP_KEY_SIZEY), 240 );
		wchar[] msg = prop.getProperty(.toUTF16(C_PROP_KEY_MESSAGE));
		int mox = cast(int) prop.getPropertyNum( .toUTF16(C_PROP_KEY_MESSAGE_OX), 0 );
		int moy = cast(int) prop.getPropertyNum( .toUTF16(C_PROP_KEY_MESSAGE_OY), 0 );
		wchar[] actCol = prop.getProperty(.toUTF16(C_PROP_KEY_BUTTON_ACTIVE));;
		wchar[] nonActCol = prop.getProperty(.toUTF16(C_PROP_KEY_BUTTON_NON_ACTIVE));
		wchar[][] buttonNm = getButtonText(prop);
		int titleType = cast(int) prop.getPropertyNum( .toUTF16(C_PROP_KEY_TITLE_TYPE), 0 );
		int dlgAlpha = cast(int) prop.getPropertyNum( .toUTF16(C_PROP_KEY_DLG_ALPHA),  255 );
		prevKeyNo = cast(int) prop.getPropertyNum( .toUTF16(C_PROP_KEY_TAB_PREV),  prevKeyNo );
		nextKeyNo = cast(int) prop.getPropertyNum( .toUTF16(C_PROP_KEY_TAB_NEXT),  nextKeyNo );
		
		// ダイアログボックスの表示位置
		int dx = cast(int) prop.getPropertyNum( .toUTF16(C_PROP_KEY_POSX), 0 );
		int dy = cast(int) prop.getPropertyNum( .toUTF16(C_PROP_KEY_POSY), 0 );
		// 上の座標は何を意味するか(左上、中央)
		int pos_base = cast(int) prop.getPropertyNum( .toUTF16(C_PROP_KEY_POS_BASE), 0 );
+/

		
		// 指定された表示位置は基準点
		if (0 != pos_base) {
			switch(pos_base) {
			case 1:
				// 中央
				dx -= sx / 2; 
				dy -= sy / 2; 
				break;
			default :
				// そなん実装してないよ...
				break;
			}
		}
		
		// ここ直さないといかんかも
		dlgRes.titleTile = new TileTexture(TileTexture.TILE_TYPE.H_LINE3);
		dlgRes.titleTile.load(cast(char[]) "img/dialog/title.sdf");
		
		DialogBox dialog = new DialogBox();
		dialog.setDialogBoxResources(dlgRes);
		
		// KeyGroupで使用するキーと使用するキー番号を設定
		dialog.setKey(key,prevKeyNo,nextKeyNo);
		dialog.setDialogSize(sx, sy);
		dialog.setXY(dx, dy);
		dialog.setXYOffsetType(DialogBox.POS_OFFSET.LEFT_TOP);
		dialog.setTitleType(cast(DialogBox.TITLE) titleType);
		dialog.setDialogAlpha( dlgAlpha );

		if (0 != msg.length) {
			Texture t = setMessageText(dlgRes.messageFont, msg );
			dialog.setMessageTexture(t, mox, moy, true);
		}
		
		GUIButton[] bts;
		int box, boy;

		foreach(int i, char[] btLabel; buttonNm) {
			getButtonXY(prop, i, box,boy);
			GUIButton bt = createButton(mouse, 
								dlgRes.getButtonLabelFontLoader(),
								dlgRes.getButtonLabelFontLoaderNo(), 
								btLabel, actCol, nonActCol, dlgRes.cursorTile);
			bt.setXY( dx + box, dy + boy);
			bts ~= bt;
		}
		
		dialog.setButton(bts);

		return dialog;
	}

	/// ダイアログボックスで使用するリソースを設定する
	void setDialogBoxResources(DialogBoxResources res) {
		this.m_dlgRes = res;
	}
	
	/// キーを設定する
	// keyno = タブグループに使用するkeyno
	void setKey(KeyInputBase key, int prevKeyNo, int nextKeyNo) {
		m_key = key;
		m_prevTabKeyNo = prevKeyNo;
		m_nextTabKeyNo = nextKeyNo;
	}
	
	/// モーダルに設定する
	/**
		この変数をみるかどうかは、このダイアログを使用するクラスに依存
	*/
	void setModal(bool b) {
		this.m_modal = b;
	}
	/// モーダル・モーダレス状態を取得
	bool isModal() {
		return this.m_modal;
	}
	
	/// ダイアログを表示する
	void show() {
		this.m_show = true;
	}
	
	/// ダイアログを消す
	void hide() {
		this.m_show = false;
	}
	
	/// ダイアロブボックスのサイズ
	void setDialogSize(int sx_, int sy_) {
		this.m_sx = sx_;
		this.m_sy = sy_;
	}
	
	/// ダイアログボックスのアルファ値の設定
	void setDialogAlpha(int alpha_) {
		if (alpha_ <  0) {
			alpha_ = 0;
		} else if ( alpha_ > 255 ) {
			alpha_ = 255;
		}
		this.m_dlgAlpha = alpha_;
	}
	
	/// 描画オフセットタイプの設定
	/// 事前に setXY で指定した値に有効
	void setXYOffsetType(POS_OFFSET type) {
		this.m_offsetType = type;
	}
		
	/// 対象ボタンを設定
	void setButton(GUIButton[] bts) {
		this.m_buttons = bts;
		this.m_keyGroup.clear();
		foreach (GUIButton bt; bts) {
			m_keyGroup.add(bt);
		}
		m_keyGroup.focus(bts.length-1);
	}
	/// 設定したボタンは onMove したあと、自分で好きなように判定すれ
	GUIButton[] getButton() {
		return this.m_buttons;
	}
	
	/// 表示メッセージを文字として設定
	void setShowMessage(char[] text_) {
		m_text = text_;
	}
	
	/// 表示メッセージをテクスチャとして設定する
	void setMessageTexture(Texture tex_, int ox, int oy, bool resizeWidth=false) {
		this.m_messageTex = tex_;
		this.m_msgox = ox;
		this.m_msgoy = oy;
		if (resizeWidth) {
			this.m_sx = cast(int) tex_.getWidth() + (ox*2);
		}
	}
	
	/// タイトルバーのタイプを設定します
	void setTitleType(TITLE type) {
		m_titleType = type;
	}
	/// タイトルバーのタイプを取得する
	TITLE getTitleType() {
		return m_titleType;
	}
	
	/// 移動処理
	override void onMove(Screen screen) {
		if (!this.m_show) return;

		if ( !(m_key is null) ) {
			if (m_key.isPush(m_nextTabKeyNo)) {
Log.print("press next : %s", m_nextTabKeyNo);
				m_keyGroup.next();
			} else if (m_key.isPush(m_prevTabKeyNo)) {
Log.print("press prev : %s", m_prevTabKeyNo);
				m_keyGroup.prev();
			}
		}
		
		// ボタン表示
		foreach (GUIButton bt; m_buttons ) {
			bt.onMove(screen);
		}
		
	}
	
	/// 描画処理
	override void onDraw(Screen screen) {
		if (!this.m_show) return;
		
		Color4ub colorOrg = screen.getColor4ub();
		
		screen.blendSrcAlpha();
		screen.setColor(255,255,255, m_dlgAlpha);
		
		int posx;
		int posy;
		
		if (POS_OFFSET.LEFT_TOP == m_offsetType) {
			posx = this.x;
			posy = this.y;
		} else if(POS_OFFSET.CENTER == m_offsetType) {
			posx = this.x - (this.m_sx/2);
			posy = this.y - (this.m_sy/2);
		}
		// メインダイアログ描画
		m_dlgRes.dialogTile.blt(screen,x,y,m_sx,m_sy);
		
		// ボタン表示
		foreach (GUIButton bt; m_buttons ) {
			bt.onDraw(screen);
		}

		// タイトルバー描画
		screen.setColor(255,255,255,255);
		m_dlgRes.titleTile.blt(screen,x,y,m_sx,0);

		// メッセージ表示
		if ( !(this.m_messageTex is null) ) {
			screen.blt(m_messageTex, posx + m_msgox, posy + m_msgoy);
		} else if ( !(m_text is null) ) {
			// todo
		}
		
		// 色を元に戻す
		screen.setColor(colorOrg);

	}
	/// KeyGroupを取得する
	// デフォルトのキーグループをカスタマズはこれをいじる
	KeyGroup getKeyGroup() {
		return m_keyGroup;
	}
	
	/// コンストラクタ
	this() {
		m_keyGroup = new KeyGroup();
		
		m_type = TYPE.TWO_BUTTON;
		m_sx = 120;
		m_sy = 80;
		m_show = true;
		m_titleTex = new Texture();
		setTitleType( TITLE.INFORMATION );
		m_dlgAlpha = 255;
		m_offsetType = POS_OFFSET.LEFT_TOP;
	}
	
protected:

/+
	/// プロパティよりボタンの名前を取得する	
	static wchar[][] getButtonText(PropertiesW prop) {
		wchar[][] result;
		int count = 0;
		while (true) {
			wchar[] key = .toUTF16(C_PROP_KEY_BUTTON_NM ~ std.string.toString(count));
			wchar[] str = prop.getProperty(key);
			if (str is null) {
				break;
			}
			++count;
			result ~= str;
		}
		
		return result;
	}
+/
	/// プロパティよりボタンの名前を取得する	
	static char[][] getButtonText(Properties prop) {
		char[][] result;
		int count = 0;
		while (true) {
			char[] key = C_PROP_KEY_BUTTON_NM ~ std.string.toString(count);
			char[] str = prop.getProperty(key);
			if (str is null) {
				break;
			}
			++count;
			result ~= str;
		}
		
		return result;
	}

	/// 当該のボタンオフセットｘとｙを取得する
	static void getButtonXY(Properties prop, int no, out int x_, out int y_) {
		x_ = cast(int) prop.getPropertyNum(
				C_PROP_KEY_BUTTON_OX ~ std.string.toString(no), 0 );
		y_ = cast(int) prop.getPropertyNum(
				C_PROP_KEY_BUTTON_OY ~ std.string.toString(no), 0 );
	}

/+
	/// 当該のボタンオフセットｘとｙを取得する
	static void getButtonXY(PropertiesW prop, int no, out int x_, out int y_) {
		x_ = cast(int) prop.getPropertyNum(
				.toUTF16(C_PROP_KEY_BUTTON_OX ~ std.string.toString(no)), 0 );
		y_ = cast(int) prop.getPropertyNum(
				.toUTF16(C_PROP_KEY_BUTTON_OY ~ std.string.toString(no)), 0 );
	}
+/
	/// メッセージを作成してセットする	
	static Texture setMessageText(Font font, char[] msg) {
		Texture t = new Texture();
		t.setSurface( font.drawBlendedUTF8(msg) );
		return t;
	}
	
	/// ボタンを生成する
	static GUIButton createButton(MouseInput mouse, FontLoader fl, int fontno, 
				char[] text, char[] colorOn, char[] colorOff, TileTexture bgTex) {
		GUIButton bt = new GUIButton();
		bt.setMouse(mouse);
		GUIFontButtonListener v = new GUIFontButtonListener;
		v.setFontLoader(fl, fontno);
		v.setType(1);
		v.setColor( colorOn, colorOff);
		v.setText( text );
		v.setActiveBackTexture(bgTex);
		bt.setEvent(v);
		bt.setXY(550,450);
		return bt;
	}
	
	
private :
	static const char[][] TITLE_BAR_FILENAME = [
		"img/dialog/sel_bar01.png",
		"img/dialog/sel_bar02.png",
		"img/dialog/sel_bar03.png",
		"img/dialog/sel_bar04.png",
		"img/dialog/sel_bar05.png",
	];

	
	static const char[] C_PROP_KEY_MESSAGE = "MESSAGE";
	static const char[] C_PROP_KEY_MESSAGE_OX = "MESSAGE_OX";
	static const char[] C_PROP_KEY_MESSAGE_OY = "MESSAGE_OY";
	static const char[] C_PROP_KEY_SIZEX = "SIZEX";
	static const char[] C_PROP_KEY_SIZEY = "SIZEY";
	static const char[] C_PROP_KEY_TITLE_TYPE = "TITLE_TYPE";
	static const char[] C_PROP_KEY_BUTTON_NM = "BUTTON_NM";
	static const char[] C_PROP_KEY_BUTTON_ACTIVE = "BUTTON_ACTIVE";
	static const char[] C_PROP_KEY_BUTTON_NON_ACTIVE = "BUTTON_NON_ACTIVE";
	static const char[] C_PROP_KEY_BUTTON_OX = "BUTTON_OX";
	static const char[] C_PROP_KEY_BUTTON_OY = "BUTTON_OY";
	static const char[] C_PROP_KEY_POSX = "POSX";
	static const char[] C_PROP_KEY_POSY = "POSY";
	static const char[] C_PROP_KEY_POS_BASE = "POS_BASE";
	static const char[] C_PROP_KEY_DLG_ALPHA = "DLG_ALPHA";	
	static const char[] C_PROP_KEY_TAB_NEXT = "TAB_NEXT";
	static const char[] C_PROP_KEY_TAB_PREV = "TAB_PREV";


/+
	static const wchar[] C_PROP_KEY_MESSAGE = "MESSAGE";
	static const wchar[] C_PROP_KEY_MESSAGE_OX = "MESSAGE_OX";
	static const wchar[] C_PROP_KEY_MESSAGE_OY = "MESSAGE_OY";
	static const wchar[] C_PROP_KEY_SIZEX = "SIZEX";
	static const wchar[] C_PROP_KEY_SIZEY = "SIZEY";
	static const wchar[] C_PROP_KEY_TITLE_TYPE = "TITLE_TYPE";
	static const wchar[] C_PROP_KEY_BUTTON_NM = "BUTTON_NM";
	static const wchar[] C_PROP_KEY_BUTTON_ACTIVE = "BUTTON_ACTIVE";
	static const wchar[] C_PROP_KEY_BUTTON_NON_ACTIVE = "BUTTON_NON_ACTIVE";
	static const wchar[] C_PROP_KEY_BUTTON_OX = "BUTTON_OX";
	static const wchar[] C_PROP_KEY_BUTTON_OY = "BUTTON_OY";
	static const wchar[] C_PROP_KEY_POSX = "POSX";
	static const wchar[] C_PROP_KEY_POSY = "POSY";
	static const wchar[] C_PROP_KEY_POS_BASE = "POS_BASE";
	static const wchar[] C_PROP_KEY_DLG_ALPHA = "DLG_ALPHA";	
	static const wchar[] C_PROP_KEY_TAB_NEXT = "TAB_NEXT";
	static const wchar[] C_PROP_KEY_TAB_PREV = "TAB_PREV";
+/

	TYPE m_type;
	TITLE m_titleType;	//!< タイトルバーのタイプ
	
	KeyInputBase m_key;
	int m_prevTabKeyNo;
	int m_nextTabKeyNo;
	KeyGroup m_keyGroup;
	
	bool m_modal;
	bool m_show;		//!< 表示フラグ
	Texture m_titleTex;
	Texture m_messageTex; //!< メッセージテクスチャ
	int m_msgox;	//!< メッセージ描画位置のオフセット値
	int m_msgoy;	//!< メッセージ描画位置のオフセット値
	POS_OFFSET m_offsetType;	//!< 描画オフセットタイプ
	int m_dlgAlpha;
	
	char[] m_text;
	
	int m_sx;
	int m_sy;

	GUIButton[] m_buttons;
	
	DialogBoxResources m_dlgRes;

}
