using MapoSDK;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using System.Collections.Generic;
using System;

namespace IOB_UT_NEXT
{
    /// <summary>
    /// Classe gestione configurazione parametri di base x allarmi
    /// </summary>
    public class BaseAlarmConf
    {
        #region Public Properties

        /// <summary>
        /// Elenco dei contatori blink x gestione caso fronte salita/discesa segnale che blinka
        /// </summary>
        public int[] alarmsBlinkCounter { get; set; }

        /// <summary>
        /// BitMask 16bit (1 = valido, 0 = filtro) degli allarmi silenziati/disabilitati (se
        /// iniziano per ##) come valore da sottrarre x check
        /// </summary>
        public uint[] alarmsMask { get; set; }

        /// <summary>
        /// Array dei valori allarme correnti
        /// </summary>
        public uint[] alarmsState { get; set; }

        /// <summary>
        /// valore di partenza x un segnale di blink in caso di fine variazione (fronte discesa)
        /// </summary>
        public int blinkDownVal { get; set; } = 4;

        /// <summary>
        /// valore di partenza x un segnale di blink in caso di inizio variazione (fronte salita)
        /// </summary>
        public int blinkUpVal { get; set; } = 3;

        /// <summary>
        /// Descrizione area allarmi
        /// </summary>
        public string description { get; set; } = "";

        /// <summary>
        /// Indice nell'area di memoria (da valore iniziale = 0)
        /// </summary>
        public int index { get; set; } = 0;

        /// <summary>
        /// Nome "assoluto" della posizione nell'area di memoria (anche diverso da indice)
        /// </summary>
        public string memAddr { get; set; } = "";

        /// <summary>
        /// Elenco allarmi configurati x la bitmap
        /// </summary>
        public List<string> messages { get; set; } = new List<string>();

        /// <summary>
        /// Size in byte
        /// </summary>
        public int size { get; set; } = 0;

        /// <summary>
        /// Tipo di dato
        /// </summary>
        [JsonConverter(typeof(StringEnumConverter))]
        public plcDataType tipoMem { get; set; } = plcDataType.Boolean;


        /// <summary>
        /// Tipo del blocco allarmi configurato
        /// </summary>
        [JsonConverter(typeof(StringEnumConverter))]
        public AlarmBlockType blockType { get; set; } = AlarmBlockType.Bitmap;

        /// <summary>
        /// Livello del blocco memoria
        /// </summary>
        [JsonConverter(typeof(StringEnumConverter))]
        public AlarmLevel blockLevel { get; set; } = AlarmLevel.Alarm;

        /// <summary>
        /// Elenco KEY codici allarme attivabili
        /// </summary>
        public List<string> activeKeys { get; set; } = new List<string>();

        /// <summary>
        /// Elenco VALUE codici allarme attivabili
        /// </summary>
        public List<string> activeValues { get; set; } = new List<string>();


        #endregion Public Properties

        #region Public Methods

        /// <summary>
        /// Calcola il filtro da condizione blink (ovvero maschera per valori indicati blinking)
        /// </summary>
        /// <param name="num"></param>
        /// <returns></returns>
        public uint blinkFilter(int num)
        {
            uint answ = 0;
            int idx = 16 * num;
            for (int i = 0; i < 16; i++)
            {
                if (alarmsBlinkCounter[idx + i] > 0)
                {
                    answ += (uint)1 << i;
                }
            }
            return answ;
        }

