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 PlcUiStateDisplay : MyUiLabel,ISingleOutputComponent, IPlcUiControl
    {
        [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, '.');} }
        Node readNode;

        [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(true)]
        //[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public new string Text
        {
            get => base.Text;
            set => base.Text = value;
        }

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

        Timer timer;
        public virtual void UpdateControlApperance()
        {
            if (Items.Count > 0)
            {
                var singleState = Items.First(s => s.State == state.ToString());
                Text = singleState.Message;
                BackColor = singleState.BackColor;
                ForeColor = singleState.ForeColor;
                if(singleState.Blink)
                {
                    if(timer==null)
                    {
                        timer = new Timer();
                        timer.Interval = 500;
                        timer.Tick += (s, e) => { this.Visible = !this.Visible; };
                    }
                    timer.Start();
                }
                else
                {
                    timer?.Stop();
                    this.Visible = true;
                }
            }
        }

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

        [Category("PLC")]
        [Description("状态集合")]
        [Editor(typeof(CollectionEditor), typeof(UITypeEditor))]
        public List<Item> Items { get; set; } = new List<Item>();
      
        [Category("PLC")]
        [Description("PLC寄存器数据发生了变化")]
        public event RegisterValueChangedHandler OnPLCRegisterValueChanged;

        public PlcUiStateDisplay()
        {
            BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
            TextAlign = ContentAlignment.MiddleCenter;
            State = "StateDisplay";
            //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:
                    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.REAL:
                    case NodeType.LREAL:
                    case NodeType.TIME:
                    case NodeType.STRING:
                        State = value.ToString();
                        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 Item
    {
        public string 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;
    }
}
