/******************************************************************************
 * SunnyUI 开源控件库、工具类库、扩展类库、多页面开发框架。
 * CopyRight (C) 2012-2024 ShenYongHua(沈永华).
 * QQ群：56829229 QQ：17612584 EMail：SunnyUI@QQ.Com
 *
 * Blog:   https://www.cnblogs.com/yhuse
 * Gitee:  https://gitee.com/yhuse/SunnyUI
 * GitHub: https://github.com/yhuse/SunnyUI
 *
 * SunnyUI.dll can be used for free under the GPL-3.0 license.
 * If you use this code, please keep this note.
 * 如果您使用此代码，请保留此说明。
 ******************************************************************************
 * 文件名称: UIFlowLayoutPanel.cs
 * 文件说明: FlowLayoutPanel
 * 当前版本: V3.1
 * 创建日期: 2020-09-29
 *
 * 2020-09-29: V2.2.8 增加文件说明
 * 2021-07-10: V3.0.4 增加滚动条颜色属性 
 * 2021-07-31: V3.0.5 可像原生控件一样通过Controls.Add增加
 * 2021-08-11: V3.0.5 删除点击的Focus事件
 * 2021-10-18: V3.0.8 增加Scroll事件
 * 2021-11-05: V3.0.8 修改不同DPI缩放滚动条未覆盖的问题
 * 2022-11-03: V3.2.6 增加了可设置垂直滚动条宽度的属性
 * 2022-11-13: V3.2.8 增加滚动条背景色调整
 * 2022-11-13: V3.2.8 删除AddControl、RemoveControl方法
 * 2022-11-25: V3.2.9 增加Get方法以获取控件
 * 2023-01-11: V3.3.1 增加AutoScroll属性
 * 2023-01-11: V3.3.1 修复只显示水平滚动条时，鼠标滚轮滚动水平滚动条不动的问题
 * 2023-11-05: V3.5.2 重构主题
 * 2024-01-17: V3.6.3 重写ScrollControlIntoView函数
 * 2024-04-28: V3.6.5 增加Render方法，尝试解决点击状态栏恢复窗体后右侧滚动条未消失的问题
******************************************************************************/

using System;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Windows.Forms;

namespace Sunny.UI
{
    public class UIFlowLayoutPanel : UIPanel, IToolTip
    {
        private UIVerScrollBarEx VBar;
        private UIHorScrollBarEx HBar;
        private FlowLayoutPanel flowLayoutPanel;
        private readonly Timer timer;

        public UIFlowLayoutPanel()
        {
            InitializeComponent();
            SetStyleFlags(true, false);
            ShowText = false;

            Panel.AutoScroll = true;
            Panel.ControlAdded += Panel_ControlAdded;
            Panel.ControlRemoved += Panel_ControlRemoved;
            Panel.Scroll += Panel_Scroll;
            Panel.MouseWheel += Panel_MouseWheel;
            Panel.ClientSizeChanged += Panel_ClientSizeChanged;
            Panel.BackColor = UIStyles.Blue.PlainColor;

            VBar.ValueChanged += VBar_ValueChanged;
            HBar.ValueChanged += HBar_ValueChanged;

            SizeChanged += Panel_SizeChanged;
            timer = new Timer();
            timer.Interval = 100;
            timer.Tick += Timer_Tick;
            timer.Start();
        }

        [Browsable(false)]
        public override string[] FormTranslatorProperties => null;

        public void Render()
        {
            if (Panel == null) return;
            int height = Panel.Height;
            Panel.Height = height + 1;
            Panel.Height = height;
        }

        [DefaultValue(true)]
        [Browsable(true)]
        public new bool AutoScroll
        {
            get => Panel.AutoScroll;
            set => Panel.AutoScroll = value;
        }

        private int scrollBarWidth = 0;

        [DefaultValue(0), Category("SunnyUI"), Description("垂直滚动条宽度，最小为原生滚动条宽度")]
        public int ScrollBarWidth
        {
            get => scrollBarWidth;
            set
            {
                scrollBarWidth = value;
                SetScrollInfo();
            }
        }

        private int scrollBarHandleWidth = 6;

        [DefaultValue(6), Category("SunnyUI"), Description("垂直滚动条滑块宽度，最小为原生滚动条宽度")]
        public int ScrollBarHandleWidth
        {
            get => scrollBarHandleWidth;
            set
            {
                scrollBarHandleWidth = value;
                if (VBar != null) VBar.FillWidth = value;
            }
        }

        protected override void OnContextMenuStripChanged(EventArgs e)
        {
            base.OnContextMenuStripChanged(e);
            if (Panel != null) Panel.ContextMenuStrip = ContextMenuStrip;
        }