        /// <summary>
        /// Effettua update dei contatori blink per gestire i segnali alternati sul fronte di salita/discesa
        /// </summary>
        /// <param name="num"></param>
        /// <param name="newStatus"></param>
        public void checkBlinkCounter(int num, uint newStatus)
        {
            // calcola la maschera di variazione da valore precedente
            var variations = newStatus ^ alarmsState[num];
            // ciclo sui 16 bit...
            for (int i = 0; i < 16; i++)
            {
                // controllo se è variato
                if ((variations & (1 << i)) == (1 << i))
                {
                    // se il valore nuovo è 1 --> è in fronte salita
                    if ((newStatus & (1 << i)) == (1 << i))
                    {
                        // cambio SOLO SE il valore blink è zero...
                        if (alarmsBlinkCounter[num * 16 + i] == 0)
                        {
                            alarmsBlinkCounter[num * 16 + i] = blinkUpVal;
                        }
                    }
                    // altrimenti se è fronte discesa
                    else
                    {
                        // cambio SOLO SE il valore blink è zero...
                        if (alarmsBlinkCounter[num * 16 + i] == 0)
                        {
                            alarmsBlinkCounter[num * 16 + i] = blinkDownVal;
                        }
                    }
                }
            }
            // decremento contatori blink
            int idx = 0;
            foreach (var item in alarmsBlinkCounter)
            {
                alarmsBlinkCounter[idx] = item > 0 ? item - 1 : item;
                idx++;
            }
        }

        /// <summary>
        /// Confronta un valore di stato allarme con lo stato precedentemente salvato considerando blink/veto
        /// </summary>
        /// <param name="num">Numero/indice del banco di allarme (uint16)</param>
        /// <param name="newValue">Valore (bitmap) allarmi come uint16</param>
        /// <returns></returns>
        public bool isChanged(int num, uint newValue)
        {
            // per prima cosa controllo valori RAW
            bool answ = !alarmsState[num].Equals(newValue);
            if (answ)
            {
                // controllo valori filtrati con ## (sottraendo BITMASK dai valori di filtro)
                answ = ((alarmsState[num] & alarmsMask[num]) != (newValue & alarmsMask[num]));
                // se fossero ancora differenti controllo ulteriore mask dato il counter dei blink:
                if (answ)
                {
                    var blinkFilt = blinkFilter(num);
                    answ = ((alarmsState[num] & (alarmsMask[num] & ~blinkFilt)) != (newValue & (alarmsMask[num] & ~blinkFilt)));
                    //answ = ((alarmsState[num] & (alarmsMask[num] | blinkFilt)) != (newValue & (alarmsMask[num] | blinkFilt)));
                }
            }
            return answ;
        }

        /// <summary>
        /// Inizializzazione classe con valori calcolati: attenzione si aspetta banchi da 32 bit...
        /// ATTENZIONE: eseguita solo se blockType == bitmap
        /// </summary>
        public void setupData()
        {
            // verifico si tratti di un tipo allarmi a bitmap... altrimenti salto
            if (blockType == AlarmBlockType.Bitmap)
            {
                // inizializzo vettore valore allarmi x banco int8 x iniziare
                alarmsState = new uint[size];
                alarmsMask = new uint[size];
                int bitSize = 8;

                // 16/32 bit
                if (size > 1)
                {
                    // inizializzo vettore valore allarmi x banco int16
                    alarmsState = new uint[size / 2];
                    alarmsMask = new uint[size / 2];
                    bitSize = 16;
                }

                // una volta inizializzata la classe di base sistemo vettori allarmi disabilitati ed il
                // contatore blink dei fronti di discesa
                alarmsBlinkCounter = new int[messages.Count];
                //verifico i contatori di blink da eventuale conf...

                int idx = 0;
                int bank = 0;
                foreach (var item in messages)
                {
                    if (item.StartsWith("##"))
                    {
                        alarmsBlinkCounter[idx] = -999;
                    }
                    else
                    {
                        alarmsBlinkCounter[idx] = 1;
                        alarmsMask[bank] += (uint)1 << idx;
                    }
                    idx++;
                    // sistemo bank/indice
                    if (idx > bitSize - 1)
                    {
                        bank++;
                        idx = 0;
                    }
                }
            }
        }

        /// <summary>
        /// Effettua il caricamento dello status da un valore precedente (es da cache REDIS)
        /// ATTENZIONE: eseguita solo se blockType == bitmap e size corrisponde a quella della mem allarmi
        /// </summary>
        /// <param name="lastState"></param>
        public void loadPrev(uint[] lastState)
        {
            // verifico si tratti di un tipo allarmi a bitmap... altrimenti salto
            if (blockType == AlarmBlockType.Bitmap)
            {
                if (lastState.Length == alarmsState.Length)
                {
                    alarmsState = lastState;
                }
            }
        }

