using System;
using System.Collections.Generic;
using System.Text;
using Yamalib.Draw;
using Yanesdk.Draw;
using Yanesdk.GUIParts;
using Yanesdk.Input;
using Yamalib.Util;

namespace Yamalib.GUI
{
    /// <summary>
    /// ダイアログボックスで使うフォント、画像を集めたエッセンスオブジェクト。
    ///	 一枚札的に使用し、ロードの回数を減らすことで俊敏になり、
    /// メモリへの負担を軽減させる。
    /// </summary>
    public class DialogBoxResources
    {
        #region メンバフィールド

        private TileTexture dialogTile;	//!< ダイアログの基本タイル
        public TileTexture DialogTile
        {
            get { return dialogTile; }
            set { dialogTile = value; }
        }

        private TileTexture titleTile;	//!< ダイアログ上部の、タイトルのタイル
        public TileTexture TitleTile
        {
            get { return titleTile; }
            set { titleTile = value; }
        }

        private TileTexture cursorTile;	//!< ダイアログボックス内選択肢のカーソルタイル
        public TileTexture CursorTile
        {
            get { return cursorTile; }
            set { cursorTile = value; }
        }

        private FontLoader buttonLabelFontLoader;
        public FontLoader ButtonLabelFontLoader
        {
            get { return buttonLabelFontLoader; }
            set { buttonLabelFontLoader = value; }
        }

        private int buttonLabelFontLoaderNo;
        public int ButtonLabelFontLoaderNo
        {
            get { return buttonLabelFontLoaderNo; }
            set { buttonLabelFontLoaderNo = value; }
        }

        private Font messageFont;
        public Font MessageFont
        {
            get { return messageFont; }
            set { messageFont = value; }
        }

        #endregion
    }

    /// <summary>
    /// OSに依存しないTextureによるダイアログボックス
    /// </summary>
    public class TextureDialog : ITextureGUI
    {

        #region 定数値

        /// ボタンのタイプ
        public enum TYPE
        {
            ONE_BUTTON,		//!< ＯＫ
            TWO_BUTTON,		//!< はい、いいえ
            THREE_BUTTON,	//!< はい、いいえ、キャンセル
            SELECTION		//!< 選択肢用
        };

        /// タイトルバーのタイプ
        public enum TITLE : int
        {
            WARNING,
            CAUTION,
            INFORMATION,
            SELECTION,
            ERROR,
        };

        /// 描画位置オフセット
        public enum POS_OFFSET
        {
            LEFT_TOP,
            CENTER,
        };

        private static readonly string[] TITLE_BAR_FILENAME = new string[]{
		    "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",
	    };

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


        #endregion

        #region メンバフィールド

        //private TYPE m_type = TYPE.TWO_BUTTON;
        private TITLE m_titleType = TITLE.INFORMATION;	//!< タイトルバーのタイプ

        private IKeyInput m_key;

        private bool m_modal;
        private bool m_show = true;		//!< 表示フラグ
        //private ITexture m_titleTex;
        private ITexture m_messageTex; //!< メッセージテクスチャ
        private int m_msgox;	//!< メッセージ描画位置のオフセット値
        private int m_msgoy;	//!< メッセージ描画位置のオフセット値
        private POS_OFFSET m_offsetType = POS_OFFSET.LEFT_TOP;	//!< 描画オフセットタイプ
        private int m_dlgAlpha = 255;

        private string m_text = string.Empty;

        private int m_x;
        private int m_y;
        private int m_sx = 120;
        private int m_sy = 80;

        private FocusableTextureGUIControl textureGuiCtrl = new FocusableTextureGUIControl();
        private List<TextureGUIControl.Control> m_button = new List<TextureGUIControl.Control>();
        private ControlContext ctrlContext;

        private DialogBoxResources m_dlgRes;

        #endregion


