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 COMUR
    /// </summary>
    public class SiemensComur : Siemens
    {
        /* --------------------------------------------------------------------------------
         * Controlli SIEMENS COMUR
         * - basasto su SIEMENS
         * - S7 vers 1500
         *
         * STRUTTURA MEMORIA DB150: 56 byte lettura, di cui 4 byte scrittura (4..7), vedere doc allegato
         * G:\Drive condivisi\30_Clienti\Valvital\Comunicazione PLC\COMUR Dentatrice
         *
         * Si intende tutto con DB150.DBxx
         *
         * - parametri processo PLC --> MES
         *   - DBX0.0 - Macchina On: Segnale pulito di informazione sullo stato della macchina. 0->Aux OFF, 1->Aux ON
         *   - DBX0.1 – Macchina in Allarme: Segnale pulito di macchina in allarme. 0->Nessun Allarme, 1->E’ presente almeno un allarme/anomalia
         *   - DBX0.2 – Macchina in Ciclo: Segnale pulito sullo stato di funzionamento. 0->La macchina NON sta eseguendo un ciclo automatico, 1->La macchina sta eseguendo un ciclo automatico.
         *   - DBX0.3 – Macchina Non in Produzione: Segnale pulito sullo stato della macchina. 0->Macchina accesa e in lavorazione automatica, 1->Macchina accesa ma NON sta eseguendo un ciclo automatico.
         *   - DBX0.4 – Macchina In Ciclo Continuità: Segnale pulito sullo stato di funzionamento. 1->La macchina sta eseguendo un ciclo automatico con carico/scarico pezzo autonomo, 0->Altrimenti.
         *   - DBX0.7 – Assi In Moto: Segnale pulito sullo stato di movimento Assi. 0->Tutti gli assi della macchina sono fermi, 1->Almeno un asse si sta muovendo.
         *   - DBX1.0 – Impulso Start Ciclo: Impulso a fronte positivo (0->1) della durata di 1’’ che rappresenta l’evento di Start Ciclo.
         *   - DBX1.1 – Impulso Fine Ciclo: Impulso a fronte positivo (0->1) della durata di 1’’ che rappresenta l’evento di Fine Ciclo. Attenzione! Questo impulso viene generato solo se il Ciclo Automatico finisce correttamente. Non viene generato nel caso in cui il Ciclo Automatico venga interrotto da allarmi.
         *   - DBX1.3 – Impulso Conta Pezzi: Impulso a fronte positivo (0->1) della durata di 1’’ generato al completamento di ogni programma pezzo.
         *   - DBX2.0 – Preallarmi Pezzi: Segnale pulito di segnalazione Preallarme Pezzi impostabile su CN. 0->Preallarme Disattivo, 1->Preallarme Attivo
         *   - DBX2.1 – Allarme Pezzi: Segnale pulito di segnalazione Allarme Pezzi impostabile su CN. 0->Allarme Disattivo, 1->Allarme Attivo.
         *   - DBX2.3 – Fine Vita Utensile: Segnale pulito di segnalazione Allarme Fine Vita Creatore. 0->Allarme Disattivo, 1->Allarme Attivo.
         *   - DBX2.7 – Ciclo In Attesa: Segnale pulito sullo stato di funzionamento. 1->Ciclo Automatico attivo ma tutti assi fermi, 0->Altrimenti.
         *
         *   - DBD52 - Codice Pezzo In Lavorazione (4byte, REAL)
         *   - DBD56 - Codice Utensile In Uso (4byte, REAL)
         *
         *
         * - parametri processo MES --> PLC
         *   - DBX4.0 – Reset Contapezzi Parziale: Segnale per resettare il valore del contatore “Contapezzi parziale”. Impostare il bit a 1 per attivare la funzione (il PLC riporterà a 0 il valore quando completa l’operazione).
         *
         *   - DB150.DBD8 - Numero di Pezzi da produrre per il lotto (4byte, DInt)
         *   - DB150.[12.0 .. 31.7] - Codice articolo (stringa da 18 char)
         *   - DB150.[32.0 .. 51.7] - Codice commessa (stringa da 18 char)
         *
         *
         * - DB111.DBD24:  PartCounter	INT	2.0	Conteggio Parziale di pezzi prodotti dalla macchina
         * -------------------------------------------------------------------------------- */

        #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 SiemensComur(AdapterFormNext caller, IobConfTree IobConfFull) : base(caller, IobConfFull)
        {
            lgInfo("NEW IOB SIEMENS versione COMUR");
        }

        #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 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);
                    // init valori
                    int byteSize = 0;
                    int valDInt = 0;
                    short valShort = 0;

                    // controllo sulla KEY
                    switch (tName)
                    {
                        case taskType.nihil:
                        case taskType.fixStopSetup:
                        case taskType.forceResetPzCount:
                        case taskType.forceSetPzCount:
                        case taskType.setProg:
                        case taskType.sendWatchDogMes2Plc:
                            taskVal = $"taskReq: {tName} | key: {item.Key} | val: {item.Value} | SKIPPED | NO EXEC";
                            break;

                        case taskType.setArt:
                        case taskType.setComm:
                        case taskType.setPzComm:
                            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];
                                if (currMem.tipoMem == plcDataType.String)
                                {
                                    saveStringOnMemBlock(ref MemBlock, item.Key, 0, byteSize);
                                }
                                else if (currMem.tipoMem == plcDataType.DInt)
                                {
                                    int.TryParse(item.Value, out valDInt);
                                    MemBlock = S7.Net.Types.DInt.ToByteArray(valDInt);
                                }
                                else if (currMem.tipoMem == plcDataType.Int)
                                {
                                    short.TryParse(item.Value, out valShort);
                                    MemBlock = S7.Net.Types.Int.ToByteArray(valShort);
                                }
                            }
                            taskVal = item.Value;
                            break;

                        case taskType.startSetup:
                            // resetto IN PRIMIS il contapezzi...
                            valDInt = 0;
                            int.TryParse(item.Value, out valDInt);
                            MemBlock = S7.Net.Types.DInt.ToByteArray(valDInt);
                            memAddrWrite = "DB150.DBB24";
                            S7WriteBB(ref MemBlock, memAddrWrite);

                            // processo scrittura BIT su DB150.DBX4.0
                            MemBlock = new byte[1];
                            MemBlock[0] = (byte)1;
                            memAddrWrite = "DB150.DBB4";
                            break;

                        case taskType.stopSetup:
                            // resetto IN PRIMIS il contapezzi...
                            valDInt = 0;
                            int.TryParse(item.Value, out valDInt);
                            MemBlock = S7.Net.Types.DInt.ToByteArray(valDInt);
                            memAddrWrite = "DB150.DBB24";
                            S7WriteBB(ref MemBlock, memAddrWrite);

                            // processo scrittura BIT su DB150.DBX4.0
                            MemBlock = new byte[1];
                            MemBlock[0] = (byte)0;
                            memAddrWrite = "DB150.DBB4";
                            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))
                            {
                                // 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;
                    }
                    // 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} | taskOk {taskOk}");
                    }
                }
            }
            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
             * B0: POWER_ON
             * B1: RUN
             * B2: pzCount
             * B3: allarme
             * B4: manuale
             * B5: allarme creatore
             *
             *
             * - BIT di stato
             *   - DBX0.0 - Macchina On: Segnale pulito di informazione sullo stato della macchina. 0->Aux OFF, 1->Aux ON
             *   - DBX0.1 – Macchina in Allarme: Segnale pulito di macchina in allarme. 0->Nessun Allarme, 1->E’ presente almeno un allarme/anomalia
             *   - DBX0.2 – Macchina in Ciclo: Segnale pulito sullo stato di funzionamento. 0->La macchina NON sta eseguendo un ciclo automatico, 1->La macchina sta eseguendo un ciclo automatico.
             *   - DBX0.3 – Macchina Non in Produzione: Segnale pulito sullo stato della macchina. 0->Macchina accesa e in lavorazione automatica, 1->Macchina  accesa ma NON sta eseguendo un ciclo automatico.
             *   - DBX0.4 – Macchina In Ciclo Continuità: Segnale pulito sullo stato di funzionamento. 1->La macchina sta eseguendo un ciclo automatico con   carico/scarico pezzo autonomo, 0-> Altrimenti. NON HA SENSO perché NON HANNO il robot...
             *   - DBX0.7 – Assi In Moto: Segnale pulito sullo stato di movimento Assi. 0->Tutti gli assi della macchina sono fermi, 1->Almeno un asse si sta muovendo.
             *   - DBX1.0 – Impulso Start Ciclo: Impulso a fronte positivo (0->1) della durata di 1’’ che rappresenta l’evento di Start Ciclo.
             *   - DBX1.1 – Impulso Fine Ciclo: Impulso a fronte positivo (0->1) della durata di 1’’ che rappresenta l’evento di Fine Ciclo. Attenzione! Questo impulso viene generato solo se il Ciclo Automatico finisce correttamente. Non viene generato nel caso in cui il Ciclo Automatico venga interrotto da allarmi.
             *   - DBX1.3 – Impulso Conta Pezzi: Impulso a fronte positivo (0->1) della durata di 1’’ generato al completamento di ogni programma pezzo.
             *   - DBX2.0 – Preallarmi Pezzi: Segnale pulito di segnalazione Preallarme Pezzi impostabile su CN. 0->Preallarme Disattivo, 1->Preallarme Attivo
             *   - DBX2.1 – Allarme Pezzi: Segnale pulito di segnalazione Allarme Pezzi impostabile su CN. 0->Allarme Disattivo, 1->Allarme Attivo.
             *   - DBX2.3 – Fine Vita Utensile: Segnale pulito di segnalazione Allarme Fine Vita Creatore. 0->Allarme Disattivo, 1->Allarme Attivo.
             *   - DBX2.7 – Ciclo In Attesa: Segnale pulito sullo stato di funzionamento. 1->Ciclo Automatico attivo ma tutti assi fermi, 0->Altrimenti.
             *
             ----------------------------------------------------- */

            byte mainData = RawInput[0];

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

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

            // considero come MANUALE NON ciclo in continuo...
            if ((mainData & (1 << 3)) != 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
    }
}