        /// <summary>
        /// Imposta il valore dello status attuale allarme impostando eventuale valore blink x le variazioni
        /// </summary>
        /// <param name="num"></param>
        /// <param name="newStatus"></param>
        public void updStatusVal(int num, uint newStatus)
        {
            // salvo nuovo valore
            alarmsState[num] = newStatus;
        }

        /// <summary>
        /// Tipologia del blocco allarmi configurato
        /// </summary>
        public enum AlarmBlockType
        {
            /// <summary>
            /// Modalità standard a bitmap
            /// </summary>
            Bitmap,

            /// <summary>
            /// Modalità elenco dei valori attivi (es OPC-UA BLM/Adige)
            /// </summary>
            ActiveList
        }

        /// <summary>
        /// Livello Allarme
        /// </summary>
        public enum AlarmLevel
        {
            /// <summary>
            /// Messaggio (non bloccante)
            /// </summary>
            Message = 0,

            /// <summary>
            /// Avviso (non bloccante)
            /// </summary>
            Warning = 100,

            /// <summary>
            /// Allarme (bloccante)
            /// </summary>
            Alarm = 200,

            /// <summary>
            /// Allarme di massimo livello
            /// </summary>
            Emergency = 300
        }


        #endregion Public Methods
    }

    /// <summary>
    /// Classe gestione configurazione parametri di base x configurazione estesa (es MTConnect,
    /// OPC-UA, ...)
    /// </summary>
    public class BaseParamConf
    {
        #region Public Properties

        /// <summary>
        /// Struttura dati x check condizione LAVORA / Green
        /// </summary>
        public List<diCheckCondition> condWork { get; set; } = new List<diCheckCondition>();

        /// <summary>
        /// Struttura dati x check condizione Manual
        /// </summary>
        public diCheckCondSetup condManual { get; set; } = new diCheckCondSetup();

        /// <summary>
        /// Struttura dati x check condizione EXTRA di controllo x singoli BIT
        /// </summary>
        public Dictionary<int, diCheckCondSetup> bitSpecCond { get; set; } = new Dictionary<int, diCheckCondSetup>();

        /// <summary>
        /// Indica se l'emergenza armata va riportata verso Mapo come bit a TRUE True --&gt; armata
        /// = 1 / triggered = 0 False --&gt; triggered = 1 / armata = 0
        /// </summary>
        public bool emergencyArmedTrue { get; set; } = true;

        /// <summary>
        /// Elenco items FILTRATI da invio come dynData --&gt; FluxLog (events o samples), ricerca SECCA
        /// </summary>
        public List<string> fluxLogVeto { get; set; } = new List<string>();

        /// <summary>
        /// Elenco items FILTRATI da invio come dynData --&gt; FluxLog (events o samples), ricerca testo come contains in displayName
        /// </summary>
        public List<string> fluxLogVetoContains { get; set; } = new List<string>();

        /// <summary>
        /// Indica se il controllo di ping sia OK (x controllo prima della connessione)
        /// </summary>
        public bool forcePingOk { get; set; } = false;

        /// <summary>
        /// Array degli elementi di traduzione item
        /// </summary>
        public Dictionary<string, string> itemTranslation { get; set; } = new Dictionary<string, string>();


        /// <summary>
        /// Indica se decodificare valori dall'area mMapRead da valori byte[] delle variabili sottoscritte
        /// </summary>
        public bool mMapReadFromRawByte { get; set; } = false;
        /// <summary>
        /// Indica se decodificare valori dall'area mMapWrite da valori byte[] delle variabili sottoscritte
        /// </summary>
        public bool mMapWriteFromRawByte { get; set; } = false;

        /// <summary>
        /// Indica se inviare i dati sottoscritti che sono "raw" o meno...
        /// </summary>
        public bool sendSubscribItemsRaw { get; set; } = true;

