using IOB_UT;
using S7.Net;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net.NetworkInformation;

namespace IOB_WIN
{
  public class IobSiemensTorri : IobSiemens
  {
    /* -------------------------------------------------------------------------------- 
     * Controlli SIEMENS TORRI
     * - basasto su SIEMENS
     * - S7 vers 1200
     * 
     * -------------------------------------------------------------------------------- */

    #region area componenti base

    /// <summary>
    /// Configurazione valori da LEGGERE dal PLC
    /// </summary>
    public otherData[] memMapR;
    /// <summary>
    /// Configurazione valori da SCRIVERE nel PLC
    /// </summary>
    public otherData[] memMapW;
    /// <summary>
    /// Byte dimensione buffer dati memoria (da file map)
    /// </summary>
    public int numByte = 0;
    /// <summary>
    /// Lungh massima stringhe
    /// </summary>
    protected int maxStrChar = 20;
    /// <summary>
    /// Oggetto PLC da ri-utilizzare...
    /// </summary>
    protected Plc currPLC;
    /// <summary>
    /// Oggetto cronometro x test vari...
    /// </summary>
    protected Stopwatch sw = new Stopwatch();
    /// <summary>
    /// parametri di connessione
    /// </summary>
    protected connParamS7 parametri;
    /// <summary>
    /// Variabile x salvataggio iobConf locale
    /// </summary>
    protected IobConfiguration _IOBConf;

    #endregion

    #region area metodi lettura/Scrittura


    /// <summary>
    /// wrapper chiamata LETTURA in blocco MULTI BYTE...
    /// </summary>
    /// <param name="MATRICE valori letti"></param>
    /// <returns></returns>
    public bool S7ReadBB(ref byte[] Value)
    {
      bool answ = false;
      sw.Restart();
      parentForm.commPlcActive = true;
      if (testCncConn())
      {
        // decodifico memoria...
        memAreaSiemens memoria = new memAreaSiemens(parametri.memAddrRead);
        int numByte = parametri.memSizeRead;
        Byte[] memByteRead = currPLC.ReadBytes(DataType.DataBlock, memoria.DbNum, memoria.indiceMem, numByte);
        // copio in value, sennò do errore...
        if (memByteRead.Length == Value.Length)
        {
          Value = memByteRead;
        }
        else
        {
          lgError(string.Format("Mismatch dimensione array memoria: passato array di {0} byte, letti da S7 {1} byte", Value.Length, memByteRead.Length));
        }
        string titolo = string.Format("READ BLOCK MEM BYTE: {0} --> {1} byte", parametri.memAddrRead, numByte);
        if (verboseLog)
        {
          lgInfo(titolo);
        }

        string contenuto = string.Format("Contenuto area memoria aquisita{0}", Environment.NewLine);
        string byteVal = "";
        for (int i = 0; i < memByteRead.Length; i++)
        {
          byteVal = Convert.ToString(memByteRead[i], 2).PadLeft(8, '0');
          contenuto += string.Format("B{0:000}: {1} | {2}{3}", i, byteVal, memByteRead[i], Environment.NewLine);
        }
        // loggo lettura...
        if (verboseLog)
        {
          lgInfo(contenuto);
        }
      }
      else
      {
        connectionOk = false;
      }
      parentForm.commPlcActive = false;
      sw.Stop();
      if (utils.CRB("recTime"))
      {
        TimingData.addResult(cIobConf.codIOB, string.Format("{0}|{1}", parametri.memAddrRead, numByte), sw.ElapsedTicks);
      }

      return answ;
    }
    /// <summary>
    /// wrapper chiamata SCRITTURA in blocco MULTI BYTE...
    /// </summary>
    /// <param name="MATRICE valori scritti"></param>
    /// <returns></returns>
    public bool S7WriteBB(ref byte[] Value)
    {
      bool answ = false;

#if false
      sw.Restart();
      if (testCncConn())
      {
        // decodifico memoria...
        memAddress memoria = new memAddress(txtMemArea.Text);
        int numByte = 1;
        int.TryParse(txtMemSize.Text, out numByte);
        Byte[] memByteRead = currPLC.ReadBytes(DataType.DataBlock, memoria.DbNum, memoria.indiceMem, numByte);
        titolo = string.Format("READ BLOCK MEM BYTE: {0} --> {1} byte", txtMemArea.Text, numByte);
        contenuto = "";
        string byteVal = "";
        for (int i = 0; i < memByteRead.Length; i++)
        {
          byteVal = Convert.ToString(memByteRead[i], 2).PadLeft(8, '0');
          contenuto += string.Format("B{0:000}: {1} | {2}{3}", i, byteVal, memByteRead[i], Environment.NewLine);
        }
        showOut(titolo, contenuto);
      }
      sw.Stop();
      tslRTime.Text = string.Format("{0}", sw.Elapsed); 
#endif


#if false
      if (FANUC_ref.Connected)
      {
        try
        {
          parentForm.commPlcActive = true;
          answ = FANUC_ref.F_RW_Byte(bWrite, MemType, memIndex, ref Value);
        }
        catch
        { }
      }
      parentForm.commPlcActive = false; 
#endif
      return answ;
    }


