using IOB_UT_NEXT;
using IOB_UT_NEXT.Config;
using MapoSDK;
using System;
using System.Collections.Generic;

namespace IOB_WIN_SIEMENS.IobSiemens
{
    /// <summary>
    /// Controllo Siemens specifico x impianti Simec
    /// </summary>
    public class SiemensSimec : Siemens
    {
        #region Public Constructors

        /// <summary>
        /// Classe base con i metodi x Siemens
        /// </summary>
        /// <param name="caller">Form chiamante</param>
        /// <param name="IOBConf">Configurazione (legacy)</param>
        /// <param name="IobConfFull">Configurazione (v 4.x)</param>
        public SiemensSimec(AdapterFormNext caller, IobConfTree IobConfFull) : base(caller, IobConfFull)
        {
            /* --------------------------------------------------------------------------------
             * Controlli SIEMENS SIMEC
             * - basasto su SIEMENS
             * - S7 vers 1500
             *
             * STRUTTURA MEMORIA DB29: (lettura) 10byte,
             * G:\Drive condivisi\30_Clienti\Valvital\Comunicazione PLC\26 - SIMEC Taglio\
             *
             * Si intende lettura con DB29.DBxx, scrittura DB30.DBxx
             *
             * DB30 blocco dati scritto dal MES
             * CodArt	Array[0..19] of Char	DBB0..19
             * CodComm	Array[0..9] of Char	DBB20..29
             * CodProgr	Array[0..9] of Char	DBB30..39
             *
             * DB29 blocco dati letto dal MES			Byte	Num
             * CicloOn	Bool	0	0
             * MacchOn	Bool	0	1
             * ManualeOn	Bool	0	2
             * AllarmiOn	Bool	0	3
             * EmergenzaOn	Bool	0	4
             * EmergenzaPremuta	Bool	0	5
             * b06	Bool	0	6
             * b07	Bool	0	7
             * b10	Bool	1	0
             * b11	Bool	1	1
             * b12	Bool	1	2
             * b13	Bool	1	3
             * b14	Bool	1	4
             * b15	Bool	1	5
             * b16	Bool	1	6
             * b17	Bool	1	7
             * ContapezziAssoluto	DInt	2
             * Comtapezzi parziale	DInt	6
             * -------------------------------------------------------------------------------- */
            lgInfo("NEW IOB SIEMENS versione SIMEC");
        }

        #endregion Public Constructors

        #region Public Methods

