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

namespace IOB_WIN_SIEMENS.IobSiemens
{
    public class SiemensFape : Siemens
    {
        /* --------------------------------------------------------------------------------
         * Controlli SIEMENS FAPE (es punzonatrice Tecnomeccanica di LVF)
         * - basasto su SIEMENS
         * - S7 vers 1200
         * - V1.0 (2018): abilitata 1 area in lettura DB15 ed 1 in scrittura DB16 (NON la usano)
         * - x poter funzionare --> protezione: meccanismi di collegamento / consenti put/get
         * - lettura/scrittura primi 48 byte (240 max x le due DB)
         *
         * Versione 2018
         * DB15 | Read seguenti byte:
         * - B0, WORD, Stato Macchina Generale
         * - B2, WORD, Posizione sequenza contatore
         * - B4, WORD, contatore cicli eseguiti per lubrifica
         * - B40, DWORD, contapezzi azzerabile da operatore
         * - B44, DWORD, contapezzi ASSOLUTO
         *
         * -------------------------------------------------------------------------------- */

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

        #endregion Public Constructors

        #region Public Methods

        /// <summary>
        /// Recupero dati override in formato dictionary
        /// </summary>
        /// <returns></returns>
        public override Dictionary<string, string> getDynData()
        {
            Dictionary<string, string> outVal = new Dictionary<string, string>();
            ushort valStatus = S7.Net.Types.Word.FromByteArray(RawInput.Skip(0).Take(2).ToArray());
            ushort valPosit = S7.Net.Types.Word.FromByteArray(RawInput.Skip(2).Take(2).ToArray());
            outVal.Add("CURR_STATO", ((stMacc2018)valStatus).ToString());
            outVal.Add("CURR_POSIT", ((posSeq2018)valPosit).ToString());
            return outVal;
        }

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

        #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;
            // FAPE: leggo i primi 2 WORD x decodifica stato e posizione...
            ushort valStatus = S7.Net.Types.Word.FromByteArray(RawInput.Skip(0).Take(2).ToArray());
            ushort valPosit = S7.Net.Types.Word.FromByteArray(RawInput.Skip(2).Take(2).ToArray());
            stMacc2018 _stMacch = ((stMacc2018)valStatus);
            posSeq2018 _posSeq = ((posSeq2018)valPosit);

            /* -----------------------------------------------------
             * bitmap MAPO
             * B0: POWER_ON
             * B1: RUN
             * B2: pzCount
             * B3: allarme
             * B4: manuale
             * B5: emergenza
            ----------------------------------------------------- */

            // bit 0 (poweron) imposto a 1 SE connected...
            B_input = currPLC.IsConnected ? 1 : 0;
            // controllo stato macchina x impostare altri bit...
            switch (_stMacch)
            {
                case stMacc2018.EMERGENZA_INSERITA:
                    B_input += (1 << 5);
                    break;

                case stMacc2018.AVARIA_ARIA:
                case stMacc2018.AVARIA_PRESSIONE_OLIO:
                case stMacc2018.AVARIA_LIVELLO_OLIO:
                case stMacc2018.AVARIA_TEMPERATURA_OLIO:
                    B_input += (1 << 3);
                    B_input += (1 << 6);
                    break;

                case stMacc2018.AVARIA_MOTORE_POMPA_IDRAULICA:
                case stMacc2018.AVARIA_MOTORE_RAFFREDDO_IDRAULICA:
                case stMacc2018.COMUNICAZIONE_ASSENTE:
                case stMacc2018.AVARIA_SINCRONISMO_PORTE:
                case stMacc2018.AVARIA_LIBERA:
                case stMacc2018.ATTIVAZIONE_IN_CORSO:
                    B_input += (1 << 3);
                    break;

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

                case stMacc2018.CICLO_IN_CORSO:
                    B_input += (1 << 1);
                    break;

                case stMacc2018.MODO_AUTOMATICO_LOCALE:
                case stMacc2018.MODO_AUTOMATICO_ROBOT:
                    B_input += (1 << 7);
                    break;

                case stMacc2018.LIBERO:
                default:
                    break;
            }

