/******************************************************************************
 * 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.
 * 如果您使用此代码，请保留此说明。
 ******************************************************************************
 * 文件名称: UIEditForm.cs
 * 文件说明: 编辑窗体基类
 * 当前版本: V3.1
 * 创建日期: 2020-01-01
 *
 * 2020-01-01: V2.2.0 增加文件说明
 * 2021-04-26: V3.0.3 代码生成增加Switch类型，代码生成增加Combobox类型
 * 2021-05-19: V3.0.3 动态生成表单，增加校验方法 
 * 2021-10-26: V3.0.8 代码生成增加ComboTreeView类型
 * 2021-10-28: V3.0.8 代码生成增加ComboCheckedListBox类型
 * 2022-04-18: V3.1.5 修改一处Show引起的无法获取控件值的问题
 * 2023-04-23: V3.3.5 代码生成增加，Double类型增加小数点位数
 * 2023-07-27: V3.4.1 默认提示弹窗TopMost为true
 * 2023-10-31: V3.5.2 代码生成增加ComboDataGridView类型
 * 2024-08-02: V3.6.8 代码生成增加文件选择和文件夹选择功能
******************************************************************************/

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Windows.Forms;

namespace Sunny.UI
{
    public partial class UIEditForm : UIForm
    {
        public UIEditForm()
        {
            InitializeComponent();

            btnOK.Text = UIStyles.CurrentResources.OK;
            btnCancel.Text = UIStyles.CurrentResources.Cancel;
            base.TopMost = true;
        }

        private readonly UIEditOption Option;