    #endregion

    /// <summary>
    /// estende l'init della classe base con i metodi x Siemens specifici x Torri
    /// </summary>
    /// <param name="caller"></param>
    /// <param name="adpConf"></param>
    public IobSiemensTorri(AdapterForm caller, IobConfiguration IOBConf) : base(caller, IOBConf)
    {
      // gestione invio ritardato contapezzi
      
      lastPzCountSend = DateTime.Now;
      lastWarnODL = DateTime.Now;
      // init conf
      _IOBConf = IOBConf;
      // inizializzo parametri...
      parametri = new connParamS7()
      {
        ipAdrr = "127.0.0.1",
        tipoCpu = CpuType.S7200,
        slot = 0,
        rack = 0,
        pingMsTimeout = IOBConf.pingMsTimeout,
        memAddrRead = "DB700.DBB0",
        memAddrWrite = "DB701.DBB0",
        memSizeRead = 0,
        memSizeWrite = 0
      };
      setParamPlc();
    }
    /// <summary>
    /// Test connessione CNC
    /// </summary>
    /// <returns></returns>
    private bool testCncConn()
    {
      bool answ = false;
      IPStatus pingStatus = testPing();
      // se passa il ping faccio il resto...
      if (pingStatus != IPStatus.Success)
      {
        lgError(string.Format("Errore in testCncConn: reply Status per {0}: {1}", parametri.ipAdrr, pingStatus));
      }
      else
      {
        if (!currPLC.IsConnected)
        {
          currPLC.Open();
        }

        if (!currPLC.IsAvailable)
        {
          lgError(string.Format("PLC Siemens NON disponibile:{0} | {1}", currPLC.LastErrorCode, currPLC.LastErrorString));
          currPLC.ClearLastError();
        }
        else
        {
          if (!currPLC.IsConnected)
          {
            lgError(string.Format("PLC Siemens NON connesso:{0} | {1}", currPLC.LastErrorCode, currPLC.LastErrorString));
            currPLC.ClearLastError();
            parentForm.updateComStats("NO connection");
          }
          else
          {
            parentForm.updateComStats("Connection OK");
            answ = true;
          }
        }
      }
      return answ;
    }
    /// <summary>
    /// Imposto parametri PLC
    /// </summary>
    private void setParamPlc()
    {
      // Creo oggetto connessione NC
      parentForm.commPlcActive = true;
      lgInfo("Start init Adapter SIEMENS TORRI all'IP {0} | CPU: {1} | R/S: {2}/{3} | --> IOB {4}", _IOBConf.cncIpAddr, _IOBConf.cpuType, _IOBConf.rack, _IOBConf.slot, _IOBConf.codIOB);
      // SE è necessario refresh...
      if (needRefresh)
      {
        lgInfo("Refreshing connection...");
        try
        {
          parametri.slot = _IOBConf.slot;
          parametri.rack = _IOBConf.rack;
          parametri.tipoCpu = (CpuType)Enum.Parse(typeof(CpuType), _IOBConf.cpuType);
          parametri.ipAdrr = _IOBConf.cncIpAddr;
          // leggo file init...
          IniFile fIni = new IniFile(_IOBConf.iniFileName);
          // ora leggo valori speciali
          parametri.memAddrRead = fIni.ReadString("MEMORY", "ADDR_READ", "");
          parametri.memAddrWrite = fIni.ReadString("MEMORY", "ADDR_WRITE", "");
          parametri.memSizeRead = fIni.ReadInteger("MEMORY", "SIZE_READ", 0);
          parametri.memSizeWrite = fIni.ReadInteger("MEMORY", "SIZE_WRITE", 0);
          // salvo vettori memoria...
          RawInput = new byte[parametri.memSizeRead];
          RawOutput = new byte[parametri.memSizeWrite];
          // salvo parametri conn!
          lgInfo(string.Format("Parametri memoria: memAddrRead: {0} | memAddrWrite: {1} | memSizeRead: {2} | memSizeWrite: {3}", parametri.memAddrRead, parametri.memAddrWrite, parametri.memSizeRead, parametri.memSizeWrite));
        }
        catch (Exception exc)
        {
          lgError(exc, "Errore in parse parametri da IOBConf");
        }
        // ora tento avvio PLC... SE PING OK...
        if (testPing() == IPStatus.Success)
        {
          try
          {
            currPLC = new Plc(parametri.tipoCpu, parametri.ipAdrr, parametri.rack, parametri.slot);
            // disconnetto e connetto...
            if (utils.CRB("verbose"))
            {
              lgInfo("SIEMENS-TORRI: tryDisconnect");
            }

            tryDisconnect();
            lgInfo("SIEMENS-TORRI: tryConnect");
            tryConnect();
            lgInfo("End init Adapter SIEMENS-TORRI");
            if (utils.CRB("verbose"))
            {
              lgInfo("S7+ CONNESSIONE AVVENUTA");
            }
          }
          catch (Exception exc)
          {
            lgError(exc, "Errore in INIT PLC S7+");
          }
          needRefresh = false;
        }
        parentForm.commPlcActive = false;
        // carico conf vettore memoria...
        loadMemConf();
        if (utils.CRB("enableContapezzi"))
        {
          lgInfo("TORRI-SIEMENS: inizio gestione contapezzi");
          try
          {
            // verifico quale modalità sia richiesta: STD (6711) oppure BIT (Custom, con indicazione area)
            if (cIobConf.optPar.Count > 0 && cIobConf.optPar["PZCOUNT_MODE"] != "")
            {
              if (cIobConf.optPar["PZCOUNT_MODE"].StartsWith("STD"))
              {
                pzCntReload(true);
                // refresh associazione Macchina - IOB
                sendM2IOB();
                // per adesso imposto lettura fanuc == contapezzi (poi farà vera lettura...)
                lastCountCNC = contapezzi;
              }
              else
              {
                contapezzi = 0;
                lgInfo("Contapezzi STD disabilitato: modalità {0}", cIobConf.optPar["PZCOUNT_MODE"]);
              }
            }
            else
            {
              contapezzi = 0;
              lgInfo("Parametro mancante PZCOUNT_MODE");
            }
          }
          catch (Exception exc)
          {
            lgError(exc, "Errore in contapezzi TORRI-SIEMENS");
          }
        }
      }
    }
    /// <summary>
    /// Override disconnessione
    /// </summary>
    public override void tryDisconnect()
    {
      if (connectionOk)
      {
        string szStatusConnection = "";
        try
        {
          currPLC.Close();
          connectionOk = false;
          lgInfo(szStatusConnection);
          lgInfo("Effettuata disconnessione adapter SIEMENS-TORRI!");
        }
        catch (Exception exc)
        {
          lgFatal(exc, "Errore nella disconnessione dall'adapter SIEMENS-TORRI");
        }
      }
      else
      {
        lgError("IMPOSSIBILE effettuare disconnessione SIEMENS-TORRI: Connessione non disponibile...");
      }
    }
    /// <summary>
    /// Override connessione
    /// </summary>
    public override void tryConnect()
    {
      bool doLog = (verboseLog || periodicLog);
      if (!connectionOk)
      {
        // reimporto parametri PLC se necessario...
        setParamPlc();
        // controllo che il ping sia stato tentato almeno pingTestSec fa...
        if (DateTime.Now.Subtract(lastPING).TotalSeconds > utils.CRI("pingTestSec"))
        {
          if (doLog)
          {
            lgInfo("SIEMENS-TORRI: ConnKO - tryConnect");
          }
          // in primis salvo data ping...
          lastPING = DateTime.Now;
          // se passa il ping faccio il resto...
          if (testPing() == IPStatus.Success)
          {
            string szStatusConnection = "";
            try
            {
              // ora provo connessione...
              parentForm.commPlcActive = true;
              currPLC.Open();
              parentForm.commPlcActive = false;
              lgInfo("szStatusConnection: " + szStatusConnection);
              connectionOk = true;
              // refresh stato allarmi!!!
              if (connectionOk)
              {
                if (adpRunning)
                {
                  // carico status allarmi (completo)
                  lgInfo("Inizio refresh completo stato allarmi...");
                  forceAlarmCheck();
                  lgInfo("Completato refresh completo stato allarmi!");
                }
                else
                {
                  lgInfo("Connessione OK");
                }
              }
              else
              {
                lgError("Impossibile procedere, connessione mancante...");
              }
            }
            catch (Exception exc)
            {
              lgFatal(string.Format("Errore nella connessione all'adapter SIEMENS-TORRI: {0}{1}{2}", szStatusConnection, Environment.NewLine, exc));
              connectionOk = false;
              lgInfo(string.Format("Eccezione in TryConnect, Adapter SIEMENS-TORRI NON running, pausa di {0} msec prima di ulteriori tentativi di riconnessione", utils.CRI("waitRecMSec")));
            }
          }
          else
          {
            // loggo no risposta ping ...
            connectionOk = false;
            if (doLog)
            {
              lgInfo(string.Format("Attenzione: SIEMENS-TORRI controllo PING fallito per IP {0}", cIobConf.cncIpAddr));
            }
          }
        }
      }
      // se non è ancora connesso faccio procesisng memoria caso disconnesso...
      if (!connectionOk)
      {
        // processo semafori ed invio...
        processMemoryDiscon();
      }
    }
    /// <summary>
    /// Caricamento conf memoria DB del SIEMENS
    /// </summary>
    private void loadMemConf()
    {
      // carico conf memoria
      loadConfFile(ref memMapR, filePath("MMapR"), 1, ref numByte);
      loadConfFile(ref memMapW, filePath("MMapW"), 1, ref numByte);
    }
    /// <summary>
    /// Restituisce path completo file da chaive configurazione
    /// </summary>
    /// <param name="keyFile">chaive conf x file richiesto</param>
    /// <returns></returns>
    protected string filePath(string keyFile)
    {
      string answ = "";
      try
      {
        answ = string.Format(@"{0}\{1}", utils.confDir, utils.CRS(keyFile));
      }
      catch (Exception exc)
      {
        lgError(exc, "Eccezione in recupero filePath");
      }
      return answ;
    }

