using IOB_UT_NEXT;
using IOB_UT_NEXT.Config;
using MapoSDK;
using Newtonsoft.Json;
using Opc.Ua;
using System;
using System.Collections.Generic;

namespace IOB_WIN_OPC_UA.IobOpc
{
    public class OpcUaSiemensOMP : OpcUaSiemens
    {
        #region Public Constructors

        /// <summary>
        /// Estende l'init della classe base, impiegando il pacchetto Nuget OPC-UA foundation con la
        /// gestione specifica per EWON (es Monti, Tenditalia) https://github.com/OPCFoundation/UA-.NETStandard
        /// </summary>
        /// <param name="caller">Form chiamante</param>
        /// <param name="IOBConf">Configurazione (legacy)</param>
        /// <param name="IobConfFull">Configurazione (v 4.x)</param>
        public OpcUaSiemensOMP(AdapterFormNext caller, IobConfTree IobConfFull) : base(caller, IobConfFull)
        {
            sendKeyRichiesta = true;
            lgInfo("Init OpcUa Siemens versione OMP (Cereria Finassi)");
        }

        #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)
        {
            // uso metodo base x salvare esito scrittura
            var writeResult = base.executeTasks(task2exe, codTav);

            // aggiungo comportamento custom: se ho impostato nome ricetta (programma) --> imposto
            // richiesta caricamento se ho richiesto reset o fine lavoro --> imposto azzeramento
            // esco restituendo risultato scrittura iniziali
            if (task2exe != null)
            {
                // controllo se memMap != null...
                if (memMap != null)
                {
                    bool taskOk = false;
                    string taskVal = "";
                    // cerco task specifici x OMP
                    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.setProg:
                                // recupero dati da memMap...
                                if (memMap != null && memMap.mMapWrite != null)
                                {
                                    if (memMap.mMapWrite.ContainsKey(item.Key))
                                    {
                                        dataConf currMem = memMap.mMapWrite[item.Key];
                                        string addr = currMem.memAddr;
                                        taskVal = $"SET task: {item.Key} --> {item.Value} | mem: {currMem.memAddr} - {currMem.size} byte";
                                        // salvo il nuovo valore nella memoria... così prox invio lo trasmetterà
                                        memMap.mMapWrite[item.Key].value = item.Value;
                                    }
                                    else
                                    {
                                        taskVal = $"NO DATA MEM, SET task: {item.Key} --> {item.Value}";
                                    }
                                }
                                else
                                {
                                    taskVal = $"NO MemMap found, SET task: {item.Key} --> {item.Value}";
                                }
                                // salvo in currProd..
                                 upsertKey(item.Key, item.Value);

                                break;

                            case taskType.startSetup:
                                setFineLotto();
                                break;

                            case taskType.stopSetup:
                                setInizioProd();
                                break;

                            default:
                                taskVal = $"taskReq: {tName} | key: {item.Key} | val: {item.Value} | SKIPPED | NO EXEC";
                                lgInfo($"Chiamata senza processing: taskOk: {taskOk} | {taskVal}");
                                break;
                        }
                    }
                }
                else
                {
                    lgError($"Attenzione! memMap è nullo, non posso eseguire task2exe!");
                }
            }

            return writeResult;
        }

        public override bool resetContapezziPLC(string codTav)
        {
            bool answ = false;
            lgInfo("Chiamata resetContapezziPLC");
            try
            {
                List<WriteValue> nodes2Write = new List<WriteValue>();
                foreach (var item in opcUaParams.actResetCounter)
                {
                    WriteValue commWriteVal = new WriteValue();
                    commWriteVal.NodeId = new NodeId(item.Key);
                    commWriteVal.AttributeId = Attributes.Value;
                    commWriteVal.Value = new DataValue();
                    commWriteVal.Value.Value = item.Value;

                    nodes2Write.Add(commWriteVal);
                    lgInfo($"Accodo nodo per scrittura OPC-UA:{Environment.NewLine}{JsonConvert.SerializeObject(commWriteVal)}");
                }
                // vera scrittura
                UA_ref.WriteNodes(nodes2Write);
                answ = true;
                lgInfo($"Eseguito scrittura OPC-UA su nodo actResetCounter");
            }
            catch
            { }
            return answ;
        }

        #endregion Public Methods

        #region Private Methods

        /// <summary>
        /// Azioni specifiche x indicare fine lotto di produzione
        /// </summary>
        /// <returns></returns>
        private bool setFineLotto()
        {
            bool answ = false;
            lgInfo("Chiamata setFineLotto");
            try
            {
                List<WriteValue> nodes2Write = new List<WriteValue>();
                foreach (var item in opcUaParams.actStopProd)
                {
                    WriteValue commWriteVal = new WriteValue();
                    commWriteVal.NodeId = new NodeId(item.Key);
                    commWriteVal.AttributeId = Attributes.Value;
                    commWriteVal.Value = new DataValue();
                    commWriteVal.Value.Value = item.Value;

                    nodes2Write.Add(commWriteVal);
                    lgInfo($"Accodo nodo per scrittura OPC-UA:{Environment.NewLine}{JsonConvert.SerializeObject(commWriteVal)}");
                }
                // vera scrittura
                UA_ref.WriteNodes(nodes2Write);
                answ = true;
                lgInfo($"Eseguito scrittura OPC-UA su nodo actStopProd");
            }
            catch
            { }
            return answ;
        }

        /// <summary>
        /// Azioni specifiche x iniziare produzione (impostazione ricetta)
        /// </summary>
        /// <returns></returns>
        private bool setInizioProd()
        {
            bool answ = false;
            lgInfo("Chiamata setInizioProd");
            try
            {
                List<WriteValue> nodes2Write = new List<WriteValue>();
                foreach (var item in opcUaParams.actSetRecipe)
                {
                    WriteValue commWriteVal = new WriteValue();
                    commWriteVal.NodeId = new NodeId(item.Key);
                    commWriteVal.AttributeId = Attributes.Value;
                    commWriteVal.Value = new DataValue();
                    commWriteVal.Value.Value = item.Value;

                    nodes2Write.Add(commWriteVal);
                    lgInfo($"Accodo nodo per scrittura OPC-UA:{Environment.NewLine}{JsonConvert.SerializeObject(commWriteVal)}");
                }
                // vera scrittura
                UA_ref.WriteNodes(nodes2Write);
                answ = true;
                lgInfo($"Eseguito scrittura OPC-UA su nodo actSetRecipe");
            }
            catch
            { }
            return answ;
        }

        #endregion Private Methods
    }
}