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

namespace Yamalib.GUI
{
    /// <summary>
    /// フォントで描画した文字をボタンとして扱うクラス
    /// </summary>
    public class FontButton : FocusableTextureGUI, IDisposable
    {
        #region 定数値

        #endregion

        #region メンバフィールド

        private Font font;
        private Color4ub? activeColor;
        private Color4ub? nonActiveColor;
        private string buttonText;
        private ITexture buttonTexture;
        private int width, height;
        private IMouseInput mouse = null;
        private bool forceActive;


        #endregion

        public FontButton(FontLoader fontloader, int fontNo)
        {
            this.font = fontloader.GetFont(fontNo);
        }

        public FontButton(Font font)
        {
            this.font = font;
        }

        /// <summary>
        /// 強制的に常にアクティブにする
        /// </summary>
        public bool IsForceActive
        {
            get { return forceActive; }
            set { forceActive = value; }
        }

        /// <summary>
        /// ボタンとして使用する文字を設定する
        /// </summary>
        /// <param name="txt"></param>
        public void SetText(string txt)
        {
            buttonText = txt;
            if (buttonTexture != null)
            {
                buttonTexture.Release();
            }
            buttonTexture = YamalibConst.CreateTexture();
            buttonTexture.SetSurface(font.DrawBlendedUnicode(txt));
        }

        /// <summary>
        /// フォントカラーを設定するt
        /// </summary>
        /// <param name="active"></param>
        /// <param name="nonActive"></param>
        public void SetColor(Color4ub active, Color4ub nonActive)
        {
            activeColor = active;
            nonActiveColor = nonActive;
        }


        #region ITextureGUI メンバ

        public void OnInit(ControlContext cc)
        {
            FocusableGUIParam param = cc.Param as FocusableGUIParam;
            if (null != param)
            {
                mouse = param.Mouse;
            }
        }

        public void OnPaint(IScreen scr, ControlContext cc, int x, int y)
        {
            if (!visible || buttonTexture == null) return;

            if (width == 0 || height == 0)
            {
                ITexture t0 = buttonTexture;
                // ボタンサイズを取得しておき、これをマウスの判定矩形として利用する
                if (t0 != null)
                {
                    width = (int)t0.Width;
                    height = (int)t0.Height;
                }
            }

            int mx, my;
            if (mouse != null)
            {
                mouse.GetPos(out mx, out my);
            }
            else
            {
                cc.MouseInput.GetPos(out mx, out my);
            }
            bool isHover =
                (x <= mx) && (mx < x + width) &&
                (y <= my) && (my < y + height);

            bool isDown = false;
            if (mouse != null)
            {
                isDown = mouse.IsPress(MouseInput.Button.Left);
            }
            else
            {
                isDown = cc.MouseInput.IsPress(MouseInput.Button.Left);
            }

            // 前フレームで、
            // isHover状態でかつisDown
            // 今回のフレームで
            // isHover状態かつ、!isDown
            // ならば、ボタンが押されたとしてボタンイベント発生。

            isOnDown = false;
            if (enable)
            {
                if (lastIsHover && lastIsDown && isHover && !isDown)
                {
                    if (OnClick != null)
                    {
                        OnClick(scr, cc);
                    }
                    isOnDown = true;
                }
                if (lastIsHover && !lastIsDown && isHover && isDown)
                {
                    if (OnDown != null)
                    {
                        OnDown(scr, cc);
                    }
                }
            }
            lastIsDown = isDown;
            lastIsHover = isHover;

            Color4ub? color;
            if (forceActive)
            {
                color = activeColor;
            }
            else if (!enable)
                color = nonActiveColor;
            else if (!isHover)
                color = nonActiveColor;
            else if (isDown)
                color = activeColor;
            else
                color = activeColor;

            ITexture tex = buttonTexture;
            if (tex != null)
            {
                if (color != null)
                {
                    scr.SetColor(color.Value);
                    scr.Blt(tex, x, y);
                    scr.ResetColor();
                }
                else
                {
                    scr.Blt(tex, x, y);
                }
            }
        }

        public delegate void MouseEvent(IScreen scr, ControlContext cc);

        //　前フレームの結果
        private bool lastIsDown;
        private bool lastIsHover;

        /// <summary>
        /// 現在hoverされているのか
        /// </summary>
        /// <remarks>
        /// Enable == falseでもhoverの判定は行なう
        /// </remarks>
        public bool IsHover
        {
            get { return lastIsHover; }
        }

        /// <summary>
        /// このボタンが現在クリックされたところか
        /// (OnClickハンドラを書くのが面倒なときに使ってください)
        /// </summary>
        /// <remarks>
        /// Enable == falseならば常にfalseを返す
        /// </remarks>
        public bool IsDown
        {
            get { return isOnDown && enable; }
        }
        private bool isOnDown;

        /// <summary>
        /// クリックされたときのイベント
        /// </summary>
        public MouseEvent OnClick;

        /// <summary>
        /// 押し下げられた瞬間に発生するイベント
        /// </summary>
        public MouseEvent OnDown;

        /// <summary>
        /// このボタンは使用可能か不可能か。
        /// Enable = falseにすると、ボタンイメージ番号は3番で
        /// 使用不可能なボタンが表示され、その場合には、
        /// ボタンのイベントハンドラは呼び出されない。
        /// 
        /// defaultではEnable。
        /// </summary>
        public bool Enable
        {
            get { return enable; }
            set { enable = value; }
        }
        private bool enable = true;

        /// <summary>
        /// loaderに、表示するときのoffsetを指定できる。
        /// defaultでは0。たとえば、この数値として5を指定すれば、
        /// Disable時に描画されるテクスチャ番号は、本来の3から、3+5 = 8になる。
        /// </summary>
        public int LoaderOffset
        {
            get { return loaderOffset; }
            set { loaderOffset = value; }
        }
        private int loaderOffset;


        /// <summary>
        /// このボタンは表示されているか？
        /// Visible = falseにすると、何も表示されない。
        /// 
        /// defaultでは、true
        /// </summary>
        public bool Visible
        {
            get { return visible; }
            set { visible = value; }
        }
        private bool visible = true;

        #endregion

        #region IDisposable メンバ

        public void Dispose()
        {
            //	loader.Dispose();
            // cacheしているのであえて解放しない
        }

        #endregion

        #region FocusableTextureGUI メンバ

        public void Focus(ControlContext controlContext, int x, int y)
        {
            ITexture t0 = buttonTexture;
            // ボタンサイズを取得しておき、これをマウスの判定矩形として利用する
            if (t0 != null)
            {
                width = (int)t0.Width;
                height = (int)t0.Height;
            }
            if (null != mouse)
            {
                mouse.SetPos(x + width / 2, y + height / 2);
            }
            else
            {
                controlContext.MouseInput.SetPos(x + width / 2, y + height / 2);
            }
        }

        #endregion
    }
}