    /// <summary>
    /// Effettua vero processing contapezzi
    /// </summary>
    public override void processContapezzi()
    {
      if (utils.CRB("enableContapezzi"))
      {
        try
        {
          // verifico quale modalità sia richiesta: STD (6711) oppure BIT (Custom, con indicazione area)
          if (cIobConf.optPar.Count > 0 && cIobConf.optPar["PZCOUNT_MODE"] != "")
          {
            string memAddr = cIobConf.optPar["PZCOUNT_MODE"];
            if (memAddr.StartsWith("STD"))
            {
              // inizio verifica area memoria/parametro levando prima parte codice
              memAddr = memAddr.Replace("STD.", "");
              object outputVal = new object();
              // verifico se si tratta di lettura area DB... formato tipo STD.DB700.DBB22.W
              if (memAddr.StartsWith("DB"))
              {
                memAreaSiemens areaCounter = new memAreaSiemens(memAddr);

                if (utils.CRB("verbose"))
                {
                  lgInfo("[0] area memoria: {1}.{2}.{3}", memAddr, areaCounter.DbNum, areaCounter.indiceMem, areaCounter.tipoMem);
                }
                // copio da blocco già letto... con switch x tipo dati --> tipo lettura... e salvo ultimo conteggio rilevato
                switch (areaCounter.tipoMem)
                {
                  case "B":
                    byte valB = RawInput[areaCounter.indiceMem];
                    outputVal = valB;
                    break;
                  case "W":
                    ushort valW = S7.Net.Types.Word.FromByteArray(RawInput.Skip(areaCounter.indiceMem).Take(2).ToArray());
                    outputVal = valW;
                    break;
                  case "DW":
                    uint valDW = S7.Net.Types.Word.FromByteArray(RawInput.Skip(areaCounter.indiceMem).Take(4).ToArray());
                    outputVal = valDW;
                    if (utils.CRB("verbose"))
                    {
                      lgInfo("[2] outputVal contapezzi: {0}", outputVal);
                    }

                    break;
                  default:
                    break;
                }
                // salvo...
                Int32.TryParse(outputVal.ToString(), out lastCountCNC);
                if (utils.CRB("verbose"))
                {
                  lgInfo("[3] lastCountCNC contapezzi: {0}", lastCountCNC);
                }
              }
              stopwatch.Stop();
            }
          }
        }
        catch (Exception exc)
        {
          lgError(exc, "Errore in contapezzi SIEMENS-TORRI");
        }
      }
    }

