using CloudBuilder.Gui.DependencyInjection;
using Krypton.Toolkit;
using Microsoft.AspNetCore.Authorization;
using Microsoft.Extensions.DependencyInjection;
using System.Collections;
using System.Collections.Concurrent;
using System.ComponentModel;
using System.Data;
using System.Data.SqlTypes;
using System.Globalization;
using System.Reflection;

namespace CloudBuilder.Gui
{
    public class GuiBindingContext
    {
        private List<Control> bindingControls = new List<Control>();
        private BindingContextAttributeProvider provider = null!;
        public object BindingObject;

        public GuiBindingContext()
        {
        }

        private static BindingContextAttributeProvider GetProvider()
        {
            return ServiceHelper.GetService<BindingContextAttributeProvider>() ??
        throw new InvalidOperationException("BindingContextAttributeProvider is not registered in the service GetProvider().");
        }

        public void BindingControls(params IComponent[] cc)
        {
            foreach (IComponent c in cc)
            {
                BindingControls(c);
            }
        }

        public void BindingControls(List<IComponent> cc)
        {
            BindingControls(cc.ToArray());
        }

        public void BindingControls(IComponent c)
        {
            if (!(c is Control)) return;
            if (provider == null) provider = GetProvider();
            if (provider.HasCustomAttribute((Control)c) && !bindingControls.Contains((Control)c))
            {
                bindingControls.Add((Control)c);
                return;
            }

            BindingControls(((Control)c).Controls);
        }

        public void BindingControls(Control.ControlCollection cc)
        {
            IEnumerator enumerator = cc.GetEnumerator();
            while (enumerator.MoveNext())
            {
                Control current = (Control)enumerator.Current;
                BindingControls(current);
            }
        }


        public void DataBind(object o, AbstractForm page)
        {
            BindingControls(page.Controls);
            DataBind(o);
        }

        public void DataBind(object o, AbstractPage page)
        {
            BindingControls(page.Controls);
            DataBind(o);
        }

        public void DataBind(object o)
        {
            if (o == null) return;

            BindingObject = o;
            provider = GetProvider();
            BindingContextCustomAttribute customAttribute = null;
            foreach (Control c in bindingControls)
            {
                customAttribute = provider.GetCustomAttribute(c);
                if (customAttribute == null) continue;
                //權限綁定時，是沒有BindDataName值的
                if (string.IsNullOrEmpty(customAttribute.BindDataName)) continue;
                //只寫和None,不綁定值
                if (customAttribute.BindDirection == EnumBindDirection.None || customAttribute.BindDirection == EnumBindDirection.WriteOnly) continue;

                PropertyInfo pi = BindingObject.GetType().GetProperty(customAttribute.BindDataName);

                if (pi == null) continue;

                var value = pi.GetValue(BindingObject, null);

                SetValue(c, value, customAttribute.BindFormat);
            }
        }

        public void ResetColor()
        {
            foreach (Control c in bindingControls)
            {
                if (!(c is TextBox)) continue;

                //if (System.Drawing.SystemColors.Desktop == customAttribute.BackColor) continue;

                if (!(c is Control)) continue;

                ((Control)c).BackColor = System.Drawing.SystemColors.Control;
            }
        }

        public void DataPack()
        {
            if (BindingObject == null) return;
            if (bindingControls == null || bindingControls.Count == 0) return;

            object value = null;
            BindingContextCustomAttribute customAttribute = null;

            foreach (Control c in bindingControls)
            {
                customAttribute = provider.GetCustomAttribute(c);

                if (customAttribute == null) continue;

                //權限綁定時，是沒有BindDataName值的
                if (string.IsNullOrEmpty(customAttribute.BindDataName)) continue;
                //只读和None,不綁定值 
                if (customAttribute.BindDirection == EnumBindDirection.ReadOnly || customAttribute.BindDirection == EnumBindDirection.None) continue;

                PropertyInfo pi = BindingObject.GetType().GetProperty(customAttribute.BindDataName);

                if (pi == null) continue;

                value = GetValue(c, pi.PropertyType.Name, customAttribute.BindFormat);

                //if (value is string && "[continue][N/A]" == (Convert.ToString(value))) continue;//ExRadioButton

                pi.SetValue(BindingObject, value, null);
            }
        }


