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

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

        [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("对应寄存器为True时显示的文字")]
        public string OnText { get; set; }

        [Category("PLC")]
        [Description("对应寄存器为False时显示的文字")]
        public string OffText { get; set; }

        [Category("PLC")]
        [Description("对应寄存器为True时显示的颜色")]
        public Color On_Color { get => OnColor; set => OnColor = value; }

        [Category("PLC")]
        [Description("对应寄存器为False时显示的颜色")]
        public Color Off_Color { get => OffColor; set => OffColor = value; }

        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public IPlcComProtocol Protocol { 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);
        }

        public virtual void UpdateControlApperance()
        {
            Text = _State
            ? (string.IsNullOrEmpty(OnText) ? Text : OnText)
            : (string.IsNullOrEmpty(OffText) ? Text : OffText);
            State = _State ?  UILightState.On: UILightState.Off;
        }
        bool isFirstUpdate = true;
        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public bool _State 
        { 
            get => state;
            set
            {
                if (!isFirstUpdate)
                {
                    if (state != value)
                    {
                        state = value;
                        UpdateControlApperance();
                        OnPLCRegisterValueChanged?.Invoke(this, ReadNode, state);
                    }
                }
                else
                {
                    isFirstUpdate = false;
                    if (state != value)
                    {
                        state = value;
                        OnPLCRegisterValueChanged?.Invoke(this, ReadNode, state);
                    }
                    UpdateControlApperance();
                }

            }
        }
        private bool state;

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

        public PlcUiLight()
        {
            ShowText = true;
            TextAlign = ContentAlignment.MiddleRight;
        }
        protected override void OnHandleCreated(EventArgs e)
        {
            base.OnHandleCreated(e);
            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 = Convert.ToBoolean(value);
                        break;
                    case NodeType.BYTE:
                        _State = Convert.ToByte(value) != 0;
                        break;
                    case NodeType.WORD:
                        _State = Convert.ToUInt16(value) != 0;
                        break;
                    case NodeType.DWORD:
                        _State = Convert.ToUInt32(value) != 0;
                        break;
                    case NodeType.LWORD:
                        _State = Convert.ToUInt64(value) != 0;
                        break;
                    case NodeType.SINT:
                        _State = Convert.ToSByte(value) != 0;
                        break;
                    case NodeType.USINT:
                        _State = Convert.ToByte(value) != 0;
                        break;
                    case NodeType.INT:
                        _State = Convert.ToInt16(value) != 0;
                        break;
                    case NodeType.UINT:
                        _State = Convert.ToUInt16(value) != 0;
                        break;
                    case NodeType.DINT:
                        _State = Convert.ToInt32(value) != 0;
                        break;
                    case NodeType.UDINT:
                        _State = Convert.ToUInt32(value) != 0;
                        break;
                    case NodeType.LINT:
                        _State = Convert.ToInt64(value) != 0;
                        break;
                    case NodeType.ULINT:
                        _State = Convert.ToUInt64(value) != 0;
                        break;
                    case NodeType.REAL:
                        _State = Convert.ToSingle(value) != 0;
                        break;
                    case NodeType.LREAL:
                        _State = Convert.ToDouble(value) != 0;
                        break;
                    case NodeType.TIME:
                        _State = Convert.ToUInt16(value) != 0;
                        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);
            }
        }

        public void WriteValue(object value)
        {
            throw new NotImplementedException();
        }
    }
    //[Serializable]
    //public class StateItem
    //{
    //    public int State { get; set; }
    //    public string Message { get; set; }
    //    public Color BackColor { get; set; } = Color.White;
    //    public Color ForeColor { get; set; } = Color.Black;

    //    [DefaultValue(false)]
    //    public bool Blink { get; set; } = false;
    //}
}
