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

namespace Yamalib.GUI
{
    public class Slider : FocusableTextureGUI
    {

        #region 定数値

        private const int KEY_MOVE_SIZE = 3;
        private const int LC_SCROLL_MAX = 65535;

        #endregion

        #region メンバフィールド

        private ITexture m_barTex;	// スライダーボタンのテクスチャ
        private ITexture m_baseTex;	// 下地となるテクスチャ

        private IKeyInput m_key;

        private bool m_keyFocused;
        private bool m_keyFocusedMove;

        private int m_posOld;	//!< 前の位置	
        private int preMx;
        private int preMy;

        private int m_texSz;
        private int m_ox;
        private int m_oy;
        private int m_sx;		//!< スライダーボタンの大きさ
        private int m_sy;
        private int m_length;	//!< スライダーの可動範囲
        private int m_pos;		//!< 現在のスクロールバーの位置
        private int m_catch;	//!< スクロールバーをつかんでいるか
        private int m_catchOx;

        private int x;
        private int y;

        private ControlContext controlContex;

        #endregion


        #region ITextureGUI メンバ

        public void OnInit(ControlContext cc)
        {
            controlContex = cc;
        }

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

        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


        /// スクロールバーのサイズ
        public void SetSize(int x_, int y_)
        {
            this.m_sx = x_;
            this.m_sy = y_;
        }

        /// キーを設定する
        public void SetKey(IKeyInput key_)
        {
            this.m_key = key_;
        }

        /// スライドバーが動かされたか
        public bool IsModifiy()
        {
            return m_posOld != m_pos;
        }

        /// スライダーの可動範囲の設定
        public void SetLength(int length_)
        {
            this.m_length = length_;
        }

        /// スライダーの可動範囲の取得
        public int GetLength()
        {
            return this.m_length;
        }

        /// 位置の設定
        public void SetXY(int x_, int y_)
        {
            x = x_;
            y = y_;
        }

        /// スライダーボタンのオフセット位置
        public void SetSliderOffset(int ox_, int oy_)
        {
            this.m_ox = ox_;
            this.m_oy = (int)(oy_ - m_barTex.Height / 2);
        }

        /// スライド位置の設定
        public void SetSlidePos(float f)
        {
            if (1.0f < f)
            {
                f = 1.0f;
            }
            else if (0.0f > f)
            {
                f = 0.0f;
            }
            this.m_pos = (int)(m_length * f) + x;
        }
        /// スクロールポジションの取得(0 - 1.0)
        public float GetSlidePos()
        {
            int width = m_pos - x;
            if (width == 0)
            {
                return 0.0f;
            }
            return width / (float)m_length;
        }


        /// 下地テクスチャの設定
        public void SetBaseTexture(ITexture t_)
        {
            this.m_baseTex = t_;
        }

        /// バーテクスチャの設定
        public void SetBarTexture(ITexture t_)
        {
            this.m_barTex = t_;
            m_texSz = (int)t_.Width;
            this.m_sx = (int)t_.Width;
            this.m_sy = (int)t_.Height;
        }

        private void OnMove(IScreen screen, ControlContext cc)
        {
            int mx, my;
            cc.MouseInput.GetPos(out mx, out my);
            m_posOld = m_pos;

            // key対応
            if (m_key != null)
            {
                bool isIn = PointInRect(mx, my, m_pos + m_ox, y + m_oy, m_pos + m_sx + m_ox, y + m_sy + m_oy);

                // キーフォーカスされているときに、マウスが操作されたら、キーフォーカスをOFFにする
                if (m_keyFocused && m_keyFocusedMove)
                {
                    if (mx != preMx || my != preMy)
                    {
                        m_keyFocused = false;
                    }
                }

                if (!isIn || !m_keyFocused)
                {
                    this.m_keyFocused = false;
                    this.m_keyFocusedMove = false;
                    OnMoveSlider(cc.MouseInput.IsPress(MouseInput.Button.Left), mx, my);
                }
                else
                {
                    if (m_key.IsPress(3))
                    {
                        // 左
                        if (!IsMin())
                        {
                            mx -= KEY_MOVE_SIZE;
                        }

                    }
                    else if (m_key.IsPress(4))
                    {
                        // 右
                        if (!IsMax())
                        {
                            mx += KEY_MOVE_SIZE;
                        }
                    }
                    cc.MouseInput.SetPos(mx, my);
                    preMx = mx;
                    preMy = my;
                    m_keyFocusedMove = true;
                    OnMoveSlider(true, mx, my);
                }


            }
            else
            {
                // キーは設定されていない
                OnMoveSlider(cc.MouseInput.IsPress(MouseInput.Button.Left), mx, my);
            }
        }