        /// <summary>
        /// 重载字体变更
        /// </summary>
        /// <param name="e">参数</param>
        protected override void OnFontChanged(EventArgs e)
        {
            base.OnFontChanged(e);
            if (flowLayoutPanel != null) flowLayoutPanel.Font = Font;
            if (VBar != null) VBar.Font = Font;
            if (HBar != null) HBar.Font = Font;
        }

        public new event ScrollEventHandler Scroll;

        /// <summary>
        /// 需要额外设置ToolTip的控件
        /// </summary>
        /// <returns>控件</returns>
        public Control ExToolTipControl()
        {
            return Panel;
        }

        public new void Focus()
        {
            base.Focus();
            Panel.Focus();
        }

        public override bool Focused
        {
            get => Panel.Focused;
        }

        protected override void OnEnter(EventArgs e)
        {
            base.OnEnter(e);
            Panel.Focus();
        }

        protected override void Dispose(bool disposing)
        {
            base.Dispose(disposing);
            timer?.Stop();
            timer?.Dispose();
        }

        [DefaultValue(FlowDirection.LeftToRight)]
        [Localizable(true)]
        public FlowDirection FlowDirection
        {
            get => Panel.FlowDirection;
            set => Panel.FlowDirection = value;
        }

        [DefaultValue(true)]
        [Localizable(true)]
        public bool WrapContents
        {
            get => Panel.WrapContents;
            set => Panel.WrapContents = value;
        }

        [DefaultValue(false)]
        [DisplayName("FlowBreak")]
        public bool GetFlowBreak(Control control)
        {
            return Panel.GetFlowBreak(control);
        }

        [DisplayName("FlowBreak")]
        public void SetFlowBreak(Control control, bool value)
        {
            Panel.SetFlowBreak(control, value);
        }

        protected override void OnControlAdded(ControlEventArgs e)
        {
            if (e.Control is UIHorScrollBarEx bar1)
            {
                if (bar1.TagString == "79E1E7DD-3E4D-916B-C8F1-F45B579C290C")
                {
                    base.OnControlAdded(e);
                    return;
                }
            }

            if (e.Control is UIVerScrollBarEx bar2)
            {
                if (bar2.TagString == "63FD1249-41D3-E08A-F8F5-CC41CC30FD03")
                {
                    base.OnControlAdded(e);
                    return;
                }
            }

            if (e.Control is FlowLayoutPanel panel)
            {
                if (panel.Tag.ToString() == "69605093-6397-AD32-9F69-3C29F642F87E")
                {
                    base.OnControlAdded(e);
                    return;
                }
            }

            if (Panel != null && !DesignMode)
            {
                Add(e.Control);
            }
            else
            {
                base.OnControlAdded(e);
                if (Panel != null) Panel.SendToBack();
            }
        }

        public void Remove(Control control)
        {
            if (Panel != null)
            {
                if (Panel.Controls.Contains(control))
                    Panel.Controls.Remove(control);
            }
        }

        public void Add(Control control)
        {
            Panel?.Controls.Add(control);
        }

        public void Clear()
        {
            foreach (Control control in Panel.Controls)
            {
                control.Dispose();
            }

            Panel.Controls.Clear();
        }

        [Browsable(false)]
        public ControlCollection AllControls => Panel.Controls;

        public T Get<T>(string controlName) where T : Control
        {
            return Panel.GetControls<T>()?.Where(p => p.Name == controlName).FirstOrDefault();
        }

        public Control Get(string controlName)
        {
            return Panel.Controls.ContainsKey(controlName) ? Panel.Controls[controlName] : null;
        }

        public Control Get(int index)
        {
            return (index >= 0 && index < Panel.Controls.Count) ? Panel.Controls[index] : null;
        }

        [Browsable(false)]
        public int ControlCount => AllControls.Count;

        [Browsable(false)]
        public Control this[string controlName]
        {
            get => Get(controlName);
        }

        [Browsable(false)]
        public Control this[int index]
        {
            get => Get(index);
        }

        private void Timer_Tick(object sender, EventArgs e)
        {
            if (VBar.Maximum != Panel.VerticalScroll.Maximum ||
                VBar.Visible != Panel.VerticalScroll.Visible ||
                HBar.Maximum != Panel.HorizontalScroll.Maximum ||
                HBar.Visible != Panel.HorizontalScroll.Visible)
            {
                SetScrollInfo();
            }
        }

        private void Panel_ClientSizeChanged(object sender, EventArgs e)
        {
            SetScrollInfo();
        }

        [Browsable(false)]
        public FlowLayoutPanel FlowLayoutPanel => flowLayoutPanel;

        /// <summary>
        /// 绘制前景颜色
        /// </summary>
        /// <param name="g">绘图图面</param>
        /// <param name="path">绘图路径</param>
        protected override void OnPaintFore(Graphics g, GraphicsPath path)
        {
        }