            // procedo SOLO SE è enabled IOB
            if (IobOnline)
            {
                // 2026.04.24 controllo ODL solo se son passati ALMENO 10 sec
                int newIdx = CurrOdl();
                currODL = $"{currIdxODL}";
            }
            else
            {
                // imposto currODL a vuoto!
                currODL = "";
                if (periodicLog)
                {
                    lgInfo($"Fanuc | Lettura ODL non effettuata: IobOnline: {IobOnline} | currODL impostato a vuoto");
                }
            }
            // verifico NON sia vietato gestione contapezzi
            if (!plcPzCountValid || !rawInputRead)
            {
                lgInfo($"Veto check contapezzi e ODL fino alle {dtVetoReadPzCount}");
            }
            else
            {
                if (!string.IsNullOrEmpty(currODL) && currIdxODL > 0)
                {
                    // ora processo il contapezzi... controllo se è passato intervallo minimo tra 2
                    // controlli/elaborazioni x distanziare invio e ridurre letture
                    if (DateTime.Now >= lastPzCountSend.AddMilliseconds(pzCountDelay))
                    {
                        // se sono differenti MOSTRO...
                        if (contapezziPLC != contapezziIOB)
                        {
                            // registro contapezzi
                            lgInfo($"Differenza Contapezzi: contapezziPLC: {contapezziPLC} | contapezziIOB {contapezziIOB}");
                        }
                        // verifico se variato contapezzi... e se passato ritardo minimo...
                        if (contapezziPLC > contapezziIOB)
                        {
                            // salvo nuovo contapezzi (incremento di 1...) + richiesta refresh conteggio
                            contapezziIOB++;
                            needRefreshPzCount = true;
                            // salvo in semaforo!
                            B_input += (1 << 2);
                            // registro contapezzi
                            lgInfo($"contapezziPLC SIEMENS: {contapezziPLC} | contapezziIOB {contapezziIOB}");
                        }
                        if (needRefreshPzCount)
                        {
                            // invio a server contapezzi (aggiornato)
                            string retVal = utils.callUrl(urlSetPzCount + contapezziIOB.ToString());
                            // verifica se tutto OK
                            if (retVal != contapezziIOB.ToString())
                            {
                                // errore salvataggio contapezzi
                                lgInfo($"Errore salvataggio Contapezzi SIEMENS: contapezziPLC {contapezziPLC} | contapezziIOB {contapezziIOB} | risposta: {retVal}");
                                // rileggo il counter pezzi da server
                                pzCntReload(true);
                            }
                            // resetto timer...
                            lastPzCountSend = DateTime.Now;
                        }
                    }
                }
                else
                {
                    if (DateTime.Now >= lastPzCountSend.AddMilliseconds(pzCountDelay))
                    {
                        lgInfo($"Attenzione: mancanza ODL non procedo con gestione contapezzi. contapezziPLC SIEMENS {contapezziPLC} | contapezziIOB {contapezziIOB}");
                        // resetto timer...
                        lastPzCountSend = DateTime.Now;
                    }
                }
            }

            // log opzionale!
            if (verboseLog)
            {
                lgInfo(string.Format("Trasformazione B_input: {0}", B_input));
            }
        }

        #endregion Protected Methods

        #region Private Enums

        /// <summary>
        /// Posizione sequenza ciclo standard punzonatrice
        /// </summary>
        private enum posSeq2018
        {
            CICLO_AUTOMATICO_FERMO = 0,
            CONTROLLO_MODO_OPERATIVO = 5,
            MODO_ATTIVO_CON_ROBOT = 8,
            SBLOCCAGGIO_PEZZO = 10,
            APERTURA_PORTELLO_ROBOT = 11,
            CONSENSO_ACCESSO_AL_ROBOT = 12,
            CARICO_ROBOT_IN_CORSO = 14,
            CARICO_ROBOT_CONCLUSO = 16,
            CHIUSURA_PORTELLO_ROBOT = 18,
            VERIFICA_POSIZIONE_CARRI = 20,
            BLOCCAGGIO_PEZZO = 22,
            ATTESA_CARRO_A_DESTRA = 24,
            DISCESA_RAPIDO_BROCCIATURA = 25,
            CICLO_DI_BROCCIATURA = 26,
            RITORNO_BROCCIATRICE = 28,
            COMANDO_CARRO_A_SINISTRA = 30,
            CICLO_DI_ALESATURA = 32,
            RITORNO_CARRO_ALESATURA = 34,
            COMANDO_CARRO_A_DESTRA = 36,
            INCREMENTO_CONTAPEZZI = 38,
            CONTROLLO_TIME_OUT_CICLO = 40,
            RILANCIO_CICLO_F42 = 42,
            ATTESA_FINE_CICLO = 45
        }

        /// <summary>
        /// Enum degli stati macchina (B0)
        /// </summary>
        private enum stMacc2018
        {
            COMUNICAZIONE_ASSENTE = 0,
            EMERGENZA_INSERITA = 1,
            AVARIA_ARIA = 2,
            AVARIA_PRESSIONE_OLIO = 3,
            AVARIA_LIVELLO_OLIO = 4,
            AVARIA_TEMPERATURA_OLIO = 5,
            AVARIA_MOTORE_POMPA_IDRAULICA = 6,
            AVARIA_MOTORE_RAFFREDDO_IDRAULICA = 7,
            AVARIA_SINCRONISMO_PORTE = 8,
            AVARIA_LIBERA = 9,
            ATTIVAZIONE_IN_CORSO = 10,
            MODO_MANUALE_ATTREZZAGGIO = 11,
            MODO_AUTOMATICO_LOCALE = 12,
            MODO_AUTOMATICO_ROBOT = 13,
            CICLO_IN_CORSO = 14,
            LIBERO = 15
        }

        #endregion Private Enums
    }
}