        /// スライダーの移動動作
        private void OnMoveSlider(bool leftDown, int mouseX, int mouseY)
        {
            if (m_pos < this.x)
            {
                m_pos = this.x;
            }

            if (leftDown)
            {
                // キャッチしていない時に、スライドバー自体をキャッチした
                if (0 == m_catch
                    && PointInRect(mouseX, mouseY, m_pos + m_ox, y + m_oy, m_pos + m_sx + m_ox, y + m_sy + m_oy))
                {
                    m_catch = 1;
                    m_catchOx = m_pos - mouseX;
                }

                // キャッチしてないときに、スライドバー可動範囲のどこかを選択した
                else if (0 == m_catch
                    && PointInRect(mouseX, mouseY, x, y + m_oy, x + m_sx + m_length, y + m_sy + m_oy))
                {
                    m_catch = 2;
                    m_catchOx = 0;
                }
            }
            else
            {
                m_catch = 0;
            }

            // キャッチしている
            if (m_catch != 0)
            {
                m_pos = mouseX + m_catchOx;
                if (m_pos < this.x)
                {
                    m_pos = this.x;
                }
                else if (m_pos > this.x + m_length)
                {
                    m_pos = this.x + m_length;
                }
            }
        }

        /// <summary>
        /// 描画処理
        /// </summary>
        /// <param name="screen"></param>
        public void OnDraw(IScreen screen)
        {
            Color4ub colorOrg = YanesdkUtil.GetNowScreenColor(screen);

            // 下地描画
            screen.Blt(this.m_baseTex, x, y);

            // スライダー描画
            if (m_barTex == null)
            {
                screen.SetColor(0, 255, 0);
                screen.DrawPolygon(
                    x + m_ox, m_pos,
                    x + m_oy, m_pos + m_texSz,
                    x + m_ox + m_sx, m_pos + m_texSz,
                    x + m_oy + m_sx, m_pos
                );
            }
            else
            {
                // テクスチャとして描画
                screen.Blt(this.m_barTex, m_pos + m_ox, y + m_oy);
            }

            // 色戻し
            screen.SetColor(colorOrg);
        }


        /// キーフォーカス状態の設定	
        public void SetKeyFocus(bool b)
        {
            m_keyFocused = b;
        }

        /// フォーカス処理を実装する
        public void Focus()
        {
            int mx = m_pos + m_ox + (int)m_barTex.Width / 2;
            int my = y + m_oy + (int)m_barTex.Height / 2;
            controlContex.MouseInput.SetPos(mx, my);
            m_keyFocused = true;
        }

        /// スライダーバーの中にあるか？
        public bool IsIn()
        {
            int mx, my;
            controlContex.MouseInput.GetPos(out mx, out my);
            return IsCursorInButton(mx, my);
        }

        /// スライダーバーが最大になっているか？
        public bool IsMax()
        {
            return GetSlidePos() == 1.0f;
        }

        /// スライダーが最低になっているか？
        public bool IsMin()
        {
            return GetSlidePos() == 0.0f;
        }


        /// 点が矩形の内側にあるかどうか
        private static bool PointInRect(int px, int py, int left, int top, int right, int bottom)
        {
            return (bool)(px >= left && px < right && py >= top && py < bottom);
        }
        /// 引数で指定した座標はスライダーボタンの中にあるか？
        private bool IsCursorInButton(int mouseX, int mouseY)
        {
            return PointInRect(mouseX, mouseY, x, y + m_oy, x + m_sx + m_length, y + m_sy + m_oy);
        }

        #region FocusableTextureGUI メンバ

        public void Focus(ControlContext controlContext, int x, int y)
        {
            int mx = m_pos + m_ox + (int)m_barTex.Width / 2;
            int my = y + m_oy + (int)m_barTex.Height / 2;
            controlContex.MouseInput.SetPos(mx, my);
            m_keyFocused = true;
        }

        #endregion
    }
}
