using System;
using Aitex.Core.RT.IOCore;
using MECF.Framework.Common.IOCore;
using MECF.Framework.Common.PLC;

namespace SicSimulator.Instances
{
    public class SimulatorAdsPlcService : IWcfPlcService
    {

        //diVariable=""  doVariable=""  aiVariable=""  aoVariable=""
        public bool CheckIsConnected()
        {
            return true;
        }

        public bool Read(string variable, out object data, string type, int length, out string reason)
        {
            reason = string.Empty;
            data = null;

            if (!TryParseIoVariable(variable, out var pmSource, out var ioType, out var bufferIndex))
                return true;

            switch (ioType)
            {
                case "DI":
                    data = IoManager.Instance.GetDiBuffer(pmSource)[bufferIndex];
                    break;
                case "DO":
                    data = IoManager.Instance.GetDoBuffer(pmSource)[bufferIndex];
                    break;
                case "AI":
                    data = IoManager.Instance.GetAiBuffer(pmSource)[bufferIndex];
                    break;
                case "AO":
                    data = IoManager.Instance.GetAoBuffer(pmSource)[bufferIndex];
                    break;
            }

            return true;
        }

        public bool WriteArrayElement(string variable, int index, object value, out string reason)
        {
            reason = string.Empty;

            if (!TryParseIoVariable(variable, out var pmSource, out var ioType, out var bufferIndex))
                return true;

            switch (ioType)
            {
                case "DI":
                    break;
                case "DO":
                    IoManager.Instance.GetDoBuffer(pmSource)[bufferIndex][index] = (bool)value;
                    break;
                case "AI":
                    IoManager.Instance.GetAiBuffer(pmSource)[bufferIndex][index] = (float)value;
                    break;
                case "AO":
                    IoManager.Instance.GetAoBuffer(pmSource)[bufferIndex][index] = (float)value;
                    break;
            }

            return true;
        }

        public bool[] ReadDi(int offset, int size, out string reason)
        {
            throw new System.NotImplementedException();
        }

        public float[] ReadAiFloat(int offset, int size, out string reason)
        {
            throw new System.NotImplementedException();
        }

        public int[] ReadAiInt(int offset, int size, out string reason)
        {
            throw new System.NotImplementedException();
        }

        public bool WriteDo(int offset, bool[] buffer, out string reason)
        {
            throw new System.NotImplementedException();
        }

        public bool WriteAoFloat(int offset, float[] buffer, out string reason)
        {
            throw new System.NotImplementedException();
        }

        public bool WriteAoInt(int offset, int[] buffer, out string reason)
        {
            throw new System.NotImplementedException();
        }

        public int Heartbeat(int counter)
        {
            return counter;
        }

        
        // GVL_IO.PM{n}_{DI|DO|AI|AO}_G[_N]  => PM{n}.PLC, type, index (N-1, default 0)
        private static bool TryParseIoVariable(string variable, out string pmSource, out string ioType, out int bufferIndex)
        {
            pmSource = null;
            ioType = null;
            bufferIndex = 0;

            var dotIndex = variable.LastIndexOf('.');
            if (dotIndex < 0)
                return false;

            var name = variable.Substring(dotIndex + 1);
            var pmEnd = name.IndexOf('_');
            if (pmEnd <= 2 || !name.StartsWith("PM"))
                return false;

            pmSource = name.Substring(0, pmEnd) + ".PLC";
            var rest = name.Substring(pmEnd + 1);

            if (rest.StartsWith("DI_")) ioType = "DI";
            else if (rest.StartsWith("DO_")) ioType = "DO";
            else if (rest.StartsWith("AI_")) ioType = "AI";
            else if (rest.StartsWith("AO_")) ioType = "AO";
            else return false;

            const string groupMarker = "_G";
            var gIndex = rest.LastIndexOf(groupMarker, StringComparison.Ordinal);
            if (gIndex < 0)
                return false;

            var indexPart = rest.Substring(gIndex + groupMarker.Length);
            if (indexPart.Length == 0)
                bufferIndex = 0;
            else if (indexPart.StartsWith("_") && int.TryParse(indexPart.Substring(1), out var suffixNum))
                bufferIndex = suffixNum - 1;
            else
                return false;

            return true;
        }

 
    }
}