        /// <summary>
        /// Separatore configurazione area OPC e subObj in caso di memorie struct speciali
        /// </summary>
        public char kvDelim { get; set; } = '#';

        /// <summary>
        /// Separatore definizione aree memoria speciali
        /// </summary>
        public char memDelim { get; set; } = '.';


        /// <summary>
        /// Nome variabile x EmergencyStop
        /// </summary>
        public string keyEStop { get; set; } = "";

        /// <summary>
        /// Nome variabile x ExeMode
        /// </summary>
        public string keyExeMode { get; set; } = "";

        /// <summary>
        /// Nome variabile x pezzi FATTI
        /// </summary>
        public string keyPartCount { get; set; } = "";

        /// <summary>
        /// Indica se sia una macchina MULTI (con varie Tavole/Pallet) 
        /// </summary>
        public bool isMulti { get; set; } = false;

        /// <summary>
        /// Dizionario variabili x pezzi FATTI se multi tavola
        /// </summary>
        public Dictionary<string, string> keyPartCountTav { get; set; } = null;

        /// <summary>
        /// Nome variabile x Codice Articolo
        /// </summary>
        public string keyPartId { get; set; } = "";

        /// <summary>
        /// Nome variabile x pezzi RICHIESTI
        /// </summary>
        public string keyPartReq { get; set; } = "";

        /// <summary>
        /// Nome variabile x NOME PROGRAMMA
        /// </summary>
        public string keyProgName { get; set; } = "";

        /// <summary>
        /// Nome variabile x RunMode
        /// </summary>
        public string keyRunMode { get; set; } = "";

        /// <summary>
        /// Aree di memoria lettura
        /// </summary>
        public Dictionary<string, dataConfTSVC> mMapRead { get; set; } = new Dictionary<string, dataConfTSVC>();

        /// <summary>
        /// Aree di memoria scrittura
        /// </summary>
        public Dictionary<string, dataConf> mMapWrite { get; set; } = new Dictionary<string, dataConf>();

        /// <summary>
        /// Dictionary dei nomi da cercare come "endsWith" a cui applicare la soglia indicata
        /// </summary>
        public Dictionary<string, float> paramsEndThresh { get; set; } = new Dictionary<string, float>();

        /// <summary>
        /// Dictionary dei nomi da cercare come "contains" a cui applicare la soglia indicata
        /// </summary>
        public Dictionary<string, float> paramsContainsThresh { get; set; } = new Dictionary<string, float>();

        /// <summary>
        /// Indica se il ping sia un criterio valido x determinare powerON impianto
        /// </summary>
        public bool pingAsPowerOn { get; set; } = true;

        /// <summary>
        /// Indica se venga richiesta invio del run mode
        /// </summary>
        public bool runModeSend { get; set; } = false;

        /// <summary>
        /// Indica se venga richiesta traduzione del run mode
        /// </summary>
        public bool runModeTrad { get; set; } = false;

        /// <summary>
        /// Lista ulteriori configurazioni KeyValuePair
        /// </summary>
        public Dictionary<string, string> optKVP { get; set; } = new Dictionary<string, string>();

        #endregion Public Properties
    }

    /// <summary>
    /// Oggetto x processing valori (elenco valori e modalità)
    /// </summary>
    public class calcConf
    {
        #region Public Properties

        public calcMode calcMode { get; set; } = calcMode.None;
        public List<string> listVal { get; set; } = new List<string>();

        #endregion Public Properties
    }

    /// <summary>
    /// Classe per rappresentare oggetti chiave/valore target x controlo condizioni multiple
    /// </summary>
    public class diCheckCondition
    {
        #region Public Properties

        /// <summary>
        /// Nome variabile
        /// </summary>
        public string keyName { get; set; } = "";

        /// <summary>
        /// Se >=0 indica ordine bit x decodifica di byte[] raw
        /// </summary>
        public int bitNum { get; set; } = -1;

        /// <summary>
        /// valore target per esito richiesto
        /// </summary>
        public string targetValue { get; set; } = "";

        #endregion Public Properties
    }