        private void InitEditor()
        {
            if (Option == null || Option.Infos.Count == 0) return;

            base.Text = Option.Text;
            int top = 55;

            List<Control> ctrls = new List<Control>();

            if (Option.AutoLabelWidth)
            {
                int size = 0;
                foreach (var info in Option.Infos)
                {
                    Size sf = TextRenderer.MeasureText(info.Text, Font);
                    size = Math.Max(sf.Width, size);
                }

                Option.LabelWidth = size + 1 + 50;
            }

            Width = Option.LabelWidth + Option.ValueWidth + 28;

            foreach (var info in Option.Infos)
            {
                UILabel label = new UILabel();
                label.Text = info.Text;
                label.AutoSize = false;
                label.Left = 5;
                label.Width = Option.LabelWidth - 25;
                label.Height = 29;
                label.Top = top;
                label.TextAlign = ContentAlignment.MiddleRight;
                label.Parent = this;

                Control ctrl = null;

                if (info.EditType == EditType.Text)
                {
                    ctrl = new UITextBox();
                    var edit = (UITextBox)ctrl;
                    edit.Text = info.Value?.ToString();
                    edit.EnterAsTab = true;
                }

                if (info.EditType == EditType.FileSelect)
                {
                    ctrl = new UITextBox();
                    var edit = (UITextBox)ctrl;
                    edit.ShowButton = true;
                    edit.ButtonSymbol = 261788;
                    edit.ButtonSymbolSize = 22;
                    edit.ButtonSymbolOffset = new Point(1, 1);
                    edit.Text = info.Value?.ToString();
                    edit.EnterAsTab = true;
                    edit.ButtonClick += Edit_FileButtonClick;
                }

                if (info.EditType == EditType.DirSelect)
                {
                    ctrl = new UITextBox();
                    var edit = (UITextBox)ctrl;
                    edit.ShowButton = true;
                    edit.ButtonSymbol = 61717;
                    edit.ButtonSymbolOffset = new Point(2, 0);
                    edit.Text = info.Value?.ToString();
                    edit.EnterAsTab = true;
                    edit.ButtonClick += Dir_FileButtonClick;
                }

                if (info.EditType == EditType.Password)
                {
                    ctrl = new UITextBox();
                    var edit = (UITextBox)ctrl;
                    edit.Text = info.Value?.ToString();
                    edit.PasswordChar = '*';
                    edit.EnterAsTab = true;
                }

                if (info.EditType == EditType.Integer)
                {
                    ctrl = new UITextBox();
                    var edit = (UITextBox)ctrl;
                    edit.Type = UITextBox.UIEditType.Integer;
                    edit.IntValue = info.Value.ToString().ToInt();
                    edit.EnterAsTab = true;
                }

                if (info.EditType == EditType.Double)
                {
                    ctrl = new UITextBox();
                    var edit = (UITextBox)ctrl;
                    edit.DecimalPlaces = info.DecimalPlaces;
                    edit.Type = UITextBox.UIEditType.Double;
                    edit.DoubleValue = info.Value.ToString().ToDouble();
                    edit.EnterAsTab = true;
                }

                if (info.EditType == EditType.Date)
                {
                    ctrl = new UIDatePicker();
                    var edit = (UIDatePicker)ctrl;
                    edit.Value = (DateTime)info.Value;
                }

                if (info.EditType == EditType.DateTime)
                {
                    ctrl = new UIDatetimePicker();
                    var edit = (UIDatetimePicker)ctrl;
                    edit.Value = (DateTime)info.Value;
                }

                if (info.EditType == EditType.Switch)
                {
                    ctrl = new UISwitch();
                    var edit = (UISwitch)ctrl;
                    edit.SwitchShape = UISwitch.UISwitchShape.Square;
                    edit.Height = 29;
                    edit.Active = (bool)info.Value;

                    if (info.DataSource != null)
                    {
                        string[] items = (string[])info.DataSource;
                        edit.ActiveText = items[0];
                        edit.InActiveText = items[1];
                        Size sf1 = TextRenderer.MeasureText(items[0], edit.Font);
                        Size sf2 = TextRenderer.MeasureText(items[0], edit.Font);
                        edit.Width = Math.Max(sf1.Width, sf2.Width) + edit.Height + 16;
                    }
                }

                if (info.EditType == EditType.Combobox)
                {
                    ctrl = new UIComboBox();
                    var edit = (UIComboBox)ctrl;
                    edit.DropDownStyle = UIDropDownStyle.DropDownList;

                    if (info.DisplayMember.IsNullOrEmpty())
                    {
                        object[] items = (object[])info.DataSource;
                        if (items != null)
                        {
                            edit.Items.AddRange(items);
                            int index = info.Value.ToString().ToInt();
                            if (index < items.Length)
                                edit.SelectedIndex = index;
                        }
                    }
                    else
                    {
                        edit.DisplayMember = info.DisplayMember;
                        edit.ValueMember = info.ValueMember;
                        edit.DataSource = info.DataSource;
                        edit.SelectedValue = info.Value;
                    }
                }

                if (info.EditType == EditType.ComboTreeView)
                {
                    ctrl = new UIComboTreeView();
                    var edit = (UIComboTreeView)ctrl;
                    edit.CanSelectRootNode = true;
                    edit.ShowLines = true;
                    edit.DropDownStyle = UIDropDownStyle.DropDownList;
                    edit.TreeView.Nodes.Clear();
                    edit.TreeView.Nodes.AddRange((TreeNode[])info.DataSource);
                    if (info.Value != null)
                    {
                        edit.TreeView.SelectedNode = (TreeNode)info.Value;
                        edit.Text = edit.TreeView.SelectedNode.Text;
                    }
                }

                if (info.EditType == EditType.ComboCheckedListBox)
                {
                    ctrl = new UIComboTreeView();
                    var edit = (UIComboTreeView)ctrl;
                    edit.CanSelectRootNode = true;
                    edit.CheckBoxes = true;
                    edit.DropDownStyle = UIDropDownStyle.DropDownList;
                    edit.TreeView.Nodes.Clear();
                    edit.Text = info.Value?.ToString();
                    var obj = (ComboCheckedListBoxItem[])info.DataSource;
                    foreach (var item in obj)
                    {
                        TreeNode node = edit.TreeView.Nodes.Add(item.Text);
                        node.Tag = item;
                        node.Checked = item.Checked;
                    }
                }

                if (info.EditType == EditType.ComboDataGridView)
                {
                    ctrl = new UIComboDataGridView();
                    var edit = (UIComboDataGridView)ctrl;
                    edit.DataGridView.Init();
                    edit.DataGridView.AutoGenerateColumns = true;
                    var obj = (DataTable)info.DataSource;
                    edit.DataGridView.DataSource = obj;
                    edit.DataGridView.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
                    foreach (DataGridViewColumn item in edit.DataGridView.Columns)
                    {
                        item.ReadOnly = true;
                    }

                    edit.SelectIndexChange += Edit_SelectIndexChange;
                    int index = (int)info.Value;
                    if (index >= 0)
                    {
                        edit.DataGridView.SelectedIndex = index;
                        edit.Text = obj.Rows[index][info.DisplayMember].ToString();
                    }
                }

                if (ctrl != null)
                {
                    ctrl.Left = Option.LabelWidth;
                    if (info.EditType != EditType.Switch)
                        ctrl.Width = info.HalfWidth ? Option.ValueWidth / 2 : Option.ValueWidth;
                    ctrl.Top = top;
                    ctrl.Parent = this;
                    ctrl.Name = "Edit_" + info.DataPropertyName;
                    ctrl.Enabled = info.Enabled;
                    ctrls.Add(ctrl);
                }

                top += 29 + 10;
            }

            pnlBtm.BringToFront();
            Height = top + 10 + 55;

            int tabIndex = 0;
            foreach (var ctrl in ctrls)
            {
                ctrl.TabIndex = tabIndex;
                tabIndex++;
            }

            pnlBtm.TabIndex = tabIndex;
            tabIndex++;
            btnOK.TabIndex = tabIndex;
            tabIndex++;
            btnCancel.TabIndex = tabIndex;
            btnOK.ShowFocusLine = btnCancel.ShowFocusLine = true;
        }

