using System;
using System.Collections.ObjectModel;
using System.Linq;
using 常用工具集.Base;
using System.Threading;
using OpcUaHelper;
using Org.BouncyCastle.Crypto.Tls;
using System.Threading.Tasks;
using Opc.Ua.Client;
using Opc.Ua;
using Ursa.Controls;

namespace 常用工具集.ViewModel._01PLC通信调试
{
    public class OPCUA调试ViewModel : ViewModelBase
    {
        private bool stop = false;
        private OpcUaClient client;
        private object _lock = new object();
        private Thread thread;
        public bool Enabled1 { get; set; } = true;
        public bool Enabled2 { get; set; } = false;

        public string OpcServer { get; set; } = "opc.tcp://10.10.0.40";
        public string Node { get; set; } = "ns=4;s=|var|Inovance-ARM-Linux.Application.StorageDatas.gStorageDatas[10].MaterialInfo.Width";
        public string Result { get; set; } = "";

        public string WriteValue { get; set; } = "";
        public string SelecedValue { get; set; } = "";
        public int SelectedIndex { get; set; } = -1;
        public ObservableCollection<MyNode> NodeList { get; set; } = new ObservableCollection<MyNode>();
        public DelegateCommand ConnectCmd { get; set; }
        public DelegateCommand DisconnectCmd { get; set; }
        public DelegateCommand SubscribeCmd { get; set; }
        public DelegateCommand ReadValueCmd { get; set; }
        public DelegateCommand WriteValueCmd { get; set; }
        public DelegateCommand CancelSubscribeCmd { get; set; }

        public DelegateCommand OpenBrowerCmd { get; set; }
        public OPCUA调试ViewModel()
        {
            ConnectCmd = new DelegateCommand(ConnectCmdFunc);
            DisconnectCmd = new DelegateCommand(DisconnectCmdFunc);
            SubscribeCmd = new DelegateCommand(SubscribeCmdFunc);
            ReadValueCmd = new DelegateCommand(ReadValueCmdFunc);
            WriteValueCmd = new DelegateCommand(WriteValueCmdFunc);
            CancelSubscribeCmd = new DelegateCommand(CancelSubscribeCmdFunc);
            OpenBrowerCmd = new DelegateCommand(OpenBrowerCmdFunc);
        }

        private void OpenBrowerCmdFunc(object obj)
        {
            //new OpcUaHelper.Forms.FormBrowseServer().Show();
        }






        /// <summary>
        /// 建立连接
        /// </summary>
        /// <param name="obj"></param>
        private void ConnectCmdFunc(object obj)
        {
            try
            {
                client = new OpcUaClient();
                DateTime start = DateTime.Now;
                bool connected = false;
                Task task = client.ConnectServer(OpcServer);
                while (true)
                {
                    if (client.Connected)
                    {
                        connected = true;
                        break;
                    }
                    if ((DateTime.Now - start).TotalMilliseconds > 1000)
                    {
                        break;
                    }
                }
                if (!connected)
                {
                    GlobalValues.Error($"连接失败");
                    client = null;
                    return;
                }
                Enabled1 = false;
                Enabled2 = true;
                stop = false;
                thread = new Thread(() =>
                {
                    while (true)
                    {
                        try
                        {
                            if (stop)
                            {
                                break;
                            }
                            Loop();
                            Thread.Sleep(1000);
                        }
                        catch (ThreadInterruptedException ex)
                        {
                            break;
                        }
                        catch (Exception e)
                        {

                        }

                    }
                });
                thread.Start();
            }
            catch (Exception ex)
            {
                GlobalValues.Error($"连接失败：{ex.Message}");
            }
        }



        /// <summary>
        /// 断开连接
        /// </summary>
        /// <param name="obj"></param>
        private void DisconnectCmdFunc(object obj)
        {
            foreach (MyNode node in NodeList)
            {
                client.RemoveSubscription(node.NodeName);
            }
            NodeList.Clear();
            client.Disconnect();
            client = null;
            Enabled1 = true;
            Enabled2 = false;
            stop = true;
            thread.Interrupt();
            thread = null;
        }


        private void SubscribeCmdFunc(object obj)
        {
            string node = Node;
            if (NodeList.Any(x => x.NodeName == node))
                return;
            lock (_lock)
            {
                NodeList.Add(new MyNode { NodeName = node, Value = null });
            }
            client.AddSubscription(node, node, CallBack);
        }

        private void CallBack(string key, MonitoredItem item, MonitoredItemNotificationEventArgs itemNotify)
        {
            MonitoredItemNotification notification = itemNotify.NotificationValue as MonitoredItemNotification;
            DataValue dataValue = notification.Value;
            bool isGood = StatusCode.IsGood(dataValue.StatusCode);
            if (isGood)
            {
                lock (_lock)
                {
                    MyNode node = NodeList.Where(it => it.NodeName == key).FirstOrDefault();
                    node.Value = dataValue.Value;
                }
            }
            else
            {
                lock (_lock)
                {
                    MyNode node = NodeList.Where(it => it.NodeName == key).FirstOrDefault();
                    node.Value = null;
                }
            }
        }
        private void ReadValueCmdFunc(object obj)
        {
            try
            {
                DataValue dataValue = client.ReadNode(new NodeId(Node));
                if (!StatusCode.IsGood(dataValue.StatusCode))
                {
                    Result = "";
                    GlobalValues.Error("读取失败");
                    return;
                }
                Result = dataValue.Value.ToString();
                GlobalValues.Success($"读取成功");
            }
            catch (Exception ex)
            {
                Result = "";
                GlobalValues.Error($"读取失败:{ex.Message}");
            }

        }