    #region da completare

    /// <summary>
    /// Recupero dati override in formato dictionary
    /// </summary>
    /// <returns></returns>
    public override Dictionary<string, string> getOverrides()
    {
      Dictionary<string, string> outVal = new Dictionary<string, string>();
      uint valDW = 0;
      // !!!FARE!!! recuperare da conf memoria, ora HARD CODED
      outVal.Add("FEED_OVER", RawInput[19].ToString());
      outVal.Add("RAPID_OVER", RawInput[20].ToString());
      outVal.Add("CURR_MODE", decodeCurrMode(RawInput[21]));
      // recupero RPM pezzo/mola !!!FARE!!! cambio nome da config, qui sono 01:conduttrice e 02:operatrice (3013), mentre sono pezzo/mola nella V100
      valDW = S7.Net.Types.DWord.FromByteArray(RawInput.Skip(24).Take(4).ToArray());
      outVal.Add("RPM_01", valDW.ToString());
      valDW = S7.Net.Types.DWord.FromByteArray(RawInput.Skip(28).Take(4).ToArray());
      outVal.Add("RPM_02", valDW.ToString());
      return outVal;
    }

    /// <summary>
    /// lettura bit semafori
    /// </summary>
    public override void readSemafori()
    {
      base.readSemafori();
      if (verboseLog)
      {
        lgInfo("inizio read semafori");
      }

      parentForm.sIN = Semaforo.SV;
      // leggo TUTTI i byte configurati...
      byte[] MemBlock = new byte[parametri.memSizeRead];
      bool fatto = S7ReadBB(ref MemBlock);
      Buffer.BlockCopy(MemBlock, 0, RawInput, 0, parametri.memSizeRead);
      if (verboseLog)
      {
        lgInfo(string.Format("RawInput[0]: {0}", utils.binaryForm(RawInput[0])));
      }
      // salvo il solo BYTE dell'input decifrando il semaforo... 
      decodeToBaseBitmap();
      decodeOtherData();
    }