        private void Edit_FileButtonClick(object sender, EventArgs e)
        {
            UITextBox edit = (UITextBox)sender;
            string filename = edit.Text;
            var info = Option.Dictionary[edit.Name.Replace("Edit_", "")];
            if (FileEx.OpenDialog(ref filename, info.DisplayMember, info.ValueMember))
            {
                edit.Text = filename;
            }
        }

        private void Dir_FileButtonClick(object sender, EventArgs e)
        {
            UITextBox edit = (UITextBox)sender;
            string dirname = edit.Text;
            var info = Option.Dictionary[edit.Name.Replace("Edit_", "")];
            if (DirEx.SelectDirEx(info.DisplayMember, ref dirname))
            {
                edit.Text = dirname;
            }
        }

        private void Edit_SelectIndexChange(object sender, int index)
        {
            UIComboDataGridView edit = (UIComboDataGridView)sender;
            var info = Option.Dictionary[edit.Name.Replace("Edit_", "")];
            var obj = (DataTable)info.DataSource;
            edit.Text = obj.Rows[index][info.DisplayMember].ToString();
        }

        public UIEditForm(UIEditOption option)
        {
            InitializeComponent();

            btnOK.Text = UIStyles.CurrentResources.OK;
            btnCancel.Text = UIStyles.CurrentResources.Cancel;
            base.TopMost = true;

            Option = option;
            InitEditor();
        }

        public bool ExistsDataPropertyName(string dataPropertyName) => Option != null && Option.ExistsDataPropertyName(dataPropertyName);

        public object this[string dataPropertyName]
        {
            get
            {
                if (Option == null)
                {
                    throw new ArgumentNullException();
                }

                if (!Option.Dictionary.ContainsKey(dataPropertyName))
                {
                    throw new ArgumentOutOfRangeException();
                }

                return Option.Dictionary[dataPropertyName].Value;
            }
        }

        public bool IsOK { get; protected set; }

        [Category("SunnyUI"), Description("确定按钮点击事件")]
        public event EventHandler ButtonOkClick;

        [Category("SunnyUI"), Description("取消按钮点击事件")]
        public event EventHandler ButtonCancelClick;

        [Description("确定按钮可用状态"), Category("SunnyUI")]
        [DefaultValue(true)]
        public bool ButtonOKEnabled
        {
            get => btnOK.Enabled;
            set => btnOK.Enabled = value;
        }

        [Description("取消按钮可用状态"), Category("SunnyUI")]
        [DefaultValue(true)]
        public bool ButtonCancelEnabled
        {
            get => btnCancel.Enabled;
            set => btnCancel.Enabled = value;
        }

        private void btnOK_Click(object sender, EventArgs e)
        {
            if (!CheckData())
            {
                return;
            }
            else
            {
                DialogResult = DialogResult.OK;
                IsOK = true;
            }

            if (CheckedData != null)
            {
                if (!CheckedData.Invoke(this, new EditFormEventArgs(this)))
                {
                    DialogResult = DialogResult.None;
                    IsOK = false;
                    return;
                }
                else
                {
                    DialogResult = DialogResult.OK;
                    IsOK = true;
                }
            }

            if (ButtonOkClick != null)
            {
                DialogResult = DialogResult.None;
                IsOK = false;
                ButtonOkClick.Invoke(sender, e);
            }
        }

        private void btnCancel_Click(object sender, EventArgs e)
        {
            if (ButtonCancelClick != null)
            {
                ButtonCancelClick.Invoke(sender, e);
            }
            else
            {
                DialogResult = DialogResult.Cancel;
                IsOK = false;
                Close();
            }
        }

        public void SetEditorFocus(string dataPropertyName)
        {
            Control editor = this.GetControl<UITextBox>("Edit_" + dataPropertyName);
            if (editor != null)
                editor.Focus();
        }

