
using EasyModbus;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading;
using System.Windows;

namespace VSview
{
    public class Turck : BaseViewModel
    {

        #region Private properties

        //Library used for connection - EasyModbus
        private ModbusClient Modbus;

        //Reference to the main view model
        private MainViewModel ViewModel;

        //Thread for reading and writing to control module
        private Thread ReadWriteThread;

        static readonly Regex trimmer = new Regex(@"\s\s+");

        #endregion

        #region Constructors
        //Main constructor
        public Turck(MainViewModel viewModel)
        {
            ViewModel = viewModel;

            Analogs = new Dictionary<string, AnalogValue>();
            Analogs.Add("Analog1", new AnalogValue() { Name = "Analog1" });
            Analogs.Add("Analog2", new AnalogValue() { Name = "Analog2" });
            Analogs.Add("Analog3", new AnalogValue() { Name = "Analog3" });
            Analogs.Add("Analog4", new AnalogValue() { Name = "Analog4" });

        }

        #endregion

        #region Public properties
        private bool _isConnected;
        public bool IsConnected
        {
            get { if (Modbus != null)
                    return Modbus.Connected;
                else
                    return false;
            }
            set
            {
                _isConnected = value;
            }
        }

        /// <summary>
        /// Collection of analog names
        /// </summary>
        public Dictionary<string, AnalogValue> Analogs { get; set; }

        /// <summary>
        /// Collection of analog values
        /// </summary>
        public List<int> AnalogValues { get; set; }

        /// <summary>
        /// Colleciton of digital I/O values
        /// </summary>
        public List<bool> DigitalValues { get; set; }
        #endregion

        /// <summary>
        /// Method for creating value collection according to selected Turck type
        /// </summary>
        /// <param name="turkType"></param>
        private void SetupValueCollection(int turkType)
        {
            try
            {
                switch (turkType)
                {
                    case 0:
                    case 1:
                    case 2:
                    case 3:
                        DigitalValues = new List<bool>();
                        for (int i = 0; i < 8; i++)
                        {
                            DigitalValues.Add(false);
                        }
                        break;
                    case 4:
                    case 5:
                        AnalogValues = new List<int>();
                        for (int i = 0; i < 4; i++)
                        {
                            AnalogValues.Add(0);
                        }
                        break;
                    default: break;
                }
            }
            catch (Exception ex) { MessageBox.Show("Error occured during turck module setup. Reason: " + ex.Message, "Turck error", MessageBoxButton.OK, MessageBoxImage.Warning); }
        }

        /// <summary>
        /// Metoda pro precteni ARP listu z PC
        /// </summary>
        /// <param name="file"></param>
        /// <param name="arguments"></param>
        /// <returns></returns>
        private static StreamReader ExecuteCommandLine(String file, String arguments = "")
        {
            ProcessStartInfo startInfo = new ProcessStartInfo()
            {
                CreateNoWindow = true,
                WindowStyle = ProcessWindowStyle.Hidden,
                UseShellExecute = false,
                RedirectStandardOutput = true,
                FileName = file,
                Arguments = arguments
            };
            Process process = Process.Start(startInfo);

            return process.StandardOutput;
        }


        /// <summary>
        /// Metoda pro pripojeni pomoci MAC addresy z ARP
        /// </summary>
        public void ConnectWithMac()
        {
            //Cteni ARP listu PC
            var MACadresslist = ExecuteCommandLine("arp", "-a");
            List<string> names = new List<string>();
            while (!MACadresslist.EndOfStream)
            {
                names.Add(MACadresslist.ReadLine().Trim());
            }

            foreach (string line in names)
            {
                var parts = trimmer.Replace(line, " ").Split(' ');

                if (parts.Length >= 2)
                {
                    if (string.Equals(parts[1], SettingViewModel.MACAddress, StringComparison.CurrentCultureIgnoreCase))
                    {
                        ConnectTurck(parts[0]);
                        SettingViewModel.IPAddress = parts[0];
                        break;
                    }
                }
            }
        }

        /// <summary>
        /// Metoda pro pripojeni dle zadaneho IP
        /// </summary>
        public void ConnectTurck(string IP = null)
        {
            new Thread(() =>
            {
                Thread.CurrentThread.IsBackground = true;
                try
                {
                    if (IP != null)
                    {
                        Modbus = new ModbusClient
                        {
                            IPAddress = IP,
                            Port = 502
                        };
                    }
                    else
                    {
                        Modbus = new ModbusClient
                        {
                            IPAddress = SettingViewModel.IPAddress,
                            Port = 502
                        };
                    }

                    Modbus.Connect();

                    if (Modbus.Connected)
                    {
                        ReadWriteThread = new Thread(ReadWriteData);
                        ReadWriteThread.IsBackground = true;

                        ReadWriteThread.Start();
                        IsConnected = true;
                    }
                    else
                        IsConnected = false;

                }
                catch (Exception ex)
                {
                    TerminalViewModel.WriteToLog("Connection to control module failed. Reason: " + ex.Message);
                }
            }).Start();
        }


