using IOB_UT_NEXT;
using IOB_UT_NEXT.Config;
using MapoSDK;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Data.Entity.Core.Mapping;
using System.IO;
using System.Net.NetworkInformation;
using System.Threading.Tasks;
using static IOB_WIN_WS.IobWs.Citizen.Responses;
using static System.Windows.Forms.VisualStyles.VisualStyleElement;

namespace IOB_WIN_WS.IobWs
{
    /// <summary>
    /// Adapter specializzato per Citizen (Colcom, MT70)
    /// </summary>
    public class Citizen : RestBase
    {
        #region Public Constructors

        /// <summary>
        /// Costruttore dell'IOB RestCitizen
        /// </summary>
        /// <param name="caller">Form chiamante</param>
        /// <param name="IobConfFull">Configurazione (v 4.x)</param>
        public Citizen(AdapterFormNext caller, IobConfTree IobConfFull) : base(caller, IobConfFull)
        {
            lgInfo($"Richiesto Adapter IobRest.RestCitizen con i parametri seguenti | ADDR: {IOBConfFull.Device.Connect.IpAddr} | PORT: {IOBConfFull.Device.Connect.Port}");
            lastPING = DateTime.Now.AddHours(-1);
            redKeyAlarm = redisMan.redHash($"IOB:Status:{IOBConfFull.General.CodIOB}:Alarm:LastRead");
            lastPING = DateTime.Now.AddHours(-1);
            // predispongo configurazione specifica Rest...
            lgInfo("Rest - 01");
            if (!string.IsNullOrEmpty(getOptPar("REST_CONF")))
            {
                setupRestConf(getOptPar("REST_CONF"));
            }
            // sistemo conf errori e samplePeriod...

            lgInfo("Rest - 02");
            if (EnableTest)
            {
                PrelimRestTest();
            }
        }

        #endregion Public Constructors

        #region Public Methods