    /// <summary>
    /// decodifica da bitmap il CURRENT MODE del controllo
    /// </summary>
    /// <param name="currModeBitmap"></param>
    /// <returns></returns>
    protected string decodeCurrMode(byte currModeBitmap)
    {
      string answ = "";
      if (verboseLog)
      {
        lgInfo(string.Format("CURR_MODE raw data: {0}", utils.binaryForm(currModeBitmap)));
      }
      // decodifica del MODO... B21
      /*
       * CURR MODE diviso in BIT:
       * B0 (01) = AUTO
       * B1 (02) = MDI
       * B2 (04) = JOG
       * B3 (08) = TeachIN (associato a MDI --> 10)
       * B4 (16) = Repos (associato a JOG --> 20)   
       * B5 (32) = RefPoint (associato a Jog --> 36)
       * B6 (64) = Incr1 (associato a Jog --> 68)
       * B7 (128) = Incr10 (associato a Jog --> -124 / 132 se UInt)
       * */

      // modi principali
      if (currModeBitmap.SelectBit(0))
      {
        answ = "AUTO";
      }
      else if (currModeBitmap.SelectBit(1))
      {
        answ = "MDI";
      }
      else if (currModeBitmap.SelectBit(2))
      {
        answ = "JOG";
      }
      // modi accessori
      if (currModeBitmap.SelectBit(3))
      {
        answ += " | TEACH-IN";
      }
      if (currModeBitmap.SelectBit(4))
      {
        answ += " | REPOS";
      }
      if (currModeBitmap.SelectBit(5))
      {
        answ += " | REF-POINT";
      }
      if (currModeBitmap.SelectBit(6))
      {
        answ += " | INCR-1";
      }
      if (currModeBitmap.SelectBit(7))
      {
        answ += " | INCR-10";
      }
      return answ;
    }
    /// <summary>
    /// Decodifica il resto dell'area TORRI x i dati accessori (allarmi, ...)
    /// </summary>
    private void decodeOtherData()
    {
      if (verboseLog)
      {

      }
    }

    /// <summary>
    /// Effettua decodifica aree memoria alla bitmap usata x MAPO
    /// </summary>
    private void decodeToBaseBitmap()
    {
      // init a zero...
      B_input = 0;
      // TORRI: leggo i primi 8 bit hard coded...
      int byteSem = RawInput[0];
      // azzero i bit NON gestiti (2-5-6-7)    
      byteSem &= ~(1 << 2);
      byteSem &= ~(1 << 5);
      byteSem &= ~(1 << 6);
      byteSem &= ~(1 << 7);
      // salvo infine variabile bit x invio
      B_input = byteSem;


      string currODL = "";
      try
      {
        currODL = utils.callUrl(urlGetCurrODL);
        // solo SE HO un ODL...
        if (currODL == "" || currODL == "0")
        {
          if (periodicLog)
          {
            lgInfo(string.Format("SiemensTorri | Lettura ODL andata a vuoto: currODL: {0}", currODL));
          }
        }
        else
        {
          // se variato o scaduto timeout log...
          if (periodicLog || (currIdxODL.ToString() != currODL))
          {
            lgInfo(string.Format("SiemensTorri | Lettura ODL, currODL: {0} --> currIdxODL prec: {1}", currODL, currIdxODL));
          }
          // provo a salvare nuovo ODL
          int.TryParse(currODL, out currIdxODL);
        }
      }
      catch (Exception exc)
      {
        if (DateTime.Now.Subtract(lastWarnODL).TotalSeconds > 15)
        {
          lgError(exc, "Errore in fase di chiamata URL x ODL corrente | URL chiamato: {0}", urlGetCurrODL);
          lastWarnODL = DateTime.Now;
        }
      }
      if (currODL != null && currODL != "" && currODL != "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 (lastCountCNC != contapezzi)
          {
            // registro contapezzi
            lgInfo(string.Format("Differenza Contapezzi: READ: {0} | Interno {1}", lastCountCNC, contapezzi));
          }
          // verifico se variato contapezzi... e se passato ritardo minimo...
          if (lastCountCNC > contapezzi)
          {
            // salvo nuovo contapezzi (incremento di 1...)
            contapezzi++;
            // salvo in semaforo!
            B_input += 1 << 2;
            // registro contapezzi
            lgInfo(string.Format("Contapezzi SIEMENST-TORRI: {0} | Contapezzi interno {1}", lastCountCNC, contapezzi));
          }

          // invio a server contapezzi (aggiornato)
          string retVal = utils.callUrl(urlSetPzCount + contapezzi.ToString());
          // verifica se tutto OK 
          if (retVal != "OK")
          {
            // errore salvataggio contapezzi    
            lgInfo(string.Format("Errore salvataggio Contapezzi SIEMENST-TORRI: {0} | Contapezzi interno {1} | Errore salvataggio: {2}", lastCountCNC, contapezzi, retVal));
          }
          // resetto timer...
          lastPzCountSend = DateTime.Now;
        }
      }
      else
      {
        if (DateTime.Now >= lastPzCountSend.AddMilliseconds(pzCountDelay))
        {
          lgInfo(string.Format("Attenzione: mancanza ODL non procedo con gestione contapezzi. Contapezzi SIEMENST-TORRI: {0} | Contapezzi interno {1}", lastCountCNC, contapezzi));
          // resetto timer...
          lastPzCountSend = DateTime.Now;
        }
      }

