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

namespace IOB_WIN_SIEMENS.IobSiemens
{
    /// <summary>
    /// Controllo Siemens specifico x impianti COMECA (gestione GNL x Pizzaferri)
    /// </summary>
    public class SiemensComeca : Siemens
    {
        /* --------------------------------------------------------------------------------
         * Controlli SIEMENS COMECA
         * - basasto su SIEMENS
         * - S7 vers 1500
         *
         * STRUTTURA MEMORIA DB85:
         * lettura:     260 byte,
         * scrittura    32 byte
         * G:\Drive condivisi\30_Clienti\Pizzaferri\Impianti\Comeca
         *
         * Si intende lettura/scrittura con DB85.DBxx
         *
         * READ
         * Si leggono parametri impianti + eventuali allarmi
         * 000...151    R   --> Variabili ANALOGICHE
         * 152...183    R   --> parametri
         * 232...259    R   --> allarmi
         *
         * WRITE
         * 268...271    R   --> Word conferma comandi (ACK)
         * 280...288    W   --> parametri inviati (WRITE)
         * 308...309    W   --> conferma invio (STR)
         *
         * -------------------------------------------------------------------------------- */

        #region Public Constructors

        /// <summary>
        /// Classe base con i metodi x Siemens
        /// </summary>
        /// <param name="caller">Form chiamante</param>
        /// <param name="IobConfFull">Configurazione (v 4.x)</param>
        public SiemensComeca(AdapterFormNext caller, IobConfTree IobConfFull) : base(caller, IobConfFull)
        {
            lgInfo("NEW IOB SIEMENS versione Comeca");
        }

        #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)
        {
            lgInfo($"Chiamata executeTasks specifica IobSiemensComeca: {task2exe.Count} task ricevuti");
            // 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);
                    // 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:
                        case taskType.setPzComm:
                        case taskType.setArt:
                        case taskType.setComm:
                            taskVal = $"taskReq: {tName} | key: {item.Key} | val: {item.Value} | SKIPPED | NO EXEC";
                            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";
                                }
                            }

                            // aggiunta finale bit a 1 x richiesta processing..
                            MemBlock = S7.Net.Types.Int.ToByteArray(1);
                            memAddrWrite = "DB85.DBB308";
                            // imposto valore strobe x check successivi
                            strobeVal = 1;

                            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;
        }

        #endregion Public Methods

        #region Protected Fields

        protected int strobeVal = 0;

        #endregion Protected Fields

        #region Protected Methods

        /// <summary>
        /// Effettua decodifica aree memoria alla bitmap usata x MAPO
        /// - per lo scopo specifico IN REALTA' non conta lo stato macchina.... ma lo inviamo lo stesso
        /// </summary>
        protected override void decodeToBaseBitmap()
        {
            // init a zero...
            B_input = 0;

            /* -----------------------------------------------------
             * bitmap MAPO STANDARD
             * B0: POWER_ON
             * B1: RUN
             * B2: pzCount
             * B3: allarme
             *
             ----------------------------------------------------- */

            //bool fatto = false;
            //ushort valW = 0;

            var MemInt = new byte[2];

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

            // processo dagli stati + gravi...
            if (hasAlarms())
            {
                byteSignals += (1 << 3);
            }
            else
            {
                byteSignals += (1 << 1);
            }

            // verifico SE ho strobe/hack da chiudere
            if (strobeVal != 0)
            {
                checkStrobeHack();
            }
            // salvo!
            B_input = byteSignals;
        }

        /// <summary>
        /// Effettua verifica se abilitato invio pezzi in blocco e nel caso
        /// - invio in blocco pezzi
        /// - aggiornamento del contapezzi (passato come ref) x nuovo valore post invio
        /// </summary>
        protected override void trySendPzCountBlock()
        {
            // non fa nulla se non accettare lato IOB i pezzi del PLC... su GWMS NON è gestito il contapezzi
            if (contapezziIOB != contapezziPLC)
            {
                contapezziIOB = contapezziPLC;
                lgTrace($"Registrata variazione contapezzi");
            }
        }

        #endregion Protected Methods

        #region Private Methods

        private void checkStrobeHack()
        {
            // verifico SE ho un hack sulla var DB85.DB268
            byte[] byteCtrlW = new byte[2];
            bool fatto = S7ReadBB(ref byteCtrlW, "DB85.DBB268", 2);
            ushort valCtrlW = S7.Net.Types.Word.FromByteArray(byteCtrlW.ToArray());
            // se vale 1 --> resetto strobe!
            if (valCtrlW == 1)
            {
                // aggiunta finale bit a 0 x chiusura processing..
                var MemBlock = S7.Net.Types.Int.ToByteArray(0);
                var memAddrWrite = "DB85.DBB308";
                // imposto valore strobe x check successivi
                var taskOk = S7WriteBB(ref MemBlock, memAddrWrite);
                if (taskOk)
                {
                    strobeVal = 0;
                }
            }
            else
            {
                lgInfo("SiemensComeca: Strobe attivo su DBB308, ack non rilevato su DBB268");
            }
        }

        #endregion Private Methods
    }
}