        /// <summary>
        /// Implementazione custom esecuzione task specifici
        /// </summary>
        /// <param name="task2exe"></param>
        /// <returns></returns>
        public override Dictionary<string, string> executeTasks(Dictionary<string, string> task2exe, string codTav)
        {
            /*---------------------------------------
             * gestione execute task SPECIFICI:
             * - setArt
             * - setComm
             * - setPzComm
             *---------------------------------------*/

            // Verificare il protocollo: dovrebbe togliere SOLO i task eseguiti...
            Dictionary<string, string> taskDone = new Dictionary<string, string>();
            if (task2exe != null)
            {
                lgTrace($"executeTasks: richiesta esecuzione {task2exe.Count} task");
                // controllo se memMap != null...
                if (memMap != null)
                {
                    bool taskOk = false;
                    string taskVal = "";
                    // cerco task specifici: qui sono NON standard...
                    foreach (var item in task2exe)
                    {
                        lgInfo($"TASK | {item.Key} --> {item.Value}");
                        taskOk = false;
                        taskVal = "";
                        // converto richiesta in enum...
                        taskType tName = taskType.nihil;
                        Enum.TryParse(item.Key, out tName);
                        // controllo sulla KEY...
                        switch (tName)
                        {
                            case taskType.setArt:
                            case taskType.setComm:
                            case taskType.setPzComm:
                                lgInfo($"Task: {item.Key} | {item.Value}");
                                // salvo valori in memoria prod data
                                upsertKey(item.Key, item.Value);
                                taskVal = $"SET task: {item.Key} --> {item.Value}";
                                // invio una chiamata al sistema con i valori attuali
                                taskOk = SetJobDataCitizen();
                                break;

                            case taskType.setParameter:
                                // richiedo da URL i parametri WRITE da popolare
                                lgInfo("Chiamata setParameter --> 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";
                                    }
                                }
                                break;

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

        /// <summary>
        /// Recupera dizionario allarmi (SE PRESENTE)
        /// </summary>
        /// <returns></returns>
        public override Dictionary<string, string> getAlarmData()
        {
            Dictionary<string, string> outVal = new Dictionary<string, string>();
            // verifico SE HO allarmi attivi e nel caso li invia...
            string rawData = ExecuteCallGet(GetUrlResource("GetCurrAlarm"));
            string bankVal = "OK";
            WarnInfo alarmResp = JsonConvert.DeserializeObject<WarnInfo>(rawData);
            bankVal = (alarmResp != null && alarmResp.IsAlarm) ? alarmResp.message : "OK";
            saveAlarmString(ref outVal, bankVal, "Alarms");
            // verificare eventuale invio allarmi "storici"
            return outVal;
        }

        /// <summary>
        /// Recupero dati DYN, impiegando i valori della LUT...
        /// </summary>
        /// <returns></returns>
        public override Dictionary<string, string> getDynData()
        {
            var answ = RestDataLUT;
            // aggiungo DynData... calcolato come variazione pezzi e lampade...
            if (answ.ContainsKey("DYNDATA"))
            {
                answ.Remove("DYNDATA");
            }
            answ.Add("DYNDATA", $"LAMP_{RestLutGet("gLamp")}{RestLutGet("yLamp")}{RestLutGet("rLamp")}_PzReq_{RestLutGet("qtyReq")}_PzWrk_{RestLutGet("qtyWrk")}_PzTot_{RestLutGet("qtyTot")}");

            return answ;
        }

        /// <summary>
        /// Recupera il progName in modalità custom...
        /// </summary>
        /// <returns></returns>
        public override string getPrgName()
        {
            return RestLutGet("pName");
        }

        /// <summary>
        /// Esegue gestioen contapezzi...
        /// </summary>
        public override void processContapezzi()
        {
            DateTime adesso = DateTime.Now;
            // controllo se sia passato il samplePeriod minimo x 3...
            if (adesso.Subtract(lastRestProcPzCount.AddMilliseconds(samplePeriod * 4)).TotalSeconds > 0)
            {
                lastRestProcPzCount = adesso;
                bool checkMachine = false;
                LadderIO ladderResp = new LadderIO();
                // in primis testo che sia connessa...
                var checkResp = ExecuteCallGet(GetUrlResource("GetConnection"), true);
                lgInfo($"GetConnection | {checkResp} | Citizen.processContapezzi");
                bool.TryParse(checkResp, out checkMachine);

                // proseguo SOLO SE macchina OK, altrimenti disconnetto...
                if (checkMachine)
                {
                    // faccio refresh token comunque...
                    string token = ExecuteCallGet(GetUrlResource("GetToken"));
                    token = token.Replace("\"", "");
                    RestLutUpsert("token", token);
                    Task.Delay(samplePeriod / 20);

                    // contapezzi corrente
                    int intVal = 0;
                    string qtyWrk = ExecuteCallGet(GetUrlResource("GetQtyProd"));
                    int.TryParse(qtyWrk, out intVal);
                    contapezziPLC = intVal;
                    RestLutUpsert("qtyWrk", qtyWrk);

                    //attendo mezzo sample period...
                    Task.Delay(samplePeriod / 10);

                    // gestione tempociclo e nome programma...
                    string cTime = ExecuteCallGet(GetUrlResource("GetCycleTime"));
                    RestLutUpsert("cTime", cTime);

                    lgInfo($"Citizen | contapezziPLC {qtyWrk} | cTime {cTime}");
                }
            }
        }

        public override async Task processOtherCounters()
        {
            DateTime adesso = DateTime.Now;
            // controllo se sia passato il samplePeriod minimo x 3...
            if (adesso.Subtract(lastRestOtherCount.AddMilliseconds(samplePeriod * 30)).TotalSeconds > 0)
            {
                lastRestOtherCount = adesso;
                bool checkMachine = false;
                LadderIO ladderResp = new LadderIO();
                // in primis testo che sia connessa...
                var checkResp = ExecuteCallGet(GetUrlResource("GetConnection"), true);
                lgInfo($"GetConnection | {checkResp} | Citizen.processOtherCounters");
                bool.TryParse(checkResp, out checkMachine);

                // proseguo SOLO SE macchina OK, altrimenti disconnetto...
                if (checkMachine)
                {
                    // faccio refresh token comunque...
                    string token = ExecuteCallGet(GetUrlResource("GetToken"));
                    token = token.Replace("\"", "");
                    RestLutUpsert("token", token);
                    await Task.Delay(samplePeriod / 20);

                    // gestione altri contapezzi x
                    string qtyTot = ExecuteCallGet(GetUrlResource("GetQtyTot"));

                    //attendo mezzo sample period...
                    await Task.Delay(samplePeriod / 5);

                    string qtyReq = ExecuteCallGet(GetUrlResource("GetQtyReq"));
                    RestLutUpsert("qtyTot", qtyTot);
                    RestLutUpsert("qtyReq", qtyReq);

                    //attendo mezzo sample period...
                    await Task.Delay(samplePeriod / 5);

                    // gestione tempociclo e nome programma...
                    string pName = ExecuteCallGet(GetUrlResource("GetProgName"));
                    RestLutUpsert("pName", pName);

                    lgInfo($"Citizen | pName {pName} | qtyReq {qtyReq} | qtyTot {qtyTot}");
                }
            }
        }


        /// <summary>
        /// Override connessione
        /// </summary>
        public override void tryConnect()
        {
            if (!connectionOk)
            {
                // controllo che il ping sia stato tentato almeno pingTestSec fa...
                if (DateTime.Now.Subtract(lastPING).TotalSeconds > utils.CRI("pingTestSec"))
                {
                    if (verboseLog || periodicLog)
                    {
                        lgInfo("Rest: ConnKO - tryConnect");
                    }
                    // in primis salvo data ping...
                    lastPING = DateTime.Now;
                    bool checkMachine = false;
                    // se passa il ping faccio il resto...
                    if (testPingMachine == IPStatus.Success)
                    {
                        string szStatusConnection = "";
                        try
                        {
                            // ora provo connessione...
                            parentForm.commPlcActive = true;

                            // chiamo metodo connect
                            var checkResp = ExecuteCallGet(GetUrlResource("GetConnection"), true);
                            lgInfo($"GetConnection | {checkResp} | Citizen.tryConnect");
                            bool.TryParse(checkResp, out checkMachine);
                            if (checkMachine)
                            {
                                connectionOk = true;
                                queueInEnabCurr = true;
                                if (adpRunning)
                                {
                                    lgInfo("Connessione Citizen OK");
                                }
                            }
                            else
                            {
                                lgError($"Errore check connessione Citizen | checkResp: {checkResp}");
                            }
                        }
                        catch (Exception exc)
                        {
                            lgFatal($"Errore nella connessione all'Adapter IobRest.Base: {szStatusConnection}{Environment.NewLine}{exc}");
                            connectionOk = false;
                            lgInfo($"Eccezione in TryConnect, Adapter IobRest.Base NON running, pausa di {utils.CRI("waitRecMSec")} msec prima di ulteriori tentativi di riconnessione");
                        }
                    }
                    else
                    {
                        // loggo no risposta ping ...
                        connectionOk = false;
                        if (verboseLog || periodicLog)
                        {
                            lgInfo($"Attenzione: Rest controllo PING fallito per IP {IOBConfFull.Device.Connect.PingIpAddr}");
                        }
                    }
                }
            }
            else
            {
                needRefresh = true;
            }
        }

        #endregion Public Methods

        #region Internal Classes

        /// <summary>
        /// Struttura delle risposte alle chiamare REST specifiche
        /// </summary>
        internal class Responses
        {
            #region Internal Classes

            /// <summary>
            /// Struttura info restituiti da AlarmList
            /// </summary>
            internal class AlarmInfo
            {
                #region Public Properties

                public DateTime date { get; set; } = DateTime.Today.AddYears(-10);
                public string ErrorMessage { get; set; } = "";
                public int id { get; set; } = 0;
                public string message { get; set; } = "";
                public string type { get; set; } = "";

                #endregion Public Properties
            }

            /// <summary>
            /// Struttura info JobData da inviare x setup
            /// </summary>
            internal class CitizenJobData
            {
                #region Public Properties

                public string itemcode { get; set; } = "";
                public string itemdescription { get; set; } = "";
                public string ordercode { get; set; } = "";
                public int piecestodo { get; set; } = 0;
                public string token { get; set; } = "";

                #endregion Public Properties
            }

            /// <summary>
            /// Struttura info restituiti x lettura Ladder
            /// </summary>
            internal class LadderIO
            {
                #region Public Properties

                public string Address { get; set; } = "";
                public string Description { get; set; } = "";
                public string ErrorMessage { get; set; } = "";
                public string IOType { get; set; } = "";
                public string VarValue { get; set; } = "";

                #endregion Public Properties
            }

            /// <summary>
            /// Struttura info QtyData da inviare x impostazioni quantità
            /// </summary>
            internal class QtyData
            {
                #region Public Properties

                public string token { get; set; } = "";
                public int value { get; set; } = 0;

                #endregion Public Properties
            }

            /// <summary>
            /// Struttura dato AlarmState (singolo, corrente)
            /// </summary>
            internal class WarnInfo
            {
                #region Public Properties

                public string ErrorMessage { get; set; } = "";
                public bool IsAlarm { get; set; } = false;
                public bool IsCaution { get; set; } = false;
                public string message { get; set; } = "";

                #endregion Public Properties
            }

            /// <summary>
            /// Struttura risposta x scrittura parametri numerici (es qty)
            /// </summary>
            internal class WriteResult
            {
                #region Public Properties

                public string ErrorMessage { get; set; } = null;
                public bool Result { get; set; } = false;

                #endregion Public Properties
            }

            #endregion Internal Classes
        }

        #endregion Internal Classes

        #region Protected Methods

        /// <summary>
        /// Effettua decodifica aree memoria alla bitmap usata x MAPO
        /// </summary>
        protected override void decodeToBaseBitmap(ref newDisplayData currDispData)
        {
            // init a zero...
            B_input = 0;
            if (queueInEnabCurr)
            {
                /* -----------------------------------------------------
                * bitmap MAPO STD 60
                * B0: POWER_ON
                * B1: RUN
                * B2: pzCount
                * B3: allarme
                * B4: manuale
                * B5: allarme TCiclo (SLOW)
                * B6: WarmUp_CoolDown
                * B7: EmergArmed (1 = NON emergenza, 0 = emergenza)
                ----------------------------------------------------- */

                // per prima cosa controllo ping e se sia connesso...

                if (connectionOk)
                {
                    B_input = 1;
                    currDispData.semIn = Semaforo.SV;

                    // controllo lampade... da rosso a verde...
                    if (RestLutGet("rLamp") == "1")
                    {
                        B_input += (1 << 3);
                    }
                    else if (RestLutGet("yLamp") == "1")
                    {
                        B_input += (1 << 4);
                    }
                    else if (RestLutGet("gLamp") == "1")
                    {
                        B_input += (1 << 1);
                    }

                    // accodo NON emergenza ... poi da cercare meglio...
                    B_input += (1 << 7);
                }
                else
                {
                    B_input = 0;
                    currDispData.semIn = Semaforo.SR;
                    lgTrace($"Citizen.decodeToBaseBitmap | connectionOk: {connectionOk}");
                }
            }
            else
            {
                lgDebug($"[VETO queueInEnabCurr] | veto attivo alle {DateTime.Now:yyyy.MM.dd HH:mm:ss}");
            }
        }

        /// <summary>
        /// Metodo da overridare x scrivere DAVVERO i parametri sul PLC
        /// </summary>
        /// <param name="updatedPar"></param>
        protected override void plcWriteParams(ref List<objItem> updatedPar)
        {
            lgTrace($"plcWriteParams: richiesta per {updatedPar.Count} params");
            foreach (var item in updatedPar)
            {
                lgInfo($"ITEM | {item.uid} | {item.value}");
                // salvo i valori ricevuti
                upsertKey(item.uid, item.reqValue);
                // resetto richiesta!
                item.reqValue = "";
                // chiamo scrittura commessa!
                var taskOk = SetJobDataCitizen();
            }
        }

        /// <summary>
        /// Esegue lettura dati + salvataggio in LUT
        /// </summary>
        protected override void refreshData()
        {
            DateTime adesso = DateTime.Now;
            // controllo se sia passato il samplePeriod minimo...
            if (adesso.Subtract(lastRestRefreshData.AddMilliseconds(samplePeriod)).TotalSeconds > 0)
            {
                lastRestRefreshData = adesso;
                bool checkMachine = false;
                LadderIO ladderResp = new LadderIO();
                // in primis testo che sia connessa...
                var checkResp = ExecuteCallGet(GetUrlResource("GetConnection"), true);
                lgInfo($"GetConnection | {checkResp} | Citizen.refreshData");
                bool.TryParse(checkResp, out checkMachine);

                // proseguo SOLO SE macchina OK, altrimenti disconnetto...
                if (checkMachine)
                {
                    //riporto err conn a zero
                    connErrCur = 0;
                    // faccio refresh token comunque...
                    string token = ExecuteCallGet(GetUrlResource("GetToken"));
                    token = token.Replace("\"", "");
                    RestLutUpsert("token", token);

                    // ora controllo valori lampada SE scaduti resetto 3 valori lamp
                    RestLutUpsert("gLamp", "0");
                    RestLutUpsert("yLamp", "0");
                    RestLutUpsert("rLamp", "0");

                    int signVal = 0;
                    string gLamp = ExecuteCallGet(GetUrlResource("GetLampGreen"));
                    ladderResp = JsonConvert.DeserializeObject<LadderIO>(gLamp);
                    if (string.IsNullOrEmpty(ladderResp.ErrorMessage))
                    {
                        int.TryParse(ladderResp.VarValue, out signVal);
                        RestLutUpsert("gLamp", $"{signVal}");
                    }

                    // se il valore è zero --> proseguo con yellow!
                    if (signVal == 0)
                    {
                        Task.Delay(samplePeriod / 5);
                        string yLamp = ExecuteCallGet(GetUrlResource("GetLampYellow"));
                        ladderResp = JsonConvert.DeserializeObject<LadderIO>(yLamp);
                        if (string.IsNullOrEmpty(ladderResp.ErrorMessage))
                        {
                            int.TryParse(ladderResp.VarValue, out signVal);
                            RestLutUpsert("yLamp", $"{signVal}");
                        }
                    }

                    // se il valore è zero --> proseguo con red!
                    if (signVal == 0)
                    {
                        Task.Delay(samplePeriod / 5);
                        string rLamp = ExecuteCallGet(GetUrlResource("GetLampRed"));
                        ladderResp = JsonConvert.DeserializeObject<LadderIO>(rLamp);
                        if (string.IsNullOrEmpty(ladderResp.ErrorMessage))
                        {
                            int.TryParse(ladderResp.VarValue, out signVal);
                            RestLutUpsert("rLamp", $"{signVal}");
                        }
                    }
                }
                else
                {
                    // verifico se devo disconnettere
                    if (connErrCur >= connErrMax)
                    {
                        connErrCur = 0;
                        tryDisconnect();
                    }
                    else
                    {
                        connErrCur++;
                    }
                }
            }
        }

        #endregion Protected Methods

        #region Private Fields

        private string basePath = "";

        private DateTime lastRestProcPzCount = DateTime.Now;
        private DateTime lastRestOtherCount = DateTime.Now;

        private DateTime lastRestRefreshData = DateTime.Now;

        #endregion Private Fields

        #region Private Properties

        /// <summary>
        /// Elenco pesate attuali
        /// </summary>
        private List<AlarmInfo> listAllarmiCurr { get; set; } = new List<AlarmInfo>();

        /// <summary>
        /// CHiave redis di salvataggio ultimo set di allarmi scaricato
        /// </summary>
        private string redKeyAlarm { get; set; } = "";

        #endregion Private Properties

        #region Private Methods

        /// <summary>
        /// Test preliminare comunicazione Rest Citizen
        /// </summary>
        private void PrelimRestTest()
        {
            lgInfo("Rest - 03");
            // test folder salvataggio log
            var appPath = System.Reflection.Assembly.GetExecutingAssembly().Location;
            var fPath = Directory.GetParent(appPath).FullName;
            basePath = Path.Combine(fPath, "Test");
            if (!Directory.Exists(basePath))
            {
                Directory.CreateDirectory(basePath);
            }
            lgInfo("Rest - 04");

            bool checkMachine = false;
            string checkResp = TestRawCall("checkconnection", true);
            lgInfo($"checkconnection | {checkResp}");
            bool.TryParse(checkResp, out checkMachine);
            if (checkMachine)
            {
                string token = TestRawCall("gettoken/mecmaticames/mecmatica@mes");
                token = token.Replace("\"", "");
                if (string.IsNullOrEmpty(token))
                {
                    lgError("Errore: token vuoto");
                }
                else
                {
                    string gLamp = TestRawCall($"getsingleladderio/{token}/Y/8E");
                    string yLamp = TestRawCall($"getsingleladderio/{token}/Y/21");
                    string rLamp = TestRawCall($"getsingleladderio/{token}/Y/22");
                    string qtyTot = TestRawCall($"gettotalquantity/{token}");
                    string qtyReq = TestRawCall($"getneededquantity/{token}");
                    string qtyWrk = TestRawCall($"getworkedquantity/{token}");
                    string cTime = TestRawCall($"getcycletime/{token}");
                    string pName = TestRawCall($"getmainprogram/{token}");

                    string cAlarm = ExecuteCallGet($"getalarm/{token}");
                    var sAlarm = JsonConvert.DeserializeObject<WarnInfo>(cAlarm);
                    cAlarm = JsonConvert.SerializeObject(sAlarm, Formatting.Indented);
                    lgInfo($"Call: getalarm/{token} | resp: {cAlarm}");

                    string allAlarm = ExecuteCallGet($"getallalarmlog/{token}");
                    var alarmList = JsonConvert.DeserializeObject<List<AlarmInfo>>(allAlarm);
                    allAlarm = JsonConvert.SerializeObject(alarmList, Formatting.Indented);
                    lgInfo($"Call: getallalarmlog/{token} | resp: {allAlarm}");

                    string err = TestRawCall($"getsingleladderio/ABC/Y/22");

                    // salvo i valori
                    File.WriteAllText(Path.Combine(basePath, "token.txt"), token);
                    File.WriteAllText(Path.Combine(basePath, "gLamp.txt"), gLamp);
                    File.WriteAllText(Path.Combine(basePath, "yLamp.txt"), yLamp);
                    File.WriteAllText(Path.Combine(basePath, "rLamp.txt"), rLamp);
                    File.WriteAllText(Path.Combine(basePath, "qtyTot.txt"), qtyTot);
                    File.WriteAllText(Path.Combine(basePath, "qtyReq.txt"), qtyReq);
                    File.WriteAllText(Path.Combine(basePath, "qtyWrk.txt"), qtyWrk);
                    File.WriteAllText(Path.Combine(basePath, "cTime.txt"), cTime);
                    File.WriteAllText(Path.Combine(basePath, "pName.txt"), pName);
                    File.WriteAllText(Path.Combine(basePath, "cAlarm.txt"), cAlarm);
                    File.WriteAllText(Path.Combine(basePath, "allAlarm.txt"), allAlarm);
                    File.WriteAllText(Path.Combine(basePath, "err.txt"), err);
                }
            }
        }

        /// <summary>
        /// Effettua scrittura set di parametri del job e restitusice task eseguito...
        /// </summary>
        /// <returns></returns>
        private bool SetJobDataCitizen()
        {
            bool answ = false;
            string varValue = "";
            CitizenJobData jobReq = new CitizenJobData();
            QtyData qtyReq = new QtyData();

            // Token!
            varValue = RestLutGet("token");
            jobReq.token = varValue;
            qtyReq.token = varValue;

            // Commessa
            varValue = getCurrProdData("setComm", "");
            jobReq.ordercode = varValue;

            // Articolo
            varValue = getCurrProdData("setArt", "");
            jobReq.itemcode = varValue;
            jobReq.itemdescription = $"ART: {varValue}";

            // Qty
            varValue = getCurrProdData("setPzComm", "");
            int pzReq = 0;
            int.TryParse(varValue, out pzReq);
            jobReq.piecestodo = pzReq;
            qtyReq.value = pzReq;

            try
            {
                // preparo payload
                string jobPayload = JsonConvert.SerializeObject(jobReq);
                // faccio chiamata POST x invio
                var rawResp = ExecuteCallPost(GetUrlResource("SetJobData"), jobPayload);
                bool.TryParse(rawResp, out answ);
                // se andatae se ho la chaive x invio abilitata invio anche la qty richiesta...
                if (answ)
                {
                    string urlNeedQty = GetUrlResource("SetNeededQuantity");
                    if (string.IsNullOrEmpty(urlNeedQty))
                    {
                        lgInfo($"Set NeedQty NON abilitato, non invio");
                    }
                    else
                    {
                        jobPayload = JsonConvert.SerializeObject(qtyReq);
                        var rawRespQty = ExecuteCallPost(GetUrlResource("SetNeededQuantity"), jobPayload);
                    }
                }
            }
            catch (Exception exc)
            {
                lgError($"Eccezione in SetJobDataCitizen{Environment.NewLine}{exc}");
            }
            return answ;
        }

        /// <summary>
        /// Test Chiamata Citizen
        /// </summary>
        /// <param name="urlReq"></param>
        /// <returns></returns>
        private string TestRawCall(string urlReq, bool fastCall = false)
        {
            lgInfo($"TestRawCall: {urlReq}");
            string answ = ExecuteCallGet(urlReq, fastCall);
            lgInfo($"TestRawCall resp: {answ}");
            return answ;
        }

        #endregion Private Methods
    }
}