        //public override void SetInheritedStyle(UIStyle style)
        //{
        //    UIStyleHelper.SetChildUIStyle(this, style);
        //    base.SetInheritedStyle(style);
        //}

        /// <summary>
        /// 设置主题样式
        /// </summary>
        /// <param name="uiColor">主题样式</param>
        public override void SetStyleColor(UIBaseStyle uiColor)
        {
            base.SetStyleColor(uiColor);
            Panel.BackColor = uiColor.PlainColor;

            if (HBar != null && HBar.Style == UIStyle.Inherited)
            {
                HBar.ForeColor = uiColor.GridBarForeColor;
                HBar.HoverColor = uiColor.ButtonFillHoverColor;
                HBar.PressColor = uiColor.ButtonFillPressColor;
                HBar.FillColor = uiColor.GridBarFillColor;
                scrollBarColor = uiColor.GridBarForeColor;
                scrollBarBackColor = uiColor.GridBarFillColor;
            }

            if (VBar != null && VBar.Style == UIStyle.Inherited)
            {
                VBar.ForeColor = uiColor.GridBarForeColor;
                VBar.HoverColor = uiColor.ButtonFillHoverColor;
                VBar.PressColor = uiColor.ButtonFillPressColor;
                VBar.FillColor = uiColor.GridBarFillColor;
                scrollBarColor = uiColor.GridBarForeColor;
                scrollBarBackColor = uiColor.GridBarFillColor;
            }
        }

        protected override void AfterSetFillColor(Color color)
        {
            base.AfterSetFillColor(color);
            Panel.BackColor = color;
        }

        private Color scrollBarColor = Color.FromArgb(80, 160, 255);

        /// <summary>
        /// 填充颜色，当值为背景色或透明色或空值则不填充
        /// </summary>
        [Description("滚动条填充颜色"), Category("SunnyUI")]
        [DefaultValue(typeof(Color), "80, 160, 255")]
        public Color ScrollBarColor
        {
            get => scrollBarColor;
            set
            {
                scrollBarColor = value;
                HBar.HoverColor = HBar.PressColor = HBar.ForeColor = value;
                VBar.HoverColor = VBar.PressColor = VBar.ForeColor = value;
                HBar.Style = VBar.Style = UIStyle.Custom;
                Invalidate();
            }
        }

        private Color scrollBarBackColor = Color.FromArgb(243, 249, 255);

        /// <summary>
        /// 填充颜色，当值为背景色或透明色或空值则不填充
        /// </summary>
        [Description("滚动条背景颜色"), Category("SunnyUI")]
        [DefaultValue(typeof(Color), "243, 249, 255")]
        public Color ScrollBarBackColor
        {
            get => scrollBarBackColor;
            set
            {
                scrollBarBackColor = value;
                HBar.FillColor = value;
                VBar.FillColor = value;
                HBar.Style = VBar.Style = UIStyle.Custom;
                Invalidate();
            }
        }

        /// <summary>
        /// 滚动条主题样式
        /// </summary>
        [DefaultValue(true), Description("滚动条主题样式"), Category("SunnyUI")]
        public bool ScrollBarStyleInherited
        {
            get => HBar != null && HBar.Style == UIStyle.Inherited;
            set
            {
                if (value)
                {
                    if (HBar != null) HBar.Style = UIStyle.Inherited;
                    if (VBar != null) VBar.Style = UIStyle.Inherited;

                    scrollBarColor = UIStyles.Blue.GridBarForeColor;
                    scrollBarBackColor = UIStyles.Blue.GridBarFillColor;
                }

            }
        }

        protected override void OnGotFocus(EventArgs e)
        {
            base.OnGotFocus(e);
            Panel.Focus();
        }

        /// <summary>
        /// 重载鼠标进入事件
        /// </summary>
        /// <param name="e">鼠标参数</param>
        protected override void OnMouseEnter(EventArgs e)
        {
            base.OnMouseEnter(e);
            Panel.Focus();
        }

        private void Panel_MouseWheel(object sender, MouseEventArgs e)
        {
            //if (e.Delta < 0)
            //{
            //    if (Panel.VerticalScroll.Maximum > Panel.VerticalScroll.Value + 50)
            //        Panel.VerticalScroll.Value += 50;
            //    else
            //        Panel.VerticalScroll.Value = Panel.VerticalScroll.Maximum;
            //}
            //else
            //{
            //    if (Panel.VerticalScroll.Value > 50)
            //        Panel.VerticalScroll.Value -= 50;
            //    else
            //        Panel.VerticalScroll.Value = 0;
            //}

            VBar.Value = Panel.VerticalScroll.Value;
            HBar.Value = Panel.HorizontalScroll.Value;
        }

        private void VBar_ValueChanged(object sender, EventArgs e)
        {
            if (VBar.Value.InRange(0, Panel.VerticalScroll.Maximum))
                Panel.VerticalScroll.Value = VBar.Value;
        }