        protected virtual bool CheckData()
        {
            if (Option != null)
            {
                foreach (var info in Option.Infos)
                {
                    if (info.EditType == EditType.Text || info.EditType == EditType.Password ||
                        info.EditType == EditType.FileSelect || info.EditType == EditType.DirSelect)
                    {
                        UITextBox edit = this.GetControl<UITextBox>("Edit_" + info.DataPropertyName);
                        if (edit == null) continue;

                        if (info.CheckEmpty && edit.Text.IsNullOrEmpty())
                        {
                            this.ShowWarningTip(edit, info.Text + Environment.NewLine + UIStyles.CurrentResources.EditorCantEmpty);
                            edit.Focus();
                            return false;
                        }

                        info.Value = edit.Text;
                    }

                    if (info.EditType == EditType.Integer)
                    {
                        UITextBox edit = this.GetControl<UITextBox>("Edit_" + info.DataPropertyName);
                        if (edit == null) continue;
                        info.Value = edit.IntValue;
                    }

                    if (info.EditType == EditType.Double)
                    {
                        UITextBox edit = this.GetControl<UITextBox>("Edit_" + info.DataPropertyName);
                        if (edit == null) continue;
                        info.Value = edit.DoubleValue;
                    }

                    if (info.EditType == EditType.Date)
                    {
                        UIDatePicker edit = this.GetControl<UIDatePicker>("Edit_" + info.DataPropertyName);
                        if (edit == null) continue;
                        info.Value = edit.Value.Date;
                    }

                    if (info.EditType == EditType.DateTime)
                    {
                        UIDatetimePicker edit = this.GetControl<UIDatetimePicker>("Edit_" + info.DataPropertyName);
                        if (edit == null) continue;
                        info.Value = edit.Value;
                    }

                    if (info.EditType == EditType.Combobox)
                    {
                        UIComboBox edit = this.GetControl<UIComboBox>("Edit_" + info.DataPropertyName);
                        if (edit == null) continue;
                        info.Value = edit.ValueMember.IsValid() ? edit.SelectedValue : edit.SelectedIndex;
                    }

                    if (info.EditType == EditType.Switch)
                    {
                        UISwitch edit = this.GetControl<UISwitch>("Edit_" + info.DataPropertyName);
                        if (edit == null) continue;
                        info.Value = edit.Active;
                    }

                    if (info.EditType == EditType.ComboTreeView)
                    {
                        UIComboTreeView edit = this.GetControl<UIComboTreeView>("Edit_" + info.DataPropertyName);
                        if (edit == null) continue;
                        info.Value = edit.TreeView.SelectedNode;
                    }

                    if (info.EditType == EditType.ComboCheckedListBox)
                    {
                        UIComboTreeView edit = this.GetControl<UIComboTreeView>("Edit_" + info.DataPropertyName);
                        if (edit == null) continue;
                        List<ComboCheckedListBoxItem> result = new List<ComboCheckedListBoxItem>();
                        foreach (TreeNode item in edit.Nodes)
                        {
                            ComboCheckedListBoxItem obj = (ComboCheckedListBoxItem)item.Tag;
                            obj.Checked = item.Checked;
                            if (obj.Checked) result.Add(obj);
                        }

                        info.Value = result.ToArray();
                    }

                    if (info.EditType == EditType.ComboDataGridView)
                    {
                        UIComboDataGridView edit = this.GetControl<UIComboDataGridView>("Edit_" + info.DataPropertyName);
                        if (edit == null) continue;
                        info.Value = edit.DataGridView.SelectedIndex;
                    }
                }
            }

            return true;
        }

        public delegate bool OnCheckedData(object sender, EditFormEventArgs e);

        public event OnCheckedData CheckedData;

        public class EditFormEventArgs : EventArgs
        {
            public EditFormEventArgs()
            {

            }

            public EditFormEventArgs(UIEditForm editor)
            {
                Form = editor;
            }

            public UIEditForm Form { get; set; }
        }

        /// <summary>
        /// 重载控件尺寸变更
        /// </summary>
        /// <param name="e">参数</param>
        protected override void OnSizeChanged(EventArgs e)
        {
            base.OnSizeChanged(e);
            if (btnOK != null && btnCancel != null)
            {
                btnCancel.Left = Width - 130;
                btnOK.Left = Width - 245;
            }
        }

        protected bool CheckEmpty(UITextBox edit, string desc)
        {
            bool result = edit.Text.IsValid();
            if (!result)
            {
                this.ShowWarningDialog(desc);
                edit.Focus();
            }

            return result;
        }

        protected bool CheckRange(UITextBox edit, int min, int max, string desc)
        {
            bool result = edit.IntValue >= min && edit.IntValue <= max;
            if (!result)
            {
                this.ShowWarningDialog(desc);
                edit.Focus();
            }

            return result;
        }

        protected bool CheckRange(UITextBox edit, double min, double max, string desc)
        {
            bool result = edit.DoubleValue >= min && edit.DoubleValue <= max;
            if (!result)
            {
                this.ShowWarningDialog(desc);
                edit.Focus();
            }

            return result;
        }

        protected bool CheckEmpty(UIComboBox edit, string desc)
        {
            bool result = edit.Text.IsValid();
            if (!result)
            {
                this.ShowWarningDialog(desc);
                edit.Focus();
            }

            return result;
        }

        protected bool CheckEmpty(UIDatePicker edit, string desc)
        {
            bool result = edit.Text.IsValid();
            if (!result)
            {
                this.ShowWarningDialog(desc);
                edit.Focus();
            }

            return result;
        }
    }
}