using PlcCom;
using Sunny.UI;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Design;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Permission;
namespace PlcUiControl
{
    public class PlcUiNumberDisplay : MyUiLabel, ISingleOutputComponent, IPlcBindableNumber,IPermissionControl, IPlcUiControl
    {
        [Category("PLC")]
        [Description("读写地址相同")]
        [DefaultValue(false)]
        [Browsable(false)]
        public bool IsReadWriteNodeSame { get; set; } = false;

        [Category("PLC")]
        [Browsable(false)]
        [Description("地址名称")]
        public string NodeName { get; private set; }

        [Category("PLC")]
        [Description("PLC读地址")]
        [Editor(typeof(NodeTypeEditor), typeof(UITypeEditor))]
        public Node ReadNode { get => readNode; set { readNode = value; if (value != null) NodeName = StringExtensions.AfterLast(value.Value, '.'); if (IsReadWriteNodeSame) writeNode = value; } }
        Node readNode;

        [Category("PLC")]
        [Description("PLC写地址")]
        [Browsable(false)]
        [Editor(typeof(NodeTypeEditor), typeof(UITypeEditor))]
        public Node WriteNode { get => writeNode; set { writeNode = value; if (value != null) NodeName = StringExtensions.AfterLast(value.Value, '.'); if (IsReadWriteNodeSame) readNode = value; } }
        Node writeNode;

        [Category("PLC")]
        [Description("显示的整数位")]
        [Browsable(true)]
        public int IntegerDigits { get => integerDigits; set {integerDigits = value; Text = CommonLib.FormatNumber(State, integerDigits, decimalPlaces, Gain, out double result); } }
        private int integerDigits = 0;

        [Category("PLC")]
        [Description("显示的小数位")]
        [Browsable(true)]
        public int DecimalPlaces { get => decimalPlaces; set { if (value < 0) value = 0; if (value >6 ) value = 6; decimalPlaces = value; Text = CommonLib.FormatNumber(State, IntegerDigits, DecimalPlaces, Gain, out double result); } }
        private int decimalPlaces = 2;

        [Category("PLC")]
        [Description("增益")]
        [Browsable(true)]
        public double Gain { get; set; } = 1;

        [Category("PLC")]
        [Description("文本前缀")]
        [Browsable(true)]
        public string Preffix { get; set; }

        [Category("PLC")]
        [Description("文本后缀")]
        [Browsable(true)]
        public string Suffix { get; set; }

        [Category("PLC")]
        [Description("致使控件不可见的变量")]
        [Editor(typeof(NodeTypeEditor), typeof(UITypeEditor))]
        [Browsable(true)]
        public Node InvisibilityTriggerNode { get; set; }

        [Category("PLC")]
        [Description("致使控件不可见的变量的目标值")]
        [Browsable(true)]
        [DefaultValue(true)]
        public bool ValueForInvisibility { get; set; } = true;

        [Category("PLC")]
        [Description("致使控件不可用的变量")]
        [Editor(typeof(NodeTypeEditor), typeof(UITypeEditor))]
        [Browsable(true)]
        public Node DisabilityTriggerNode { get; set; }

        [Category("PLC")]
        [Description("致使控件不可用的变量的目标值")]
        [Browsable(true)]
        [DefaultValue(true)]
        public bool ValueForDisability { get; set; } = true;

        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public bool Invisibility { get => invisibility; set { invisibility = value; HandlePermissionChange(); } }
        private bool invisibility;

        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public bool Disability { get => disability; set { disability = value; HandlePermissionChange(); } }
        private bool disability;

        protected override void HandlePermissionChange()
        {
            CommonLib.ApplyPermissionState(this, this, this);
        }


        [Browsable(false)]
        //[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public new string Text
        {
            get => base.Text;
            set => base.Text = value;
        }

        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public IPlcComProtocol Protocol { get; set; }

        public virtual void UpdateControlApperance()
        {
            Text = CommonLib.FormatNumber(state, IntegerDigits, DecimalPlaces, Gain, out double result);
            if(!string.IsNullOrEmpty(Preffix))
            {
                Text = Preffix + Text;
            }
            if (!string.IsNullOrEmpty(Suffix))
            {
                Text = Text + Suffix;
            }
        }

        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public double State
        {
            get => state;
            set
            {
               
                if (state != value)
                {
                    state = value;
                    UpdateControlApperance();
                    OnPLCRegisterValueChanged?.Invoke(this,readNode, state);
                }
            }
        }

        private double state;

        [Category("PLC")]
        [Description("PLC寄存器数据发生了变化")]
        public event RegisterValueChangedHandler OnPLCRegisterValueChanged;

        public PlcUiNumberDisplay()
        {
            //BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
            //TextAlign = ContentAlignment.MiddleCenter;
            //State = 123.123456789;
            State = 1;
            UpdateControlApperance();
        }

        public event ReadRegisterFailedHandler OnReadRegisterFailed;
        public event UpdateComponentStateFailedHandler OnUpdateComponentStateFailed;

        public object Read()
        {
            if (Protocol != null && ReadNode != null)
            {
                object result;
                var rt = Protocol.ReadValue(ReadNode.Value, out result);
                if (rt == 0)
                {
                    UpdateValue(result);
                    return result;
                }
                else
                {
                    OnReadRegisterFailed?.Invoke(this, ReadNode, rt);
                }
            }
            return null;
        }
        public void UpdateValue(object value)
        {
            try
            {
                switch (ReadNode.Type)
                {
                    case NodeType.BOOL:
                        State=(value is bool b) ? (b ? 1.0 : 0.0) : 0.0;
                        break;
                    case NodeType.BYTE:
                    case NodeType.WORD:
                    case NodeType.DWORD:
                    case NodeType.LWORD:
                    case NodeType.SINT:
                    case NodeType.USINT:
                    case NodeType.INT:
                    case NodeType.UINT:
                    case NodeType.DINT:
                    case NodeType.UDINT:
                    case NodeType.LINT:
                    case NodeType.ULINT:
                    case NodeType.TIME:
                        //State = Convert.ToInt32(value);
                        //break;
                    case NodeType.REAL:
                    case NodeType.LREAL:
                        State =Convert.ToDouble(value);
                        break;
                    case NodeType.STRING:
                        break;
                    default:
                        throw new ArgumentOutOfRangeException(nameof(ReadNode.Type), ReadNode.Type, null);
                }
            }
            catch (Exception ex)
            {
                OnUpdateComponentStateFailed?.Invoke(this,readNode, value, ex.Message);
            }
        }
    }
}