    /// <summary>
    /// Classe per rappresentare una lista di oggetti chiave/valore target x controlo condizioni
    /// multiple + indicazione modalità di controllo (AND/OR/...)
    /// </summary>
    public class diCheckCondSetup
    {
        #region Public Properties

        /// <summary>
        /// Elenco condizioni
        /// </summary>
        public List<diCheckCondition> checkList { get; set; } = new List<diCheckCondition>();

        /// <summary>
        /// Modalità verifica condizioni
        /// </summary>
        public boolCheckMode checkMode { get; set; } = boolCheckMode.AND;

        /// <summary>
        /// indica se il check vada NEGATO (esempio se cerco la condizione opposta, esempio num
        /// allarmi 0 --&gt; se true NEGO la condizione HO ALLARMI)
        /// </summary>
        public bool negateValue { get; set; } = false;

        #endregion Public Properties
    }

    /// <summary>
    /// Classe x definizione delle azioni in fase di setup macchina
    /// </summary>
    public class MachineSetupAction
    {
        #region Public Properties

        /// <summary>
        /// Indica se vada disabilitato il contapezzi quando la condizione NotEqual sia soddisfatta
        /// </summary>
        public bool DisablePzCountNotEqual { get; set; } = false;

        /// <summary>
        /// Parametro target dell'azione
        /// </summary>
        public string TargetParam { get; set; } = "";

        /// <summary>
        /// Parametro da impostare SE il check da esito EQUAL
        /// </summary>
        public int TargetValEqual { get; set; } = 0;

        /// <summary>
        /// Parametro da impostare SE il check da esito NOT EQUAL
        /// </summary>
        public int TargetValNotEqual { get; set; } = 1;

        #endregion Public Properties
    }

    /// <summary>
    /// Definizione parametri di setup incrociato...
    /// </summary>
    public class MachineSetupConf
    {
        #region Public Properties

        /// <summary>
        /// Dizionario dei parametri di corrispondenza tra variabili MES e variabili Macchina MES =
        /// scritte dal MES Macchina = scritte da macchina
        /// </summary>
        public Dictionary<string, string> checkParList { get; set; } = new Dictionary<string, string>();

        /// <summary>
        /// Abilitazione gestione Setup Avanzato (= scrittura)
        /// </summary>
        public bool EnableAdvSetup { get; set; } = false;

        /// <summary>
        /// Modalità gestione setup
        /// </summary>
        public MachineSetupMode SetupMode { get; set; } = MachineSetupMode.ND;

        /// <summary>
        /// Dizionario dei parametri da scrivere quando si rilevano differenze tra i parametri MES/Macchina
        /// </summary>
        public List<MachineSetupAction> writeParAction { get; set; } = new List<MachineSetupAction>();

        #endregion Public Properties
    }

    /// <summary>
    /// COnfigurazione blocchi x accesso memoria ottimizzato
    /// </summary>
    public class MemBlockConf
    {
        #region Public Properties

        public Dictionary<int, int> ReadBlocks { get; set; } = new Dictionary<int, int>();

        #endregion Public Properties
    }

    /// <summary>
    /// Classe gestione configurazione parametri specifici MTC da BaseParamConf
    /// </summary>
    public class MtcParamConf : BaseParamConf
    {
        #region Public Properties

        /// <summary>
        /// Struttura dati x check condizione PowerOn
        /// </summary>
        public diCheckCondition condPowerOn { get; set; } = new diCheckCondition();

        /// <summary>
        /// Intervallo standard x SAMPLE data in ms
        /// </summary>
        public int clientSampleIntMs { get; set; } = 500;

        /// <summary>
        /// Timeout standard x richieste in ms
        /// </summary>
        public int reqTOutMs { get; set; } = 1500;

        /// <summary>
        /// Intervallo riconnessione standard in caso di mancanza risposta in ms
        /// </summary>
        public int reconnectIntMs { get; set; } = 1500;

        /// <summary>
        /// Indica se usare il metodo di sottoscrizione alle variazioni in modalità observations
        /// </summary>
        public bool doSubsObserv { get; set; } = false;