        private void HBar_ValueChanged(object sender, EventArgs e)
        {
            Panel.HorizontalScroll.Value = HBar.Value;
        }

        private void Panel_Scroll(object sender, ScrollEventArgs e)
        {
            Scroll?.Invoke(this, e);
            VBar.Value = Panel.VerticalScroll.Value;
        }

        private void Panel_SizeChanged(object sender, EventArgs e)
        {
            SetScrollInfo();
        }

        private void Panel_ControlRemoved(object sender, ControlEventArgs e)
        {
            SetScrollInfo();
        }

        private void Panel_ControlAdded(object sender, ControlEventArgs e)
        {
            SetScrollInfo();
        }

        public void SetScrollInfo()
        {
            VBar.Visible = Panel.VerticalScroll.Visible;
            VBar.Maximum = Panel.VerticalScroll.Maximum;
            VBar.Value = Panel.VerticalScroll.Value;
            VBar.LargeChange = Panel.VerticalScroll.LargeChange;
            VBar.BoundsHeight = Panel.VerticalScroll.LargeChange;

            HBar.Visible = Panel.HorizontalScroll.Visible;
            HBar.Maximum = Panel.HorizontalScroll.Maximum;
            HBar.Value = Panel.HorizontalScroll.Value;
            HBar.LargeChange = Panel.HorizontalScroll.LargeChange;
            HBar.BoundsWidth = Panel.HorizontalScroll.LargeChange;

            SetScrollPos();
        }
        public FlowLayoutPanel Panel => flowLayoutPanel;

        private void InitializeComponent()
        {
            flowLayoutPanel = new FlowLayoutPanel();
            VBar = new UIVerScrollBarEx();
            HBar = new UIHorScrollBarEx();
            SuspendLayout();
            // 
            // flowLayoutPanel
            // 
            flowLayoutPanel.BackColor = Color.FromArgb(235, 243, 255);
            flowLayoutPanel.Dock = DockStyle.Fill;
            flowLayoutPanel.Location = new Point(2, 2);
            flowLayoutPanel.Name = "flowLayoutPanel";
            flowLayoutPanel.Size = new Size(429, 383);
            flowLayoutPanel.TabIndex = 0;
            flowLayoutPanel.Tag = "69605093-6397-AD32-9F69-3C29F642F87E";
            // 
            // VBar
            // 
            VBar.Font = new Font("宋体", 12F);
            VBar.Location = new Point(410, 5);
            VBar.MinimumSize = new Size(1, 1);
            VBar.Name = "VBar";
            VBar.Size = new Size(18, 377);
            VBar.TabIndex = 1;
            VBar.TagString = "63FD1249-41D3-E08A-F8F5-CC41CC30FD03";
            VBar.Text = "uiVerScrollBarEx1";
            VBar.Visible = false;
            // 
            // HBar
            // 
            HBar.Font = new Font("宋体", 12F);
            HBar.Location = new Point(5, 364);
            HBar.MinimumSize = new Size(1, 1);
            HBar.Name = "HBar";
            HBar.Size = new Size(399, 18);
            HBar.TabIndex = 2;
            HBar.TagString = "79E1E7DD-3E4D-916B-C8F1-F45B579C290C";
            HBar.Text = "uiHorScrollBarEx1";
            HBar.Visible = false;
            // 
            // UIFlowLayoutPanel
            // 
            Controls.Add(HBar);
            Controls.Add(VBar);
            Controls.Add(flowLayoutPanel);
            Name = "UIFlowLayoutPanel";
            Padding = new Padding(2);
            Size = new Size(433, 387);
            ResumeLayout(false);
        }

        /// <summary>
        /// 重载控件尺寸变更
        /// </summary>
        /// <param name="e">参数</param>
        protected override void OnSizeChanged(EventArgs e)
        {
            base.OnSizeChanged(e);
            SetScrollPos();
        }

        private void SetScrollPos()
        {
            if (VBar != null && HBar != null)
            {
                int added = 1;
                if (RadiusSides != UICornerRadiusSides.None)
                {
                    added = Radius / 2;
                }

                int barWidth = Math.Max(ScrollBarInfo.VerticalScrollBarWidth(), ScrollBarWidth);
                VBar.Width = barWidth;
                VBar.Left = Width - barWidth - added;
                VBar.Top = added;
                VBar.Height = Height - added * 2;

                HBar.Height = ScrollBarInfo.HorizontalScrollBarHeight();
                HBar.Left = added;
                HBar.Top = Height - HBar.Height - added;

                if (VBar.Visible)
                    HBar.Width = VBar.Left - 1 - added;
                else
                    HBar.Width = Width - added * 2;
            }
        }

        public new void ScrollControlIntoView(Control activeControl)
        {
            Panel.ScrollControlIntoView(activeControl);
        }
    }
}
