using System;
using System.Collections.Generic;
using System.Linq;
using SystemX.Net.Platform.Common.Util;
using static SystemX.PLC.Interface.PLCCommDefinition;

namespace SystemX.PLC.Interface
{
    public class PLCAddressTemplate
    {
        public string Area { get; set; } = string.Empty;
        public string Address { get; set; } = string.Empty;
        public string Length { get; set; } = string.Empty;
        public string DataName { get; set; } = string.Empty;
        public string DataType { get; set; } = string.Empty;
        public string Operation { get; set; } = string.Empty;
        public string Desc { get; set; } = string.Empty;
        public string AddressKey { get { return Area + Address; } }

        List<string> AssociatedAddress { get; set; } = null;
        List<int> KeyAddressValues { get; set; } = null;

        public string Value
        {
            get { return RefineInvalidChars(MakeResultValue()); }
        }
        
        public List<int> RawValue
        {
            get { return KeyAddressValues; }
        }

        public PLCAddressTemplate()
        {
        }

        public void UpdateValue(string strKey, int nValue)
        {
            int nFindKeyAddrIdx = AssociatedAddress.IndexOf(strKey);

            KeyAddressValues[nFindKeyAddrIdx] = nValue;
        }

        public void SetStringValue(string strValue)
        {
            List<int> vnValues = new List<int>();
            int nLength = Convert.ToInt32(Length);
            eDataType eType = (eDataType)Enum.Parse(typeof(eDataType), DataType);

            if (eType == eDataType.ASCII)
                vnValues = (from value in CommonUtil.HexStringToBytes(strValue) select Convert.ToInt32(value)).ToList();
            else if (eType == eDataType.DECIMAL)
            {
                int nInputValue = string.IsNullOrWhiteSpace(strValue) ? 0 : Convert.ToInt32(strValue);
                vnValues.Add(nInputValue);
            }
            
            for (int i = 0; i < vnValues.Count; i++)
                KeyAddressValues[i] = vnValues[i];
        }

        public void SetAssociatedValue(int nValue)
        {
            KeyAddressValues[0] = nValue;
        }

        public void SetAssociatedValues(List<int> nValues)
        {
            for (int i = 0; i < nValues.Count; i++)
                KeyAddressValues[i] = nValues[i];
        }

        public void SetAssocationKeys()
        {
            AssociatedAddress = new List<string>();
            KeyAddressValues = new List<int>();

            int nLength = Convert.ToInt32(Length);
            int nStartAddress = Convert.ToInt32(Address);

            for (int i = 0; i < nLength; i++)
            {
                AssociatedAddress.Add(Area + (nStartAddress + i).ToString());
                KeyAddressValues.Add(00);
            }                
        }

        public string PLCAddress { get { return Area + Address; } }

        public bool IsMyAssociation(string strKey)
        {
            if (AssociatedAddress == null)
                SetAssocationKeys();

            if (AssociatedAddress.Contains(strKey))
                return true;

            return false;
        }

        string MakeResultValue()
        {
            eDataType eType = (eDataType)Enum.Parse(typeof(eDataType), DataType);
            string strData = string.Empty;

            if (eType == eDataType.ASCII)
                strData = CommonUtil.GetStringFromASCII(KeyAddressValues.ToArray());
            else if (eType == eDataType.BIT)
                strData = KeyAddressValues[0].ToString();
            else if (eType == eDataType.DECIMAL)
                strData = KeyAddressValues[0].ToString();
            
            return strData;
        }

        public string RefineInvalidChars(string strSource)
        {
            string strReturn = strSource.Trim(InvalidChars);

            strReturn = new string((from cCode in strSource.ToCharArray() where (48 <= Convert.ToInt32(cCode) && Convert.ToInt32(cCode) <= 95) select cCode).ToArray());

            return strReturn;
        }
    }

    public class PLCConnectionInfo
    {
        public string Name { get; set; } = string.Empty;
        public string CPUType { get; set; } = string.Empty;
        public string RWType { get; set; } = string.Empty;
        public string IP { get; set; } = string.Empty;
        public string Port { get; set; } = string.Empty;
        public string ConnectionType { get; set; } = string.Empty;
        public string Timeout { get; set; } = string.Empty;

        public PLCConnectionInfo()
        {
        }
    }
}