        /// <summary>
        /// ダイアログボックスを作って返却する
        /// </summary>
        /// <param name="dlgRes"></param>
        /// <param name="defFilename"></param>
        /// <param name="mouse"></param>
        /// <param name="key"></param>
        /// <param name="prevKeyNo"></param>
        /// <param name="nextKeyNo"></param>
        /// <returns></returns>
        public static TextureDialog CreateDialogBox(DialogBoxResources dlgRes, string defFilename, ControlContext cc,
            IKeyInput key, int prevKeyNo, int nextKeyNo)
        {
            Properties prop = Properties.GetInstance(defFilename);

            int sx = (int)prop.GetPropertyNum(C_PROP_KEY_SIZEX, 320);
            int sy = (int)prop.GetPropertyNum(C_PROP_KEY_SIZEY, 240);
            string msg = prop.GetProperty(C_PROP_KEY_MESSAGE);
            int mox = (int)prop.GetPropertyNum(C_PROP_KEY_MESSAGE_OX, 0);
            int moy = (int)prop.GetPropertyNum(C_PROP_KEY_MESSAGE_OY, 0);
            string actCol = prop.GetProperty(C_PROP_KEY_BUTTON_ACTIVE); ;
            string nonActCol = prop.GetProperty(C_PROP_KEY_BUTTON_NON_ACTIVE);
            List<string> buttonNm = GetButtonText(prop);
            int titleType = (int)prop.GetPropertyNum(C_PROP_KEY_TITLE_TYPE, 0);
            int dlgAlpha = (int)prop.GetPropertyNum(C_PROP_KEY_DLG_ALPHA, 255);
            prevKeyNo = (int)prop.GetPropertyNum(C_PROP_KEY_TAB_PREV, prevKeyNo);
            nextKeyNo = (int)prop.GetPropertyNum(C_PROP_KEY_TAB_NEXT, nextKeyNo);

            // ダイアログボックスの表示位置
            int dx = (int)prop.GetPropertyNum(C_PROP_KEY_POSX, 0);
            int dy = (int)prop.GetPropertyNum(C_PROP_KEY_POSY, 0);
            // 上の座標は何を意味するか(左上、中央)
            int pos_base = (int)prop.GetPropertyNum(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(null, TileTexture.TILE_TYPE.H_LINE3);

            TextureDialog dialog = new TextureDialog();
            dialog.SetDialogBoxResources(dlgRes);

            // KeyGroupで使用するキーと使用するキー番号を設定
            dialog.SetKey(key, prevKeyNo, nextKeyNo);
            dialog.SetDialogSize(sx, sy);
            dialog.SetXY(dx, dy);
            dialog.SetXYOffsetType(TextureDialog.POS_OFFSET.LEFT_TOP);
            dialog.SetTitleType((TextureDialog.TITLE)titleType);
            dialog.SetDialogAlpha(dlgAlpha);

            if (0 != msg.Length)
            {
                ITexture t = SetMessageText(dlgRes.MessageFont, msg);
                dialog.SetMessageTexture(t, mox, moy, true);
            }

            int box, boy;

            int i = 0;
            foreach (string btLabel in buttonNm)
            {
                GetButtonXY(prop, i, out box, out boy);
                FontButton bt = CreateButton(cc,
                                    dlgRes.ButtonLabelFontLoader,
                                    dlgRes.ButtonLabelFontLoaderNo,
                                    btLabel, actCol, nonActCol, dlgRes.CursorTile);
                dialog.AddButton(bt, cc, dx + box, dy + boy);
                ++i;
            }

            return dialog;
        }

        #region ITextureGUI メンバ

        /// <summary>
        /// 初期化処理
        /// </summary>
        /// <param name="cc"></param>
        public void OnInit(ControlContext cc)
        {
            ctrlContext = cc;
            textureGuiCtrl.OnInit(cc);
        }

        /// <summary>
        /// 動作/描画処理
        /// </summary>
        /// <param name="scr"></param>
        /// <param name="cc"></param>
        /// <param name="X"></param>
        /// <param name="Y"></param>
        public void OnPaint(IScreen scr, ControlContext cc, int x, int y)
        {
            // 移動処理
            OnMove(scr, cc);
            // 描画処理
            OnDraw(scr, cc);
        }

        public bool Visible
        {
            get
            {
                throw new Exception("The method or operation is not implemented.");
            }
            set
            {
                throw new Exception("The method or operation is not implemented.");
            }
        }

        #endregion

        /// <summary>
        /// 移動処理
        /// </summary>
        /// <param name="screen"></param>
        private void OnMove(IScreen screen, ControlContext cc)
        {
            if (!this.m_show) return;
            if (!(m_key == null))
            {
                textureGuiCtrl.OnMoveFocus();
            }
        }

        /// <summary>
        /// 描画処理
        /// </summary>
        /// <param name="screen"></param>
        private void OnDraw(IScreen screen, ControlContext cc)
        {
            if (!this.m_show) return;

            Color4ub colorOrg = YanesdkUtil.GetNowScreenColor(screen);
            screen.BlendSrcAlpha();
            screen.SetColor(255, 255, 255, m_dlgAlpha);

            int posx;
            int posy;
            posx = posy = 0;
            if (POS_OFFSET.LEFT_TOP == m_offsetType)
            {
                posx = this.m_x;
                posy = this.m_y;
            }
            else if (POS_OFFSET.CENTER == m_offsetType)
            {
                posx = this.m_x - (this.m_sx / 2);
                posy = this.m_y - (this.m_sy / 2);
            }
            // メインダイアログ描画
            m_dlgRes.DialogTile.OnPaint(screen, m_x, m_y, m_sx, m_sy);

            // ボタン描画
            textureGuiCtrl.OnPaint(screen);

            // タイトルバー描画
            screen.SetColor(255, 255, 255, 255);
            //m_dlgRes.TitleTile.OnPaint(screen, m_x, m_y, m_sx, 0);

            // メッセージ表示
            if (this.m_messageTex != null)
            {
                screen.Blt(m_messageTex, posx + m_msgox, posy + m_msgoy);
            }
            else if (m_text != null)
            {
                // todo
            }

            // 色を元に戻す
            screen.SetColor(colorOrg);
        }

        /// <summary>
        /// ダイアログボックスで使用するリソースを設定する
        /// </summary>
        /// <param name="res"></param>ed
        public void SetDialogBoxResources(DialogBoxResources res)
        {
            this.m_dlgRes = res;
        }

        public void SetXY(int x, int y)
        {
            this.m_x = x;
            this.m_y = y;
        }

        /// <summary>
        /// キーを設定する
        /// </summary>
        /// <param name="key"></param>
        /// <param name="prevKeyNo">タブグループに使用するkeyno</param>
        /// <param name="nextKeyNo">タブグループに使用するkeyno</param>
        public void SetKey(IKeyInput key, int prevKeyNo, int nextKeyNo)
        {
            m_key = key;
            textureGuiCtrl.PrevButtonNo = prevKeyNo;
            textureGuiCtrl.NextButtonNo = nextKeyNo;
        }

        /// モーダルに設定する
        /**
            この変数をみるかどうかは、このダイアログを使用するクラスに依存
        */
        public void SetModal(bool b)
        {
            this.m_modal = b;
        }
        /// モーダル・モーダレス状態を取得
        public bool IsModal()
        {
            return this.m_modal;
        }

        /// ダイアログを表示する
        public void Show()
        {
            this.m_show = true;
        }

        /// ダイアログを消す
        public void Hide()
        {
            this.m_show = false;
        }

        /// ダイアロブボックスのサイズ
        public void SetDialogSize(int sx_, int sy_)
        {
            this.m_sx = sx_;
            this.m_sy = sy_;
        }

        /// ダイアログボックスのアルファ値の設定
        public void SetDialogAlpha(int alpha_)
        {
            if (alpha_ < 0)
            {
                alpha_ = 0;
            }
            else if (alpha_ > 255)
            {
                alpha_ = 255;
            }
            this.m_dlgAlpha = alpha_;
        }

        /// 描画オフセットタイプの設定
        /// 事前に SetXY で指定した値に有効
        public void SetXYOffsetType(POS_OFFSET type)
        {
            this.m_offsetType = type;
        }

        /// <summary>
        /// ボタンを追加する
        /// </summary>
        /// <param name="button"></param>
        /// <param name="X"></param>
        /// <param name="Y"></param>
        public void AddButton(ITextureGUI button, ControlContext cc,  int x, int y)
        {
            textureGuiCtrl.OnInit(cc);
            TextureGUIControl.Control control = new TextureGUIControl.Control(button, x, y);
            m_button.Add(control);
            textureGuiCtrl.AddControl(control);

            FocusableTextureGUI focusGui = button as FocusableTextureGUI;
            if (null != focusGui)
            {
                textureGuiCtrl.AddFocusGUI(focusGui);
            }

        }

        /// <summary>
        /// 設定されているすべてのボタンを取得する
        /// </summary>
        /// <returns></returns>
        public List<TextureGUIControl.Control> GetButton()
        {
            return m_button;
        }

        /// 表示メッセージを文字として設定
        public void SetShowMessage(string text_)
        {
            m_text = text_;
        }

        /// 表示メッセージをテクスチャとして設定する
        public void SetMessageTexture(ITexture tex_, int ox, int oy, bool resizeWidth)
        {
            this.m_messageTex = tex_;
            this.m_msgox = ox;
            this.m_msgoy = oy;
            if (resizeWidth)
            {
                this.m_sx = (int)tex_.Width + (ox * 2);
            }
        }

        /// タイトルバーのタイプを設定します
        public void SetTitleType(TITLE type)
        {
            m_titleType = type;
        }

        /// タイトルバーのタイプを取得する
        public TITLE GetTitleType()
        {
            return m_titleType;
        }

        /// プロパティよりボタンの名前を取得する	
        protected static List<string> GetButtonText(Properties prop)
        {
            int count = 0;
            List<string> result = new List<string>();
            while (true)
            {
                string key = C_PROP_KEY_BUTTON_NM + count.ToString();
                string str = prop.GetProperty(key);
                if (str == null || str.Length == 0)
                {
                    break;
                }
                ++count;
                result.Add(str);
            }
            return result;
        }

        /// 当該のボタンオフセットｘとｙを取得する
        protected static void GetButtonXY(Properties prop, int no, out int x_, out int y_)
        {
            x_ = (int)prop.GetPropertyNum(C_PROP_KEY_BUTTON_OX + no.ToString(), 0);
            y_ = (int)prop.GetPropertyNum(C_PROP_KEY_BUTTON_OY + no.ToString(), 0);
        }

        /// <summary>
        /// メッセージを作成してセットする
        /// </summary>
        /// <param name="font"></param>
        /// <param name="msg"></param>
        /// <returns></returns>
        protected static ITexture SetMessageText(Font font, string msg)
        {
            ITexture texture = YamalibConst.CreateTexture();
            texture.SetSurface(font.DrawBlendedUnicode(msg));
            return texture;
        }

        /// ボタンを生成する
        private static FontButton CreateButton(ControlContext cc, FontLoader fl, int fontno,
                    string text, string colorOn, string colorOff, TileTexture bgTex)
        {
            FontButton bt = new FontButton(fl, fontno);
            bt.OnInit(cc);
            bt.SetText(text);
            bt.SetColor(YanesdkUtil.ToColor4ub(colorOn), YanesdkUtil.ToColor4ub(colorOff));
            bt.OnClick += null;
            return bt;
        }
    }
}
