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

namespace IOB_WIN_BECKHOFF.IobBeckhoff
{
    public class BeckhoffCpa : IobBeckhoff.Beckhoff
    {
        #region Public Constructors

        /// <summary>
        /// Estende l'init della classe base
        /// </summary>
        /// <param name="caller">Form chiamante</param>
        /// <param name="IobConfFull">Configurazione (v 4.x)</param>
        public BeckhoffCpa(AdapterFormNext caller, IobConfTree IobConfFull) : base(caller, IobConfFull)
        {
            lgInfo("START IobBeckhoffCPA Adapter specifico");

            // leggo le altre conf standard...
            if (!string.IsNullOrEmpty(getOptPar("CPA_STATE_VAR")))
            {
                statusVar = getOptPar("CPA_STATE_VAR");
            }
            if (!string.IsNullOrEmpty(getOptPar("CPA_PZCOUNT")))
            {
                counterVar = getOptPar("CPA_PZCOUNT");
            }

            if (getOptPar("ADD_VARS").ToLower() == "true")
            {
                // fixme conf var gestite ad eventi da json
                dataVal.Add(statusVar);
            }

            if (getOptPar("EARLY_CONNECT").ToLower() == "true")
            {
                tryConnect();
            }
            if (AdsCli != null)
            {
                readCurrVal();
            }
        }

        #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 IobBeckhoffCpa: {task2exe.Count} task ricevuti");
            // Verificare il protocollo: dovrebeb togliere SOLO i task eseguiti...
            Dictionary<string, string> taskDone = new Dictionary<string, string>();
            string taskVal = "";
            // inizio con 1 byte di default
            byte[] MemBlock = new byte[1];
            if (task2exe != null)
            {
                // cerco task specifici
                foreach (var item in task2exe)
                {
                    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";
                            break;

                        case taskType.setPzComm:
                            AdsCli.WriteVariabile(setPzReqVar, item.Value);
                            AdsCli.WriteVariabile(setParamsVar, 1);
                            break;

                        case taskType.setArt:
                            AdsCli.WriteVariabile(setArtVar, item.Value);
                            AdsCli.WriteVariabile(setParamsVar, 1);
                            break;

                        case taskType.setComm:
                            AdsCli.WriteVariabile(setCommVar, item.Value);
                            AdsCli.WriteVariabile(setParamsVar, 1);
                            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..
                            AdsCli.WriteVariabile(setParamsVar, 1);

                            break;

                        default:
                            taskVal = "SKIPPED | NO EXEC";
                            break;
                    }
                    // aggiungo task!
                    taskDone.Add(item.Key, taskVal);
                }
            }
            return taskDone;
        }

        /// <summary>
        /// Effettua vero processing contapezzi
        /// </summary>
        public override void processContapezzi()
        {
            if (utils.CRB("enableContapezzi"))
            {
                var rawCount = AdsCli.ReadVariabile(counterVar).ToString();
                if (!string.IsNullOrEmpty(rawCount))
                {
                    int newVal = -1;
                    int.TryParse(rawCount, out newVal);
                    contapezziPLC = newVal > -1 ? newVal : contapezziPLC;
                }
            }
        }

        /// <summary>
        /// Leggo le variabili correnti (status, contapezzi)
        /// </summary>
        public override void readCurrVal()
        {
            var rawStatus = AdsCli.ReadVariabile(statusVar).ToString();
            if (!string.IsNullOrEmpty(rawStatus))
            {
                int.TryParse(rawStatus, out currStatus);
            }
            var rawCount = AdsCli.ReadVariabile(counterVar).ToString();
            if (!string.IsNullOrEmpty(rawCount))
            {
                int newVal = -1;
                int.TryParse(rawCount, out newVal);
                contapezziPLC = newVal > -1 ? newVal : contapezziPLC;
            }
        }

        /// <summary>
        /// Effettua lettura semafori principale <paramref name="currDispData">Parametri da
        /// aggiornare x display in form</paramref>
        /// </summary>
        public override void readSemafori(ref newDisplayData currDispData)
        {
            /* -----------------------------------------------------
               * STATE MACHINE 60
               * --------------------------
               * bitmap MAPO
               * B0: POWER_ON
               * B1: RUN
               * B2: pzCount
               * B3: allarme
               * B4: manuale
               * B5: slowTC
               * B6: WarmUpCoolDown
               * B7: emergenza
               *
               * --------------------------
               * Enum Stato macchina
               * --------------------------
               * Errore = -1,
               * Ferma = 0,
               * Automatica = 1,
               * Manuale = 2,
               * Emergenza = 3,
               * AzzeraTavola = 4,
               * ManualeStazione = 5,
               * Avviamento = 7
              ----------------------------------------------------- */

            byte[] MemBlock = new byte[2];
            try
            {
                if (connectionOk)
                {
                    B_input = 1;
                    currDispData.semIn = Semaforo.SV;
                }
                else
                {
                    B_input = 0;
                    currDispData.semIn = Semaforo.SR;
                }
                // indico emergenza ARMATA
                B_input += (1 << 7);

                // in base all'enum di status compilo valori...
                switch (currStatus)
                {
                    case -1:
                        B_input += (1 << 3);
                        break;

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

                    case 3:
                        // tolgo emergenza SE fosse premuta (force zero)
                        B_input &= ~(1 << 7);
                        break;

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

                    default:
                        break;
                }
            }
            catch
            {
                currDispData.semIn = Semaforo.SR;
            }
        }

        public override void setEventHandler()
        {
            base.setEventHandler();
            if (AdsCli != null)
            {
                AdsCli.StatusChanged += AdsCli_StatusChanged;
                AdsCli.CountChanged += AdsCli_CountChanged;
                AdsCli.ValueChanged += AdsCli_ValueChanged;
            }
        }

        #endregion Public Methods

        #region Protected Fields

        protected int currStatus = 0;

        #endregion Protected Fields

        #region Protected Methods

        protected void AdsCli_CountChanged(TcAdsClient sender, int newCount)
        {
            contapezziPLC = newCount;
            lgInfo($"Nuova lettura contapezzi | contapezziPLC: {contapezziPLC} | contapezziIOB: {contapezziIOB}");
        }

        protected void AdsCli_StatusChanged(TcAdsClient sender, int newStatus)
        {
            currStatus = newStatus;
            lgInfo($"Status changed: {newStatus}");
        }

        #endregion Protected Methods

        #region Private Fields

        private string counterVar = "VarADS.BuoniLancio";
        private string setArtVar = "VarADS.NomeDisegnoRichiesto";
        private string setCommVar = "VarADS.NomeLancioRichiesto";
        private string setParamsVar = "VarADS.bCambioArticolo";
        private string setPzReqVar = "VarADS.nQuantitaRichiesta";
        private string statusVar = "VarADS.StatoMacchina";

        #endregion Private Fields

#if false
        public enum EnuStates  //Stato Macchina
        {
            Errore = -1,
            Ferma = 0,
            Automatica = 1,
            Manuale = 2,
            Emergenza = 3,
            AzzeraTavola = 4,
            ManualeStazione = 5,
            Avviamento = 7,
        }
#endif
    }
}