        /// <summary>
        /// Metoda pro odpojeni modulu
        /// </summary>
        public void DisconnectTurck()
        {
            try
            {
                if (Modbus.Connected)
                {
                    Modbus.Disconnect();
                    IsConnected = false;
                }
            }
            catch (Exception ex)
            {
                TerminalViewModel.WriteToLog("Disconnecting from control module failed. Reason: " + ex.Message);
            }
        }



        /// <summary>
        /// Metoda pro linearni konverzi
        /// </summary>
        /// <param name="input"></param>
        /// <param name="parA"></param>
        /// <param name="parB"></param>
        /// <returns></returns>
        private double LinearConvertion(int input, string parA, string parB)
        {
            double volt = (10.0 / 32768.0) * input;
            double A = double.Parse(parA.Replace(',', '.'), CultureInfo.InvariantCulture);
            double B = double.Parse(parB.Replace(',', '.'), CultureInfo.InvariantCulture);
            return (A * volt + B);
        }
        /// <summary>
        /// Metoda pro kvadratickou konverzi
        /// </summary>
        /// <param name="input"></param>
        /// <param name="parA"></param>
        /// <param name="parB"></param>
        /// <param name="parC"></param>
        /// <returns></returns>
        private double QuadraticConvertion(int input, string parA, string parB, string parC)
        {
            double volt = (10.0 / 32768.0) * input;
            double A = double.Parse(parA.Replace(',', '.'), CultureInfo.InvariantCulture);
            double B = double.Parse(parB.Replace(',', '.'), CultureInfo.InvariantCulture);
            double C = double.Parse(parC.Replace(',', '.'), CultureInfo.InvariantCulture);
            return (A * (Math.Pow(volt, 2)) + B * input + C);
        }
        /// <summary>
        /// Metoda pro exponencialni konverzi
        /// </summary>
        /// <param name="input"></param>
        /// <param name="parA"></param>
        /// <param name="parB"></param>
        /// <returns></returns>
        private double ExponentialConvertion(int input, string parA, string parB)
        {
            double volt = (10.0 / 32768.0) * input;
            double A = double.Parse(parA.Replace(',', '.'), CultureInfo.InvariantCulture);
            double B = double.Parse(parB.Replace(',', '.'), CultureInfo.InvariantCulture);
            double exponent = (volt - A) * B;
            return Math.Pow(10, exponent);
        }

        /// <summary>
        /// Cycklicke cteni dat z modulu
        /// </summary>
        public void ReadWriteData()
        {
            try
            {
                //Unvitř jednotlivých if pro moduly je nutné doplnit odesílací podmínky - například zápis analogových výstupů pouze když...
                while (Modbus.Connected)
                {
                    switch (SettingViewModel.ControlModules[SettingViewModel.ControlIndex])
                    {
                        case "Turck - S2 - 4AI":
                            AnalogValues = Modbus.ReadInputRegisters(0, 4).ToList();

                            for (int i = 0; i < 4; i++)
                            {
                                if (ViewModel.MeasurementViewModel.Displays[i].Selection == 3)
                                {
                                    ViewModel.MeasurementViewModel.Displays[i].Value = Analogs["Analog1"].Result;
                                }
                                else if (ViewModel.MeasurementViewModel.Displays[i].Selection == 4)
                                {
                                    ViewModel.MeasurementViewModel.Displays[i].Value = Analogs["Analog2"].Result;
                                }
                                else if (ViewModel.MeasurementViewModel.Displays[i].Selection == 5)
                                {
                                    ViewModel.MeasurementViewModel.Displays[i].Value = Analogs["Analog3"].Result;
                                }
                                else if (ViewModel.MeasurementViewModel.Displays[i].Selection == 6)
                                {
                                    ViewModel.MeasurementViewModel.Displays[i].Value = Analogs["Analog4"].Result;
                                }
                            }
                            break;
                        case "Turck - S2-4AO":
                            Modbus.WriteMultipleRegisters(0, AnalogValues.ToArray());
                            //zápis jenotlivých analogů - např....(pozice, hodnota)
                            //Modbus.WriteSingleRegister(2, AnalogValues[2]);
                            break;
                        case "Turck - S1-8DIP":
                            DigitalValues = Modbus.ReadDiscreteInputs(0, 8).ToList();
                            break;
                        case "Turck - S1-8DOP":
                            Modbus.WriteMultipleCoils(0, DigitalValues.ToArray());
                            break;
                        case "Turck - S1-4DIP-4DOP":
                            //DigitalValues= Modbus.ReadDiscreteInputs(0, 4);
                            Modbus.WriteMultipleCoils(4, DigitalValues.ToArray());
                            break;
                        default: break;
                    }
                    Thread.Sleep(250);
                }
            }
            catch (Exception ex)
            {

            }


        }

    }
}