        /// <summary>
        /// Indica se usare il metodo di sottoscrizione alle variazioni sample
        /// </summary>
        public bool doSubsSample { get; set; } = true;

        #endregion Public Properties
    }

    /// <summary>
    /// Parametri speciali configurazione ModBusTCP
    /// </summary>
    public class ModBusTcpParamConf
    {
        #region Public Fields

        /// <summary>
        /// Indirizzo di base degli Holding Register
        /// </summary>
        public int holdRegBaseAddr { get; set; } = 40001;

        /// <summary>
        /// Indirizzo IP del PLC
        /// </summary>
        public string ipAdrr { get; set; } = "127.0.0.1";

        /// <summary>
        /// Base area x lettura
        /// </summary>
        public string memAddrRead { get; set; } = "40001";

        /// <summary>
        /// Base area x scrittura
        /// </summary>
        public string memAddrWrite { get; set; } = "41001";

        /// <summary>
        /// Size memoria lettura
        /// </summary>
        public int memSizeRead { get; set; } = 0;

        /// <summary>
        /// Size memoria scrittura
        /// </summary>
        public int memSizeWrite { get; set; } = 0;

        /// <summary>
        /// Timeout ping
        /// </summary>
        public int pingMsTimeout { get; set; } = 500;

        /// <summary>
        /// Porta di comunicazione
        /// </summary>
        public int port { get; set; } = 502;

        /// <summary>
        /// Indica se usare baseAddress calcolati o da config
        /// </summary>
        public bool useCalcBaseAddr { get; set; } = true;

        /// <summary>
        /// Delta valore lettura base MBus
        /// </summary>
        public int deltaBase { get; set; } = 0;

        /// <summary>
        /// Indice della LUT corrente
        /// </summary>
        public int indexLutCorr { get; set; } = 0;

        /// <summary>
        /// Gestione opzionale memoria estesa: non 0...10'000 ma 0...xFFFF=65536
        /// </summary>
        public bool modbusExtReg { get; set; } = false;

        #endregion Public Fields
    }

    /// <summary>
    /// Classe gestione configurazione parametri specifici OPC-UA da BaseParamConf
    /// </summary>
    public class OpcUaParamConf : BaseParamConf
    {
        #region Public Properties

        /// <summary>
        /// Elenco Variabili (e valori da impostare) x indicare di resettare contatore lotto e
        /// quindi riavviare produzione (es: impostando valore a 1...)
        /// </summary>
        public Dictionary<string, string> actResetCounter { get; set; } = new Dictionary<string, string>();

        /// <summary>
        /// Elenco Variabili (e valori da impostare) x indicare di effettuare impostazione nuovo
        /// programma/ricetta (es: impostando valore a 1...)
        /// </summary>
        public Dictionary<string, string> actSetRecipe { get; set; } = new Dictionary<string, string>();

        /// <summary>
        /// Elenco Variabili (e valori da impostare) x indicare di fermare la produzione (es:
        /// impostando valore a 1...)
        /// </summary>
        public Dictionary<string, string> actStopProd { get; set; } = new Dictionary<string, string>();

        /// <summary>
        /// Identificativo nodo iniziale
        /// </summary>
        public string BrowseFullVal { get; set; } = "ns=2;s=Scalar_Static";

        /// <summary>
        /// Elenco di nodi da sottoscrivere direttamente al posto dell'albero derivante dal BrowseFullVal
        /// </summary>
        public List<string> BrowseNodeList { get; set; } = new List<string>();

        /// <summary>
        /// Indice NS da cui fare il browse dei file
        /// </summary>
        public ushort BrowseNSIndex { get; set; } = 4;

        /// <summary>
        /// ID del nodo da cui partire x il browse di identificazione nodi iniziale
        /// </summary>
        public uint BrowseValue { get; set; } = 5001;

        /// <summary>
        /// Lista valori calcolati/derivati da processare
        /// </summary>
        public Dictionary<string, calcConf> calcValues { get; set; } = new Dictionary<string, calcConf>();