      // log opzionale!
      if (verboseLog)
      {
        lgInfo(string.Format("Trasformazione B_input: {0}", B_input));
      }
    }
    /// <summary>
    /// Recupero programma in lavorazione
    /// </summary>
    /// <returns></returns>
    public override string getPrgName()
    {
      string prgName = "";
#if false
      // recupero NUOVO prgName...
      try
      {
        // recupero nome programma MAIN
        prgName = utils.purgedChar2String(FANUC_ref.getPrgNameMain());
        // trimmo path del programma, ovvero "CNCMEMUSERPATH1"
        prgName = prgName.Replace(utils.CRS("basePrgMemPath"), "");
      }
      catch (Exception exc)
      {
        lgError(string.Format("Eccezione in recupero PRG NAME MAIN:{0}{1}", Environment.NewLine, exc));
      } 
#endif
      return prgName;
    }

    /// <summary>
    /// Recupero programma in lavorazione come Dictionary FANUC...
    /// - SYSINFO: (prima KEY globale) TUTTI i valori separati da # (x fare check modifica)
    /// - altre stringhe: ogni singolo parametro / valore
    /// </summary>
    /// <returns></returns>
    public override Dictionary<string, string> getSysInfo()
    {
      Dictionary<string, string> outVal = new Dictionary<string, string>();
#if false
      inizio = DateTime.Now;
      EgwProxy.MultiCncLib.Focas1.ODBSYS answ = FANUC_ref.getSysInfo();
      if (utils.CRB("recTime")) TimingData.addResult(string.Format("SYS-INFO"), DateTime.Now.Subtract(inizio).Ticks);
      try
      {
        string cnc_type = new string(answ.cnc_type);
        string mt_type = new string(answ.mt_type);
        string series = new string(answ.series);
        string version = new string(answ.version);
        string axes = new string(answ.axes);
        //short addInfo = answ.addinfo;
        short max_axis = answ.max_axis;
        // preparo i singoli valori dell'array...
        outVal.Add("SYSINFO", string.Format("{0}#{1}#{2}#{3}#{4}#{5}", cnc_type, mt_type, series, version, axes, max_axis));
        outVal.Add("CNC", cnc_type);
        outVal.Add("MTT", mt_type);
        outVal.Add("SER", series);
        outVal.Add("VER", version);
        outVal.Add("AXS", string.Format("{0}|{1}", axes, max_axis));
      }
      catch (Exception exc)
      {
        lgError(exc, "Errore in getSysInfo");
      } 
#endif
      return outVal;
    }
    /// <summary>
    /// Esegue processing MODE (e nel contempo recupera altri dati dell'area G)
    /// </summary>
    public override void processMode()
    {
      if (utils.CRB("enableMode"))
      {
#if false
        try
        {
          inizio = DateTime.Now;
          // leggo tutto da 0 a 43...
          int memIndex = 0;
          FanucMemRW(R, FANUC.MemType.G, memIndex, ref MemBlockG);
          if (utils.CRB("recTime")) TimingData.addResult(string.Format("R{0}-G-AREA", MemBlockG.Length), DateTime.Now.Subtract(inizio).Ticks);
          // verifico modo con valore corrente, se cambia aggiorno...
          CNC_MODE newMode = decodeG43(MemBlockG[43]);
          if (newMode != currMode)
          {
            // aggiorno!
            currMode = newMode;
            // conversione NUM MODE in descrizione da ENUM
            string descrMode = Enum.GetName(typeof(CNC_MODE), currMode);
            // accodo x invio
            string sVal = string.Format("[CNC_MODE]{0}", descrMode);
            // chiamo accodamento...
            accodaFLog(sVal, qEncodeFLog("CNC_MODE", descrMode));
          }
        }
        catch (Exception exc)
        {
          lgError(exc, "Errore in process Mode G43");
        } 
#endif
      }
    }
#if false
    /// <summary>
    /// decodifica il modo dai valori del byte G43
    /// </summary>
    /// <param name="currVal"></param>
    /// <returns></returns>
    protected CNC_MODE decodeG43(byte currVal)
    {
      // hard coded da valori tabellari a MODI definiti in CNC_MODE...
      CNC_MODE answ = CNC_MODE.ND;
      switch (currVal)
      {
        case 0:
          answ = CNC_MODE.MDI;
          break;
        case 1:
          answ = CNC_MODE.MEN;
          break;
        case 3:
          answ = CNC_MODE.EDIT;
          break;
        case 4:
          answ = CNC_MODE.HANDLE_INC;
          break;
        case 5:
          answ = CNC_MODE.JOG;
          break;
        case 6:
          answ = CNC_MODE.TJOG;
          break;
        case 7:
          answ = CNC_MODE.THND;
          break;
        case 33:
          answ = CNC_MODE.RMT;
          break;
        case 133:
          answ = CNC_MODE.REF;
          break;
        default:
          answ = CNC_MODE.ND;
          break;
      }
      return answ;
    } 
#endif
    /// <summary>
    /// Recupero dati dinamici...
    /// </summary>
    public override Dictionary<string, string> getDynData()
    {
      Dictionary<string, string> outVal = new Dictionary<string, string>();
#if false
      inizio = DateTime.Now;
      EgwProxy.MultiCncLib.Focas1.ODBDY2_1 answ = FANUC_ref.getAllDynData();
      if (utils.CRB("recTime")) TimingData.addResult(string.Format("PROC-DYN-DATA"), DateTime.Now.Subtract(inizio).Ticks);
      try
      {
        string actf = answ.actf.ToString();
        string acts = answ.acts.ToString();
        //string numAlarm = answ.alarm.ToString();
        // preparo i singoli valori dell'array...
        //outVal.Add("DYNDATA", string.Format("{0}#{1}#{2}", actf, acts, numAlarm));
        outVal.Add("DYNDATA", string.Format("FEED {0}#SPEED_RPM {1}", actf, acts));
        if (utils.CRB("SendFeedSpeed"))
        {
          outVal.Add("FEED", actf);
          outVal.Add("SPEED_RPM", acts);
          //outVal.Add("NUM_ALARM", numAlarm);
        }
        if (utils.CRB("SendAxPos"))
        {
          // salvo le posizioni...
          EgwProxy.MultiCncLib.Focas1.FAXIS posAx = answ.pos;
          int[] currPosAbs = posAx.absolute;
          int i = 0;
          foreach (var item in currPosAbs)
          {
            i++;
            outVal.Add(string.Format("POS_{0:00}", i), item.ToString());
          }
        }
      }
      catch (Exception exc)
      {
        lgError(exc, "Errore in getDynData");
      } 
#endif
      return outVal;
    }