        public void SetValue(Control c, object value, string bindFormat)
        {
            BindingContextCustomAttribute customAttribute = provider.GetCustomAttribute(c);
            if (c is KryptonTextBox)
            {
                ((KryptonTextBox)c).SetValue(value, customAttribute.BindFormat);
            }
            else if (c is KryptonComboBox)
            {
                ((KryptonComboBox)c).SetValue(value);
            }
            else if (c is KryptonCheckBox)
            {
                ((KryptonCheckBox)c).SetValue(value);
            }
            else if (c is KryptonDateTimePicker)
            {
                ((KryptonDateTimePicker)c).SetValue(value, customAttribute.BindFormat);
            }
            if (c is KryptonMaskedTextBox)
            {
                ((KryptonMaskedTextBox)c).SetValue(value, customAttribute.BindFormat);
            }
            if (c is KryptonCheckedListBox)
            {
                ((KryptonCheckedListBox)c).SetValue(QuotedString.DelimiteredListToArray((string)value));
            }
            if (c is KryptonListBox)
            {
                ((KryptonListBox)c).SetValue(QuotedString.DelimiteredListToArray((string)value));
            }
            else if (c is KryptonRadioButton)
            {
                ((KryptonRadioButton)c).SetValue(value);
            }
        }
        public object GetValue(Control c, string type, string bindFormat)
        {
            if (c is KryptonTextBox)
            {
                if (type.ToLower() == "string")
                {
                    return ((KryptonTextBox)c).Text.Trim();
                }
                else if (type.ToLower() == "nullable`1" || type.ToLower() == "datetime" || type.ToLower() == "sqldatetime")
                {
                    if (type.ToLower() == "datetime" && string.IsNullOrEmpty(((KryptonTextBox)c).Text))
                        return DBNull.Value;
                    else if (type.ToLower() == "sqldatetime" && string.IsNullOrEmpty(((KryptonTextBox)c).Text))
                        return SqlDateTime.Null;
                    else
                        if (!string.IsNullOrEmpty(bindFormat))
                        return DateTime.ParseExact(((KryptonTextBox)c).Text.Trim(), bindFormat, CultureInfo.InvariantCulture, DateTimeStyles.None);
                    else
                        return DateTime.Parse(((KryptonTextBox)c).Text.Trim(), CultureInfo.InvariantCulture, DateTimeStyles.None);
                }
                else if (type.ToLower() == "decimal")
                {
                    if (string.IsNullOrEmpty(((KryptonTextBox)c).Text))
                        return 0m;
                    if (!string.IsNullOrEmpty(bindFormat))
                        return Decimal.Parse(Convert.ToDecimal(((KryptonTextBox)c).Text).ToString(bindFormat));
                    else
                        return Convert.ToDecimal(((KryptonTextBox)c).Text);
                }
                else if (type.ToLower() == "int" || type.ToLower() == "int32" || type.ToLower() == "int16")
                {
                    if (string.IsNullOrEmpty(((KryptonTextBox)c).Text))
                        return 0;
                    return Convert.ToInt32(Convert.ToDecimal(((KryptonTextBox)c).Text));
                }
                else if (type.ToLower() == "int64")
                {
                    if (string.IsNullOrEmpty(((KryptonTextBox)c).Text))
                        return 0;
                    return Convert.ToInt64(Convert.ToDecimal(((KryptonTextBox)c).Text));
                }
                else if (type.ToLower() == "double" || type.ToLower() == "float")
                {
                    if (string.IsNullOrEmpty(((KryptonTextBox)c).Text))
                        return 0;
                    return Convert.ToDouble(((KryptonTextBox)c).Text);
                }
            }
            else if (c is KryptonComboBox)
            {
                if (((KryptonComboBox)c).SelectedValue == null) return null;

                if (type.ToLower() == "string")
                {
                    return ((KryptonComboBox)c).SelectedValue.ToString();
                }
                else if (type.ToLower() == "decimal")
                {
                    if (string.IsNullOrEmpty((string)((KryptonComboBox)c).SelectedValue)) return 0m;

                    if (!string.IsNullOrEmpty(bindFormat))
                        return Decimal.Parse(Convert.ToDecimal(((KryptonComboBox)c).SelectedValue).ToString(bindFormat));
                    else
                        return Convert.ToDecimal(((KryptonComboBox)c).SelectedValue);
                }
                else if (type.ToLower() == "int" || type.ToLower() == "int32" || type.ToLower() == "int16")
                {
                    if (string.IsNullOrEmpty((string)((KryptonComboBox)c).SelectedValue)) return 0;

                    return Convert.ToInt32(Convert.ToDecimal(((KryptonComboBox)c).SelectedValue));
                }
                else if (type.ToLower() == "int64")
                {
                    if (string.IsNullOrEmpty((string)((KryptonComboBox)c).SelectedValue)) return 0;

                    return Convert.ToInt64(Convert.ToDecimal(((KryptonComboBox)c).SelectedValue));
                }
                else if (type.ToLower() == "double" || type.ToLower() == "float")
                {
                    if (string.IsNullOrEmpty((string)((KryptonComboBox)c).SelectedValue)) return 0;

                    return Convert.ToDouble(((KryptonComboBox)c).SelectedValue);
                }
            }
            else if (c is KryptonCheckBox)
            {
                if (type.ToLower() == "string")
                {
                    return ((KryptonCheckBox)c).Checked ? YesNoPolicy.YES : YesNoPolicy.NO;
                }
                else if (type.ToLower() == "decimal")
                {
                    return ((KryptonCheckBox)c).Checked ? 1m : 0m;
                }
                else if (type.ToLower() == "bool")
                {
                    return ((KryptonCheckBox)c).Checked ? true : false;
                }
                else if (type.ToLower() == "int" || type.ToLower() == "int32" || type.ToLower() == "int16" || type.ToLower() == "int64")
                {
                    return ((KryptonCheckBox)c).Checked ? 1 : 0;
                }
                else if (type.ToLower() == "double" || type.ToLower() == "float")
                {
                    return ((KryptonCheckBox)c).Checked ? 1d : 0d;
                }
            }
            else if (c is KryptonDateTimePicker)
            {
                if (!((KryptonDateTimePicker)c).Checked) return null;

                if (string.IsNullOrEmpty(((KryptonDateTimePicker)c).Text)) return null;
                else if (type.ToLower() == "string")
                {
                    return ((KryptonDateTimePicker)c).Text.Trim();
                }
                else if (type.ToLower() == "nullable`1" || type.ToLower() == "datetime" || type.ToLower() == "sqldatetime")
                {
                    if (type.ToLower() == "datetime" && string.IsNullOrEmpty(((KryptonDateTimePicker)c).Text))
                        return DBNull.Value;
                    else if (type.ToLower() == "sqldatetime" && string.IsNullOrEmpty(((KryptonDateTimePicker)c).Text))
                        return SqlDateTime.Null;
                    else
                        return ((KryptonDateTimePicker)c).Value;
                }
            }
            else if (c is KryptonMaskedTextBox)
            {
                if (string.IsNullOrEmpty(((KryptonMaskedTextBox)c).Text)) return null;
                else if (type.ToLower() == "string")
                {
                    return ((KryptonMaskedTextBox)c).Text.Trim();
                }
                else if (type.ToLower() == "nullable`1" || type.ToLower() == "datetime" || type.ToLower() == "sqldatetime")
                {
                    if (type.ToLower() == "datetime" && string.IsNullOrEmpty(((KryptonMaskedTextBox)c).Text))
                        return DBNull.Value;
                    else if (type.ToLower() == "sqldatetime" && string.IsNullOrEmpty(((KryptonMaskedTextBox)c).Text))
                        return SqlDateTime.Null;
                    else
                    {
                        if (!string.IsNullOrEmpty(bindFormat))
                            return DateTime.ParseExact(((KryptonMaskedTextBox)c).Text.Trim(), bindFormat, CultureInfo.InvariantCulture, DateTimeStyles.None);
                        else
                            return DateTime.Parse(((KryptonMaskedTextBox)c).Text.Trim(), CultureInfo.InvariantCulture, DateTimeStyles.None);
                    }
                }
                else if (type.ToLower() == "decimal")
                {
                    if (!string.IsNullOrEmpty(bindFormat))
                        return Decimal.Parse(Convert.ToDecimal(((KryptonMaskedTextBox)c).Text).ToString(bindFormat));
                    else
                        return Convert.ToDecimal(((KryptonMaskedTextBox)c).Text);
                }
                else if (type.ToLower() == "int" || type.ToLower() == "int32" || type.ToLower() == "int16")
                {
                    return Convert.ToInt32(Convert.ToDecimal(((KryptonMaskedTextBox)c).Text));
                }
                else if (type.ToLower() == "int64")
                {
                    return Convert.ToInt64(Convert.ToDecimal(((KryptonMaskedTextBox)c).Text));
                }
                else if (type.ToLower() == "double" || type.ToLower() == "float")
                {
                    return Convert.ToDouble(((KryptonMaskedTextBox)c).Text);
                }
            }
            else if (c is KryptonCheckedListBox)
            {
                if (((KryptonCheckedListBox)c).GetCheckedItemValue<string>().Count() == 0) return null;

                return QuotedString.ToDelimiteredList(((KryptonCheckedListBox)c).GetCheckedItemValue<string>());
            }
            else if (c is KryptonListBox)
            {
                if (((KryptonListBox)c).GetAllItemValue<string>().Count() == 0) return null;

                return QuotedString.ToDelimiteredList(((KryptonListBox)c).GetAllItemValue<string>());
            }
            else if (c is KryptonRadioButton)
            {
                if (type.ToLower() == "string")
                {
                    return ((KryptonRadioButton)c).Checked ? "Y" : "N";
                }
                else if (type.ToLower() == "decimal")
                {
                    return ((KryptonRadioButton)c).Checked ? 1m : 0m;
                }
                else if (type.ToLower() == "bool")
                {
                    return ((KryptonRadioButton)c).Checked ? true : false;
                }
                else if (type.ToLower() == "int" || type.ToLower() == "int32" || type.ToLower() == "int16" || type.ToLower() == "int64")
                {
                    return ((KryptonRadioButton)c).Checked ? 1 : 0;
                }
                else if (type.ToLower() == "double" || type.ToLower() == "float")
                {
                    return ((KryptonRadioButton)c).Checked ? 1d : 0d;
                }
            }

            return ((Control)c).Text;
        }
    }

    public class BindingContextCustomAttribute
    {
        public BindingContextCustomAttribute()
        {

        }

        public string BindDataName { get; set; }
        public string BindDisplayName { get; set; }

        public EnumBindDirection BindDirection { get; set; }
        public string BindFormat { get; set; }

        public EnumEditModeColor EditModeColor { get; set; }

        public Operate PermissionMode { get; set; }
        public string PermissionName { get; set; }

        public string DependentDetailName { get; set; }

        public List<dynamic> DataSource { get; set; }

        public DataTable DataTableSource { get; set; }
        public DataTable DeleteDataTableSource { get; set; }
    }
}