        /// <summary>
        /// Numero minimo di secondi di durata di uno status
        /// </summary>
        public int minSecStatusDuration { get; set; } = 1;

        /// <summary>
        /// Numero minimo di secondi di attesa finale (es prima di chiedere chiusura ODL)
        /// </summary>
        public int minSecFinalWait { get; set; } = 30;

        /// <summary>
        /// Struttura dati x check condizione Contapezzi Abilitato (se vuoto = sempre abilitato)
        /// </summary>
        public diCheckCondSetup condCountEnabled { get; set; } = new diCheckCondSetup();

        /// <summary>
        /// Struttura dati x check condizione Errore
        /// </summary>
        public diCheckCondSetup condError { get; set; } = new diCheckCondSetup();

        /// <summary>
        /// Struttura dati x check condizione Emergenza
        /// </summary>
        public diCheckCondSetup condEStop { get; set; } = new diCheckCondSetup();


        /// <summary>
        /// Struttura dati x check condizione PowerOn
        /// </summary>
        public diCheckCondSetup condPowerOn { get; set; } = new diCheckCondSetup();

        /// <summary>
        /// Struttura dati x check condizione READY
        /// </summary>
        public diCheckCondSetup condReady { get; set; } = new diCheckCondSetup();

        /// <summary>
        /// Struttura dati x check condizione Setup
        /// </summary>
        public diCheckCondSetup condSetup { get; set; } = new diCheckCondSetup();

        /// <summary>
        /// Struttura dati x check condizione Tavola 1 attiva
        /// </summary>
        public diCheckCondSetup condActTav1 { get; set; } = new diCheckCondSetup();

        /// <summary>
        /// Struttura dati x check condizione Tavola 2 attiva
        /// </summary>
        public diCheckCondSetup condActTav2 { get; set; } = new diCheckCondSetup();

        /// <summary>
        /// Struttura dati x check condizione WarmUp - CoolDown
        /// </summary>
        public diCheckCondSetup condWarmUpCoolDown { get; set; } = new diCheckCondSetup();

        /// <summary>
        /// Struttura dati x check condizione Warning
        /// </summary>
        public diCheckCondSetup condWarning { get; set; } = new diCheckCondSetup();

        /// <summary>
        /// Struttura dati x check condizione Errore
        /// </summary>
        public diCheckCondSetup condWorkOpc { get; set; } = new diCheckCondSetup();

        /// <summary>
        /// Elenco dei NodeId da ignorare intesi come interi rami (se vuoto NON filtro)
        /// </summary>
        public List<string> filterItemsNodeId { get; set; } = new List<string>();

        /// <summary>
        /// Elenco item flux da FILTRARE per chiave tradotta/VALORE
        /// es: Cimolai / Baglietto, RunModeVal NON VOGLIO inviare quando il valore è 0
        /// </summary>
        public Dictionary<string, List<string>> fluxLogKeyValVeto { get; set; } = new Dictionary<string, List<string>>();

        public UserIdent Identity { get; set; } = new UserIdent();

        /// <summary>
        /// Aree di memoria lettura
        /// </summary>
        public new Dictionary<string, dataConfTSVC> mMapRead { get; set; } = new Dictionary<string, dataConfTSVC>();

        /// <summary>
        /// Aree di memoria scrittura
        /// </summary>
        public new Dictionary<string, dataConf> mMapWrite { get; set; } = new Dictionary<string, dataConf>();

        /// <summary>
        /// Elenco item RAW sottoscritti e relative configurazioni di decodifica da byte[]
        /// </summary>
        public Dictionary<string, string> rawSubscribedItemsConf { get; set; } = new Dictionary<string, string>();

        /// <summary>
        /// Conf gestione setup macchina
        /// </summary>
        public MachineSetupConf SetupConf { get; set; } = new MachineSetupConf();

        /// <summary>
        /// Elenco dei SOLI item sottoscritti (se vuoto TUTTI)
        /// </summary>
        public List<string> subscribedItems { get; set; } = new List<string>();