    /// <summary>
    /// Override salvataggio valori in memoria...
    /// </summary>
    /// <param name="tipo">tipo di DUMP</param>
    public override void saveMemDump(dumpType tipo)
    {
#if false
      dump_MemAreaD();
      dump_MemAreaY(); 
#endif
    }
    /// <summary>
    /// Dump PERIODICO area D della memoria
    /// </summary>
    /// <param name="memIndex">area memoria di partenza</param>
    /// <param name="memSyzeByte"></param>
    private void dump_MemAreaD(int memIndex, int memSyzeByte)
    {
      // leggo TUTTI i 9999 byte della memoria D...
      byte[] MemBlockD = new byte[memSyzeByte];
      stopwatch.Restart();
      if (verboseLog)
      {
        lgInfo("START MemDump AreaD");
      }
#if false
      FanucMemRW(R, FANUC.MemType.D, memIndex, ref MemBlockD);
      if (verboseLog) lgInfo("END MemDump AreaD");
      if (utils.CRB("recTime")) TimingData.addResult(string.Format("R{0}-MemDumpD", MemBlockD.Length), DateTime.Now.Subtract(inizio).Ticks);
      // file out!
      string nomeFile = "";
      Dictionary<string, string> mappaValori = new Dictionary<string, string>();
      // salvo in file i dati letti come DWord (4byte)
      nomeFile = string.Format(@"{0}\SAMPLES\MemDump_D_DW_{1:yyyyMMdd_HHmmss}.dat", utils.dataDatDir, DateTime.Now);
      for (int i = 0; i < MemBlockD.Length / 4; i++)
      {
        mappaValori.Add(i.ToString("0000"), BitConverter.ToUInt32(MemBlockD, i * 4).ToString());
      } 
      utils.WritePlain(mappaValori, nomeFile);
#endif
    }
    /// <summary>
    /// Dump area D della memoria
    /// </summary>
    private void dump_MemAreaD()
    {
      // faccio chaimate e salvo in file dump...
      int memIndex = 0;
      // leggo TUTTI i 9999 byte della memoria D...
      byte[] MemBlockD = new byte[9999];
      stopwatch.Restart();
      if (verboseLog)
      {
        lgInfo("START MemDump AreaD");
      }
#if false
      FanucMemRW(R, FANUC.MemType.D, memIndex, ref MemBlockD);
      if (verboseLog) lgInfo("END MemDump AreaD");
      if (utils.CRB("recTime")) TimingData.addResult(string.Format("R{0}-MemDumpD", MemBlockD.Length), DateTime.Now.Subtract(inizio).Ticks);
      //
      string nomeFile = "";
      // salvo in file i dati letti come BYTE
      nomeFile = string.Format(@"{0}\MemDump_D_Byte.dat", utils.dataDatDir);
      Dictionary<string, string> mappaValori = new Dictionary<string, string>();
      for (int i = 0; i < MemBlockD.Length; i++)
      {
        mappaValori.Add(i.ToString("0000"), MemBlockD[i].ToString());
      }
      utils.WritePlain(mappaValori, nomeFile);

      // salvo in file i dati letti come DWord (4byte)
      nomeFile = string.Format(@"{0}\MemDump_D_DW.dat", utils.dataDatDir);
      mappaValori = new Dictionary<string, string>();
      for (int i = 0; i < MemBlockD.Length / 4; i++)
      {
        mappaValori.Add(i.ToString("0000"), BitConverter.ToUInt32(MemBlockD, i * 4).ToString());
      }
      utils.WritePlain(mappaValori, nomeFile);

      // salvo in file i dati letti come DWord (4byte)
      nomeFile = string.Format(@"{0}\MemDump_D_W.dat", utils.dataDatDir);
      mappaValori = new Dictionary<string, string>();
      for (int i = 0; i < MemBlockD.Length / 2; i++)
      {
        mappaValori.Add(i.ToString("0000"), BitConverter.ToUInt16(MemBlockD, i * 2).ToString());
      } 
      utils.WritePlain(mappaValori, nomeFile);
#endif
    }
    /// <summary>
    /// Dump area Y della memoria
    /// </summary>
    private void dump_MemAreaY()
    {
      // faccio chaimate e salvo in file dump...
      int memIndex = 0;
      // leggo TUTTI i 9999 byte della memoria Y...
      byte[] MemBlockY = new byte[10];
      stopwatch.Restart();
      if (verboseLog)
      {
        lgInfo("START MemDump AreaY");
      }
#if false
      FanucMemRW(R, FANUC.MemType.Y, memIndex, ref MemBlockY);
      if (verboseLog) lgInfo("END MemDump AreaY");
      if (utils.CRB("recTime")) TimingData.addResult(string.Format("R{0}-MemDumpY", MemBlockY.Length), DateTime.Now.Subtract(inizio).Ticks);
      //
      string nomeFile = "";
      // salvo in file i dati letti come BYTE
      nomeFile = string.Format(@"{0}\MemDump_Y_Byte.dat", utils.dataDatDir);
      Dictionary<string, string> mappaValori = new Dictionary<string, string>();
      for (int i = 0; i < MemBlockY.Length; i++)
      {
        mappaValori.Add(i.ToString("0000"), MemBlockY[i].ToString());
      }
      utils.WritePlain(mappaValori, nomeFile);

      // salvo in file i dati letti come DWord (4byte)
      nomeFile = string.Format(@"{0}\MemDump_Y_DW.dat", utils.dataDatDir);
      mappaValori = new Dictionary<string, string>();
      for (int i = 0; i < MemBlockY.Length / 4; i++)
      {
        mappaValori.Add(i.ToString("0000"), BitConverter.ToUInt32(MemBlockY, i * 4).ToString());
      }
      utils.WritePlain(mappaValori, nomeFile);

      // salvo in file i dati letti come DWord (4byte)
      nomeFile = string.Format(@"{0}\MemDump_Y_W.dat", utils.dataDatDir);
      mappaValori = new Dictionary<string, string>();
      for (int i = 0; i < MemBlockY.Length / 2; i++)
      {
        mappaValori.Add(i.ToString("0000"), BitConverter.ToUInt16(MemBlockY, i * 2).ToString());
      } 
      utils.WritePlain(mappaValori, nomeFile);
#endif
    }
    #endregion
  }
}