        private void WriteValueCmdFunc(object obj)
        {
            try
            {
                string cmd = obj.ToString();
                if (cmd == "bool")
                {
                    bool value;
                    bool flag = bool.TryParse(WriteValue, out value);
                    if (!flag)
                    {
                        GlobalValues.Error("数据转换失败,请输入正确的数据");
                        return;
                    }
                    flag = client.WriteNode<bool>(Node, value);
                    if (!flag)
                    {
                        GlobalValues.Error("写入失败");
                        return;
                    }
                    GlobalValues.Success("写入成功");
                }
                else if (cmd == "uint16")
                {
                    ushort value;
                    bool flag = ushort.TryParse(WriteValue, out value);
                    if (!flag)
                    {
                        GlobalValues.Error("数据转换失败,请输入正确的数据");
                        return;
                    }
                    flag = client.WriteNode<ushort>(Node, value);
                    if (!flag)
                    {
                        GlobalValues.Error("写入失败");
                        return;
                    }
                    GlobalValues.Success("写入成功");
                }
                else if (cmd == "int16")
                {
                    short value;
                    bool flag = short.TryParse(WriteValue, out value);
                    if (!flag)
                    {
                        GlobalValues.Error("数据转换失败,请输入正确的数据");
                        return;
                    }
                    flag = client.WriteNode<short>(Node, value);
                    if (!flag)
                    {
                        GlobalValues.Error("写入失败");
                        return;
                    }
                    GlobalValues.Success("写入成功");
                }
                else if (cmd == "int32")
                {
                    int value;
                    bool flag = int.TryParse(WriteValue, out value);
                    if (!flag)
                    {
                        GlobalValues.Error("数据转换失败,请输入正确的数据");
                        return;
                    }
                    flag = client.WriteNode<int>(Node, value);
                    if (!flag)
                    {
                        GlobalValues.Error("写入失败");
                        return;
                    }
                    GlobalValues.Success("写入成功");
                }
                else if (cmd == "int64")
                {
                    long value;
                    bool flag = long.TryParse(WriteValue, out value);
                    if (!flag)
                    {
                        GlobalValues.Error("数据转换失败,请输入正确的数据");
                        return;
                    }
                    flag = client.WriteNode<long>(Node, value);
                    if (!flag)
                    {
                        GlobalValues.Error("写入失败");
                        return;
                    }
                    GlobalValues.Success("写入成功");
                }
                else if (cmd == "float")
                {
                    float value;
                    bool flag = float.TryParse(WriteValue, out value);
                    if (!flag)
                    {
                        GlobalValues.Error("数据转换失败,请输入正确的数据");
                        return;
                    }
                    flag = client.WriteNode<float>(Node, value);
                    if (!flag)
                    {
                        GlobalValues.Error("写入失败");
                        return;
                    }
                    GlobalValues.Success("写入成功");
                }
                else if (cmd == "double")
                {
                    double value;
                    bool flag = double.TryParse(WriteValue, out value);
                    if (!flag)
                    {
                        GlobalValues.Error("数据转换失败,请输入正确的数据");
                        return;
                    }
                    flag = client.WriteNode<double>(Node, value);
                    if (!flag)
                    {
                        GlobalValues.Error("写入失败");
                        return;
                    }
                    GlobalValues.Success("写入成功");
                }
            }
            catch (Exception ex)
            {
                MessageBox.ShowAsync(ex.Message);
            }
        }

        /// <summary>
        /// 取消订阅
        /// </summary>
        /// <param name="obj"></param>
        private void CancelSubscribeCmdFunc(object obj)
        {
            try
            {
                if (SelectedIndex < 0)
                {
                    return;
                }
                lock (_lock)
                {
                    MyNode selectKey = NodeList[SelectedIndex];
                    client.RemoveSubscription(selectKey.NodeName);
                    NodeList.RemoveAt(SelectedIndex);
                }
            }
            catch (Exception ex)
            {

            }
        }

        private void Loop()
        {
            if (SelectedIndex < 0)
            {
                return;
            }
            lock (_lock)
            {
                MyNode selectKey = NodeList[SelectedIndex];
                object value = selectKey.Value;
                if (value == null)
                {
                    SelecedValue = "";
                }
                else
                {
                    SelecedValue = value.ToString();
                }
            }
        }
    }

    public class MyNode : ViewModelBase
    {
        public string NodeName { get; set; }

        public object Value { get; set; }
    }
}