        /// <summary>
        /// Processo i task richiesti e li elimino dalla coda 1:1
        /// </summary>
        /// <param name="task2exe"></param>
        public override Dictionary<string, string> executeTasks(Dictionary<string, string> task2exe, string codTav)
        {
            // Verificare il protocollo: dovrebeb togliere SOLO i task eseguiti...
            Dictionary<string, string> taskDone = new Dictionary<string, string>();
            bool writeDone = false;
            bool taskOk = false;
            string taskVal = "";
            // inizio con 1 byte di default
            byte[] MemBlock = new byte[1];
            string memAddrWrite = "";
            if (task2exe != null)
            {
                // cerco task specifici
                foreach (var item in task2exe)
                {
                    taskOk = false;
                    taskVal = "";
                    // converto richiesta in enum...
                    taskType tName = taskType.nihil;
                    Enum.TryParse(item.Key, out tName);
                    // controllo sulla KEY
                    switch (tName)
                    {
                        case taskType.nihil:
                        case taskType.fixStopSetup:
                        case taskType.forceResetPzCount:
                        case taskType.forceSetPzCount:
                        case taskType.setProg:
                        case taskType.sendWatchDogMes2Plc:
                        case taskType.startSetup:
                        case taskType.stopSetup:
                            taskVal = $"taskReq: {tName} | key: {item.Key} | val: {item.Value} | SKIPPED | NO EXEC";
                            lgInfo(taskVal);
                            break;

                        case taskType.setPzComm:
                        case taskType.setArt:
                        case taskType.setComm:
                            upsertKey(item.Key, item.Value);
                            int byteSize = 0;
                            // verifico se posso aggiornare valori in memoria...
                            if (memMap != null && memMap.mMapWrite != null)
                            {
                                if (memMap.mMapWrite.ContainsKey(item.Key))
                                {
                                    // recupero dati da memMap... altrimenti NULLA
                                    if (memMap.mMapWrite.ContainsKey(item.Key))
                                    {
                                        dataConf currMem = memMap.mMapWrite[item.Key];
                                        byteSize = currMem.size;
                                        memAddrWrite = currMem.memAddr;
                                        MemBlock = new byte[byteSize];
                                        if (currMem.tipoMem == plcDataType.String)
                                        {
                                            saveStringOnMemBlock(ref MemBlock, item.Key, 0, byteSize);
                                        }
                                        else if (currMem.tipoMem == plcDataType.DInt)
                                        {
                                            int valDInt = 0;
                                            int.TryParse(item.Value, out valDInt);
                                            MemBlock = S7.Net.Types.DInt.ToByteArray(valDInt);
                                        }
                                        else if (currMem.tipoMem == plcDataType.Int)
                                        {
                                            short valDInt = 0;
                                            short.TryParse(item.Value, out valDInt);
                                            MemBlock = S7.Net.Types.Int.ToByteArray(valDInt);
                                        }
                                    }
                                    taskVal = item.Value;
                                }
                                else
                                {
                                    taskVal = $"NO DATA MEM, SET task: {item.Key} --> {item.Value}";
                                }
                            }
                            else
                            {
                                taskVal = $"NO MemMap found, SET task: {item.Key} --> {item.Value}";
                            }
                            if (!string.IsNullOrEmpty(memAddrWrite))
                            {
                                // scrivo!
                                writeDone = true;
                                taskOk = S7WriteBB(ref MemBlock, memAddrWrite);
                            }
                            // se restituiscce "" faccio altra prova...
                            break;

                        case taskType.setParameter:
                            // richiedo da URL i parametri WRITE da popolare
                            lgInfo("Chiamata processMemWriteRequests");
                            taskVal = processMemWriteRequests();
                            if (string.IsNullOrEmpty(taskVal))
                            {
                                // i parametri me li aspetto come stringa composta paramName|paramvalue
                                if (item.Value.Contains("|"))
                                {
                                    string[] paramsJob = item.Value.Split('|');
                                    taskVal = $"REQUEST SET PARAMETERS: {paramsJob[0]} --> {paramsJob[1]}";
                                }
                                else
                                {
                                    taskVal = $"WRONG REQUEST FOR SET PARAMETERS: {item.Value} doesnt contain pipe for splitting key/value";
                                }
                            }
                            break;

                        default:
                            taskVal = "SKIPPED | NO EXEC";
                            break;
                    }
                    if (!taskOk && writeDone)
                    {
                        // aggiungo task!
                        taskDone.Add(item.Key, taskVal);
                        lgError($"Errore in S7WriteBB durante executeTasks: {item.Key} | {item.Value} | taskOk {taskOk} | writeDone {writeDone}");
                    }
                }
            }
            return taskDone;
        }

        #endregion Public Methods

        #region Protected Methods

        /// <summary>
        /// Effettua decodifica aree memoria alla bitmap usata x MAPO
        /// </summary>
        protected override void decodeToBaseBitmap()
        {
            // init a zero...
            B_input = 0;

            /* -----------------------------------------------------
             * bitmap MAPO STANDARD (54)
             * B0: POWER_ON
             * B1: RUN
             * B2: pzCount
             * B3: allarme
             * B4: manuale
             * B5: emergenza (1=attiva/premuta, 0=armed)
             *
             * - BIT di stato
             * DB29 blocco dati letto dal MES			Byte	Num
             * CicloOn	                        Bool	0   	0
             * MacchOn	                        Bool	0   	1
             * ManualeOn	                    Bool	0   	2
             * AllarmiOn	                    Bool	0   	3
             * EmergenzaOn	                    Bool	0   	4
             * EmergenzaPremuta	                Bool	0   	5
             * ContapezziAssoluto	            DInt	2
             * Comtapezzi parziale	            DInt	6
             *
             ----------------------------------------------------- */

            byte mainData = RawInput[0];

            int byteSignals = 0;
            // bit 0 (poweron) imposto a 1 SE connected...
            if (currPLC.IsConnected)
            {
                byteSignals += (1 << 0);
            }

            // lavora --> bit0 e bit1: cicloOn AND macchOn
            if ((mainData & (1 << 0)) != 0 && (mainData & (1 << 1)) != 0)
            {
                byteSignals += (1 << 1);
            }

            // controllo il bit ALARM
            if ((mainData & (1 << 3)) != 0)
            {
                byteSignals += (1 << 3);
            }
            // controllo il bit emergenza dello status
            if ((mainData & (1 << 5)) != 0)
            {
                byteSignals += (1 << 5);
            }

            // check MANUALE ...
            if ((mainData & (1 << 2)) != 0)
            {
                byteSignals += (1 << 4);
            }

            // salvo!
            B_input = byteSignals;

            // log opzionale!
            if (verboseLog)
            {
                lgInfo($"Trasformazione dati: RawInput:{RawInput[0]} --> B_input: {B_input}");
            }
        }

        #endregion Protected Methods
    }
}