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 SAET
    /// </summary>
    public class SiemensAt2001 : Siemens
    {
        /* --------------------------------------------------------------------------------
         * Controlli VIPA/SIEMENS (Interclays) di @2001
         * - VIPA, COMPATIBILE SIEMENS
         * - S7 vers 300
         *
         *

         * -------------------------------------------------------------------------------- */

        #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 SiemensAt2001(AdapterFormNext caller, IobConfTree IobConfFull) : base(caller, IobConfFull)
        {
            lgInfo("NEW IOB SIEMENS versione VIPA AT2001");
            lastPLCWatchDog = DateTime.Now.AddMinutes(-1);
        }

        #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 taskOk = false;
            string taskVal = "";
            // inizio VUOTO
            byte[] MemBlock = new byte[1];
            string memAddrWrite = "";
            if (task2exe != null)
            {
                // cerco task specifici: se ho startSetup --> imposto bit DBB701.DBB0.4
                foreach (var item in task2exe)
                {
                    taskOk = false;
                    taskVal = "";
                    memAddrWrite = "";
                    // 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.forceSetPzCount:
                        case taskType.stopSetup:
                            taskVal = $"taskReq: {tName} | key: {item.Key} | val: {item.Value} | SKIPPED | NO EXEC";
                            break;

                        case taskType.forceResetPzCount:
                        case taskType.startSetup:
                            // alzo il bit x registrare richiesta reset contapezzi... POI quando ha
                            // eseguito abbassa il PLC il bit a zero...
                            MemBlock[0] = 1;
                            memAddrWrite = "DB1001.DBB88";
                            break;

                        case taskType.setArt:
                        case taskType.setComm:
                        case taskType.setProg:

                            int byteSize = 0;
                            upsertKey(item.Key, item.Value);
                            // 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];
                                switch (currMem.tipoMem)
                                {
                                    case plcDataType.Boolean:
                                        break;

                                    case plcDataType.Int:
                                        saveIntOnMemBlock(ref MemBlock, item.Key, 0);
                                        break;

                                    case plcDataType.DInt:
                                        saveDIntOnMemBlock(ref MemBlock, item.Key, 0);
                                        break;

                                    case plcDataType.Real:
                                        saveRealOnMemBlock(ref MemBlock, item.Key, 0);
                                        break;

                                    case plcDataType.String:
                                        saveStringOnMemBlock(ref MemBlock, item.Key, 0, byteSize);
                                        break;

                                    default:
                                        break;
                                }
                            }
                            taskVal = item.Value;
                            break;

                        case taskType.setParameter:
                            // richiedo da URL i parametri WRITE da popolare
                            lgInfo("Chiamata processMemWriteRequests");
                            taskVal = processMemWriteRequests();
                            // se restituiscce "" faccio altra prova...
                            if (!string.IsNullOrEmpty(taskVal))
                            {
                                taskOk = true;
                            }
                            else
                            {
                                // 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";
                                }
                            }
                            // alzo il bit x registrare RICHEISTA modifica (secondo BIT)... POI
                            // quando ha eseguito abbassa il PLC il bit a zero...
                            MemBlock[0] = 2;
                            memAddrWrite = "DB1001.DBB88";
                            break;

                        case taskType.sendWatchDogMes2Plc:
                            //// compogo in byte... primo bit è setup/run, ultimo è watchdog
                            //int valore = inSetup ? 1 : 0;
                            int valore = counterMes2Plc;
                            MemBlock[68] = (byte)valore;
                            taskVal = $"VALUE DB1001.68 --> {counterMes2Plc}";
                            break;

                        default:
                            taskVal = "SKIPPED | NO EXEC";
                            break;
                    }

                    // aggiungo task!
                    taskDone.Add(item.Key, taskVal);
                    if (!string.IsNullOrEmpty(memAddrWrite))
                    {
                        // scrivo!
                        taskOk = S7WriteBB(ref MemBlock, memAddrWrite);
                    }
                    if (!taskOk)
                    {
                        lgError($"Errore in S7WriteBB durante executeTasks: {item.Key} | {item.Value}");
                    }
                }
            }

            return taskDone;
        }

        /// <summary>
        /// Effettua processing del recupero delle OVERRIDE (spindle, feedrate, rapid)
        /// </summary>
        public override void processOverride()
        {
        }

        public override void processWhatchDog()
        {
            //NON SERVE!!!!
        }

        #endregion Public Methods

        #region Protected Fields

        protected int counterMes2Plc = 0;
        protected int counterPlc2Mes = 0;
        protected DateTime lastPLCWatchDog;

        #endregion Protected Fields

        #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
             * B0: POWER_ON
             * B1: RUN
             * B2: pzCount
             * B3: allarme
             * B4: manuale
             * B5: avvio/spegnimento
             * B6: emergenza
             *
             *
             * - BYTE di stato
             *  - +0.0 AutoStatus BYTE B#16#0 Valore 0=Fermo/1->3=Avviamento/4=Avviato/5=Pausa/6->8spegnimento/9->10 allarme
             *  - +1.0 Dosatore BYTE B#16#0 Stato (bit0=in avviamento/1=marcia sx/2=marcia dx/3=in allarme/4=by-pass on)
             *  - +2.0 V_Dosatore BYTE B#16#0 Stato (bit0=in avviamento/1=marcia sx/2=marcia dx/3=in allarme/4=by-pass on)
             *  - +3.0 Nas_Lancio BYTE B#16#0 Stato (bit0=in avviamento/1=marcia sx/2=marcia dx/3=in allarme/4=by-pass on)
             *  - +4.0 Cilindro BYTE B#16#0 Stato (bit0=in avviamento/1=marcia sx/2=marcia dx/3=in allarme/4=by-pass on)
             *  - +5.0 Bruciatore BYTE B#16#0 Stato (bit0=in avviamento/1=marcia sx/2=marcia dx/3=in allarme/4=by-pass on)
             *  - +6.0 Aspiratore BYTE B#16#0 Stato (bit0=in avviamento/1=marcia sx/2=marcia dx/3=in allarme/4=by-pass on)
             *  - +7.0 Nas_Raccolta BYTE B#16#0 Stato (bit0=in avviamento/1=marcia sx/2=marcia dx/3=in allarme/4=by-pass on)
             *  - +8.0 Nas_Brandeg BYTE B#16#0 Stato (bit0=in avviamento/1=marcia sx/2=marcia dx/3=in allarme/4=by-pass on)
             *  - +9.0 Coclea_Filtro BYTE B#16#0 Stato (bit0=in avviamento/1=marcia sx/2=marcia dx/3=in allarme/4=by-pass on)
             *  - +10.0 Ciclico_Filtro BYTE B#16#0 Stato (bit0=in avviamento/1=marcia sx/2=marcia dx/3=in allarme/4=by-pass on)
             ----------------------------------------------------- */

            // recupero byte segnali...
            int byteSignals = RawInput[0];

            // bit 0 (poweron) imposto a 1 SE connected...
            B_input = currPLC.IsConnected ? 1 : 0;

            // avviamento --> manuale
            switch (byteSignals)
            {
                case 0:
                    B_input = 1;
                    break;

                case 1:
                case 2:
                case 3:
                    B_input += (1 << 5);
                    break;

                case 4:
                    B_input += (1 << 1);
                    break;

                case 5:
                    B_input += (1 << 4);
                    break;

                case 6:
                case 7:
                case 8:
                    B_input += (1 << 5);
                    break;

                case 9:
                    B_input += (1 << 3);
                    break;

                case 10:
                    B_input += (1 << 6);
                    break;

                default:
                    break;
            }

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

        #endregion Protected Methods
    }
}