        /// <summary>
        /// Conf Gestione WatchDog
        /// </summary>
        public WatchDogConf WatchDog { get; set; } = new WatchDogConf();

        /// <summary>
        /// Indica che si utilizza (per LUT e gestione conf) il NodeId completo, default false (solo il  DisplayName)
        /// </summary>
        public bool UseFullId { get; set; } = false;

        /// <summary>
        /// Numero massimo di letture null prima di disconnettere il client
        /// </summary>
        public int maxNullRead { get; set; } = 1000;

        /// <summary>
        /// Base del namespace da mascherare in invio OPC
        /// </summary>
        public string BaseIdMask { get; set; } = "";

        /// <summary>
        /// Abilita la gestione dei popup x inviare 
        /// </summary>
        public bool EnablePopup { get; set; } = false;

        public Dictionary<string, string> DictOpcNameReplace { get; set; } = new Dictionary<string, string>();

        #endregion Public Properties
    }

    /// <summary>
    /// Classe gestione configurazione parametri specifici Rest Client da BaseParamConf
    /// </summary>
    public class RestParamConf : BaseParamConf
    {
        /// <summary>
        /// Timeout chiamate REST
        /// </summary>
        public int timeOutSec { get; set; } = 60;

        /// <summary>
        /// API di base x chiamate REST, eventuali variabili van indicate come [[nomevar]]
        /// </summary>
        public string apiUrl { get; set; } = "";

        /// <summary>
        /// Periodo minimo di campionamento in ms x lettura dati frequenti stato/semafori...
        /// </summary>
        public int samplePeriod { get; set; } = 1000;

        /// <summary>
        /// Numero di errori dopo cui fare una vera disconnesisone con report poweroff della macchina
        /// </summary>
        public int connErrorMax { get; set; } = 5;

        /// <summary>
        /// Elenco delle chiamate x ID / struttura
        /// </summary>
        public Dictionary<string, CallStruc> CallList { get; set; } = new Dictionary<string, CallStruc>();

        public class CallStruc
        {
            /// <summary>
            /// ID univoco chiamata per poterla recuperare
            /// </summary>
            public int Idx { get; set; } = 0;

            /// <summary>
            /// Metodo chiamata
            /// </summary>
            public RestSharp.Method Method { get; set; } = RestSharp.Method.Get;

            /// <summary>
            /// Url chiamata
            /// </summary>
            public string Url { get; set; } = "";

            /// <summary>
            /// Nome x invio a MES
            /// </summary>
            public string Name { get; set; } = "";

            /// <summary>
            /// Nome x salvataggio valore output in ProdData da poter richiamare
            /// </summary>
            public string OutVarName { get; set; } = "";

            /// <summary>
            /// Intervallo di campionamento (minimo) da rispettare x evitare flood chiamate
            /// </summary>
            public int SamplePeriod { get; set; } = 5000;

            /// <summary>
            /// Elenco chiamate richieste se non fosse trovata/valida una variabile
            /// </summary>
            public List<string> ListPrevCall { get; set; } = new List<string>();
        }
    }

    public class UserIdent
    {
        #region Public Properties

        public string Passwd { get; set; } = "";
        public string UserName { get; set; } = "";

        #endregion Public Properties
    }

    /// <summary>
    /// Definizione parametri watchdog
    /// </summary>
    public class WatchDogConf
    {
        #region Public Properties

        /// <summary>
        /// Abilitazione WatchDog
        /// </summary>
        public bool IsEnabled { get; set; } = false;

        /// <summary>
        /// Valore max contatore prima di resettare
        /// </summary>
        public int MaxVal { get; set; } = 9999;

        /// <summary>
        /// Conf memoria x lettura WatchDog (ToMes), se !="" è gestito
        /// </summary>
        public string MemConfRead { get; set; } = "";

        /// <summary>
        /// Conf memoria x scrittura WatchDog (FromMes), se !="" è gestito
        /// </summary>
        public string MemConfWrite { get; set; } = "";

        #endregion Public Properties
    }
}