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 PlcUiTextDisplay :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(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 = state;
        }

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

        [Category("PLC")]
        [Description("数据为DWORD格式时，是否格式化为时间格式")]
        [DefaultValue(false)]
        public bool FormatedToTime { get; set; }

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

        public PlcUiTextDisplay()
        {
            //BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
            //TextAlign = ContentAlignment.MiddleCenter;
            State = "TextDisplay";
            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.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;
                    case NodeType.DWORD:
                        if (!FormatedToTime)
                        {
                            State = value.ToString();
                        }
                        else
                        {
                            // 安全转换：先判断类型，再转微秒为 TimeSpan
                            if (value is uint microseconds)
                            {
                                State = PlcDataConvert.FormatDWordSpanToDHMS(microseconds);
                            }
                            else
                            {
                                throw new InvalidCastException("PLC TIME 值不是 UInt32 类型");
                            }
                        }
                        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();
        }
    }
}
