/*
 * Copyright Copyright 2016, Steamware s.r.l. & CMS/SCM s.p.a.
 *
 * Based on data, code and example by MTC consortium & System Insights, Inc.
 *
 * */
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Threading;
using System.Windows.Forms;
using NLog;
using MTC;
using NLog.Config;
using NLog.Targets;
using System.Collections;
using System.Configuration;
using System.Diagnostics;
using System.IO;

namespace MTC_Adapter
{

    public partial class MainForm : Form
    {
        #region inizializzazione contatori

        /// <summary>
        /// contatore veloce
        /// </summary>
        protected int fastCount;
        /// <summary>
        /// contatore normale
        /// </summary>
        protected int normCount;
        /// <summary>
        /// contatore lento
        /// </summary>
        protected int slowCount;
        /// <summary>
        /// contatore sync allarmi
        /// </summary>
        protected int alarmSyncCount;
        /// <summary>
        /// timer base in avvio
        /// </summary>
        protected int startTimerMs = 250;
        /// <summary>
        /// ultimo tentativo riavvio...
        /// </summary>
        protected DateTime lastStartTry;

        #endregion

        #region inizializzazione oggetti base

        /// <summary>
        /// oggetto logging
        /// </summary>
        public static Logger lg;

        /// <summary>
        /// Oggetto x gestione dell'adapter GENERICO (x poter usare metodi di ognuno...)
        /// </summary>
        AdapterGeneric agObj;
        /// <summary>
        /// configurazione caricata
        /// </summary>
        AdapterConf adpConf;
        /// <summary>
        /// tipo di adapter prescelto...
        /// </summary>
        protected tipoAdapter tipoScelto = tipoAdapter.DEMO;

        #endregion


        #region utils ed helpers

        public static void EnableTab(TabPage page, bool enable)
        {
            EnableControls(page.Controls, enable);
        }
        private static void EnableControls(Control.ControlCollection ctls, bool enable)
        {
            foreach (Control ctl in ctls)
            {
                ctl.Enabled = enable;
                EnableControls(ctl.Controls, enable);
            }
        }
        private class Item
        {
            public string Name;
            public int Value;
            public Item(string name, int value)
            {
                Name = name; Value = value;
            }
        }
        /// <summary>
        /// mostra un testo sulla status bar ed attende startTimerMs
        /// </summary>
        /// <param name="txt2show"></param>
        public void displayTaskAndWait(string txt2show)
        {
            lblStatus.Text = txt2show;
            lg.Info(txt2show);
            Thread.Sleep(startTimerMs);
        }

        #endregion

        #region gestione form e visibilità

        /// <summary>
        /// Gestione form principale
        /// </summary>
        public MainForm()
        {
            InitializeComponent();
            lblStatus.Text = "Loading";

            lastStartTry = DateTime.Now;

            // fix icon!
            Icon = Icon.ExtractAssociatedIcon(defIconFilePath);
            notifyIcon1.Icon = Icon.ExtractAssociatedIcon(defIconFilePath);

            // fix versione!
            lblApp.Text = string.Format("{0}", ConfigurationManager.AppSettings.Get("appName"));
            lblVers.Text = string.Format(" v.{0}", System.Reflection.Assembly.GetExecutingAssembly().GetName().Version);

            startTimerMs = utils.CRI("startTimerMs");

#if DEBUG
            // Setup the logging view for Sentinel - http://sentinel.codeplex.com
            var sentinalTarget = new NLogViewerTarget()
            {
                Name = "sentinal",
                Address = "udp://127.0.0.1:9999",
                IncludeNLogData = false
            };
            var sentinalRule = new LoggingRule("*", LogLevel.Trace, sentinalTarget);
            LogManager.Configuration.AddTarget("sentinal", sentinalTarget);
            LogManager.Configuration.LoggingRules.Add(sentinalRule);

#endif

            LogManager.ReconfigExistingLoggers();

            lg = LogManager.GetCurrentClassLogger();
            displayTaskAndWait("Starting MainForm");

            // inizio con tab control disabilitati
            EnableTab(tabCtrlMain.TabPages[1], false);
            EnableTab(tabCtrlMain.TabPages[2], false);

            // se abilitato autoload conf leggo file corretto...
            if (utils.CRB("autoLoadConf"))
            {
                loadXmlFile(defConfFilePath);
                lg.Info("XML LOADED");
                loadPersistLayer(defPersLayerFile);
                lg.Info("PersLayerFile READ");
                agObj.loadPersData();
                lg.Info("PersLayerFile LOADED");
            }
            else
            {
                // definisco e avvio tipo adapter generico
                tipoScelto = tipoAdapter.ND;
                adpConf = new AdapterConf();
                loadAdapterType();
                displayTaskAndWait("Waiting for config file selection");
            }

            // Start timer periodico
            gather.Interval = utils.CRI("timerIntMs");
            gather.Enabled = true;

            displayTaskAndWait("Program Running");
            createTrayMenu();
            displayTaskAndWait("Tray Menu OK");

            // avvio minimizzato se richiesto
            if (utils.CRB("startMinimized"))
            {
                // imposto minimized se necessario!
                if (WindowState != FormWindowState.Minimized)
                {
                    WindowState = FormWindowState.Minimized;
                }
                displayTaskAndWait("Minimized");
            }

            displayTaskAndWait("Main Form OK");
        }
        /// <summary>
        /// Verifica finale a fine show...
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void MainForm_Shown(object sender, EventArgs e)
        {
            // avvio minimizzato se richiesto
            if (utils.CRB("startMinimized"))
            {
                // controllo e mando a tray...
                sendToTray();
            }
            displayTaskAndWait("Main Form SHOWN");
        }
        /// <summary>
        /// crea menù tray x applicazione
        /// </summary>
        private void createTrayMenu()
        {
            // Fix testi menù tray...
            trayMenu.Items.Clear();
            // SE permessa massimizzazione...
            if (utils.CRB("windowCanMax"))
            {
                trayMenu.Items.Add("Show MTC Adapter");
            }
            // se è permesso tray close...
            if (utils.CRB("trayClose"))
            {
                trayMenu.Items.Add("Close MTC Adapter");
            }
        }

        /// <summary>
        /// doppio click su tray icon
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void notifyIcon1_DoubleClick(object sender, EventArgs e)
        {
            // SOLO SE PERMESSO mostrare full...
            if (utils.CRB("windowCanMax"))
            {
                Show();
                WindowState = FormWindowState.Normal;
            }
        }
        /// <summary>
        /// evento resize
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void MainForm_Resize(object sender, EventArgs e)
        {
            checkFormVisibility();
        }
        /// <summary>
        /// Verifica stato windows (minimized/normal) e visibilità con tray...
        /// </summary>
        private void checkFormVisibility()
        {
            // se non può massimizzare imposto COMUNQUE a minimized...
            if (!utils.CRB("windowCanMax"))
            {
                WindowState = FormWindowState.Minimized;
            }
            // controllo cosa devo mostrare...
            if (WindowState == FormWindowState.Minimized)
            {
                notifyIcon1.Visible = false;
                sendToTray();
            }
            else
            {
                notifyIcon1.Visible = false;
            }

        }
        /// <summary>
        /// Gestisce "andata nel tray" della form
        /// </summary>
        private void sendToTray()
        {
            if (!notifyIcon1.Visible)
            {
                notifyIcon1.BalloonTipTitle = utils.CRS("appName");
                notifyIcon1.BalloonTipText = string.Format("{0} running on tray", utils.CRS("appName"));
                notifyIcon1.Visible = true;
                notifyIcon1.ShowBalloonTip(100);
            }
            Hide();
        }
        /// <summary>
        /// click su menù contestuale in tray
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void trayMenu_ItemClicked(object sender, ToolStripItemClickedEventArgs e)
        {
            if (e.ClickedItem.Text.StartsWith("Close"))
            {
                // stop adapter...
                closeAdapter();
                // chiudo!
                Close();
            }
            else if (e.ClickedItem.Text.StartsWith("Show"))
            {
                if (utils.CRB("windowCanMax"))
                {
                    Show();
                    WindowState = FormWindowState.Normal;
                }
            }

        }

        #endregion

        protected string defConfFilePath
        {
            get
            {
                return string.Format(@"{0}\{1}", utils.confDir, utils.CRS("defaultConfFile"));
            }
        }
        /// <summary>
        /// File persistenza generale
        /// </summary>
        protected string defPersLayerFile
        {
            get
            {
                return string.Format(@"{0}\{1}", utils.dataDatDir, utils.CRS("defaultPersLayerFile"));
            }
        }
        protected string defIconFilePath
        {
            get
            {
                return string.Format(@"{0}\MTCA.ico", utils.resxDir);
            }
        }

        /// <summary>
        /// carica adapter richiesto
        /// </summary>
        private void loadAdapterType()
        {
            switch (tipoScelto)
            {
                case tipoAdapter.DEMO:
                    agObj = new AdapterDemo(this, adpConf);
                    EnableTab(tabCtrlMain.TabPages[1], true);
                    EnableTab(tabCtrlMain.TabPages[2], true);
                    start.Enabled = true;
                    break;
                case tipoAdapter.ESAGV:
                    agObj = new AdapterESA(this, adpConf);
                    EnableTab(tabCtrlMain.TabPages[1], true);
                    EnableTab(tabCtrlMain.TabPages[2], false);
                    start.Enabled = true;
                    break;
                case tipoAdapter.FANUC:
                    agObj = new AdapterFanuc(this, adpConf);
                    EnableTab(tabCtrlMain.TabPages[1], true);
                    EnableTab(tabCtrlMain.TabPages[2], false);
                    start.Enabled = true;
                    break;
                case tipoAdapter.OSAI:
                    agObj = new AdapterOsai(this, adpConf);
                    EnableTab(tabCtrlMain.TabPages[1], true);
                    EnableTab(tabCtrlMain.TabPages[2], false);
                    start.Enabled = true;
                    break;
                case tipoAdapter.SIEMENS:
                    agObj = new AdapterSiemens(this, adpConf);
                    EnableTab(tabCtrlMain.TabPages[1], true);
                    EnableTab(tabCtrlMain.TabPages[2], false);
                    start.Enabled = true;
                    break;
                case tipoAdapter.ND:
                default:
                    agObj = new AdapterDemo(this, adpConf);
                    EnableTab(tabCtrlMain.TabPages[1], false);
                    EnableTab(tabCtrlMain.TabPages[2], false);
                    start.Enabled = false;
                    break;
            }
            lblCurrAdapt.Text = string.Format("Adapter loaded: {0}", tipoScelto.ToString().ToUpper());

            // carico i default values su interfaccia
            setDefaults();

            displayTaskAndWait(string.Format("Caricata conf per adapter {0}", tipoScelto));
        }

        /// <summary>
        /// impostazione valori defaults
        /// </summary>
        private void setDefaults()
        {
            stop.Enabled = false;
            dump.Enabled = false;

            D1_NAME.Text = "DEMO MACHINE"; // utils.CRS("D1_NAME");
            D1_ID.Text = "DEMO ID"; //utils.CRS("D1_ID");
            D1_UUID.Text = "DEMO UUID"; // utils.CRS("D1_UUID");

            program.Text = "DEMO PRG"; // utils.CRS("D1_PROGRAM");
            PROG_ROW_NUM.Text = "0";
            partID.Text = "DEMO PART-ID"; // utils.CRS("PartID");

            pzOk = 0;
            pzKo = 0;
            Power = 1000;
            AccTime = 1440 * 365;

            OPERATOR_ID.Text = "OPxxxx";

            STATUS_STRB_DW0.Text = utils.binaryForm(0);
            STATUS_STRB_DW1.Text = utils.binaryForm(0);
            STATUS_STRB_DW2.Text = utils.binaryForm(0);
            STATUS_STRB_DW3.Text = utils.binaryForm(0);

            STATUS_ACK_DW0.Text = utils.binaryForm(0);
            STATUS_ACK_DW1.Text = utils.binaryForm(0);
            STATUS_ACK_DW2.Text = utils.binaryForm(0);
            STATUS_ACK_DW3.Text = utils.binaryForm(0);

            MainProgrBar.Minimum = 0;
            MainProgrBar.Maximum = 1000;
            MainProgrBar.Value = 0;
            MainProgrBar.Step = 1;

            // compilo combobox causali fermo...
            string[] contenuto = File.ReadAllLines(utils.confDir + "\\HaltTypeList.map");

            System.Collections.Generic.Dictionary<string, string> comboSource = new Dictionary<string, string>();
            foreach (var line in contenuto)
            {
                // se la linea non è commento e non è vuota...
                if (line.Length > 0 && line[0] != '#')
                {
                    string[] tokens = line.Split(':');
                    comboSource.Add(tokens[0], tokens[1]);
                }
            }
            functionalMode.DataSource = new BindingSource(comboSource, null);
            functionalMode.DisplayMember = "Value";
            functionalMode.ValueMember = "Key";


            string[] row = { "0", "0", "0", "0", "0", "0" };
            PosAct.Rows.Add(row);

            // fix componenti vettoriali PATH, UNOP, ASSI...
            for (int i = 0; i < adpConf.nPath; i++)
            {
                cbPathSel.Items.Insert(i, adpConf.Path[i].ident);
            }
            if (adpConf.nPath > 0) cbPathSel.SelectedIndex = 0;

            for (int i = 0; i < adpConf.nUnOp; i++)
            {
                cbUnOpSel.Items.Insert(i, adpConf.UnOp[i].ident);
            }
            if (adpConf.nUnOp > 0) cbUnOpSel.SelectedIndex = 0;

            for (int i = 0; i < adpConf.nAxis; i++)
            {
                cbAxNum.Items.Insert(i, adpConf.Axis[i].ident);
            }
            if (adpConf.nAxis > 0) cbAxNum.SelectedIndex = 0;


        }

        /// <summary>
        /// Avvio dell'adapter
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void start_Click(object sender, EventArgs e)
        {
            avviaAdapter();
            agObj.loadPersData();
            // salvo che ho avviato adapter
            lg.Info("Completato LOAD Adapter");
        }

        public void avviaAdapter()
        {
            displayTaskAndWait("Adapter starting");
            // se NON sta girando...
            if (!agObj.adpRunning)
            {
                int porta = Convert.ToInt32(port.Text);
                agObj.startAdapter(porta);
                displayTaskAndWait("Adapter started!");

                // fix buttons start/stop/dump
                start.Enabled = false;
                stop.Enabled = true;
                dump.Enabled = true;
                if (utils.CRB("openDumpOnStart"))
                {
                    displayTaskAndWait("Dump Window starting");
                    apriDumpAgent();
                    displayTaskAndWait("Dump Windows OK");
                }

                displayTaskAndWait("Start Timers");
                // inizializzo contatori fast/mid/slow
                fastCount = utils.CRI("fastCount");
                normCount = utils.CRI("normCount");
                slowCount = utils.CRI("slowCount");
                alarmSyncCount = utils.CRI("alarmSyncCount");
                displayTaskAndWait("Adapter Running...");
                // forzo check allarmi..
                agObj.forceAlarmCheck();
            }
            else
            {
                displayTaskAndWait("Adapter STILL Running...");
            }
        }

        /// <summary>
        /// fermata dell'adapter
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void stop_Click(object sender, EventArgs e)
        {
            fermaAdapter(false);
            // salvo che ho fermato adapter
            lg.Info("UNLOAD Adapter");
        }
        /// <summary>
        /// Ferma l'adapter
        /// </summary>
        /// <param name="tryRestart">determina se si debba tentare riavvio automatico (per caduta connessione)</param>
        public void fermaAdapter(bool tryRestart)
        {
            fermaTutto(false, tryRestart);
        }

        private void gather_Tick(object sender, EventArgs e)
        {
            // eseguo cicli attivi SOLO se adapter è in EFFETTIVO running...
            if (agObj.adpRunning)
            {
                // inizio a riportare che sto eseguendo..
                advProgBar();
                if (agObj.connectionOk)
                {
                    // check esecuzione FastTask
                    checkFastTask();
                    // check esecuzione NormTask
                    checkNormTask();
                    // check esecuzione SlowTask
                    checkSlowTask();
                    // check esecuzione AlarmSync
                    checkAlarmSync();
                }
                else
                {
                    double currWait = DateTime.Now.Subtract(lastStartTry).TotalMilliseconds;
                    if (agObj.adpTryRestart && currWait > utils.CRI("waitRecMSec"))
                    {
                        lastStartTry = DateTime.Now;
                        agObj.tryConnect();
                        agObj.loadPersData();
                    }
                }
                // se è arrivato a MAX resetto...
                if (MainProgrBar.Value >= MainProgrBar.Maximum)
                {
                    MainProgrBar.Value = 0;
                }
            }
            else
            {
                // verifico SE debba tentare il riavvio, ovvero NON running ma tryReconn e non ho riprovato x oltre waitRecMSec
                double currWait = DateTime.Now.Subtract(lastStartTry).TotalMilliseconds;
                if (agObj.adpTryRestart && currWait > utils.CRI("waitRecMSec"))
                {
                    lastStartTry = DateTime.Now;
                    avviaAdapter();
                    agObj.loadPersData();
                }
            }
        }

        public void resetProgBar()
        {
            MainProgrBar.Value = 0;
        }

        private void checkAlarmSync()
        {

            alarmSyncCount--;
            if (alarmSyncCount <= 0)
            {
                alarmSyncCount = utils.CRI("alarmSyncCount");

                // avvio fase raccolta dati e invio con adapter
                agObj.gaterAndSend(gatherCycle.VLF);
            }
        }
        private void checkSlowTask()
        {
            slowCount--;
            if (slowCount <= 0)
            {
                slowCount = utils.CRI("slowCount");

                // avvio fase raccolta dati e invio con adapter
                agObj.gaterAndSend(gatherCycle.LF);

                // refresh stringhe code M/S/T
                refreshCodeMST();

                // effettua salvataggio del file di conf con i valori ATTUALI dei parametri ove applicabile/aggiornati (es ore utilizzo, KM assi percorsi...) --> sia file corrente che file "history"
                persistData();
            }
        }

        /// <summary>
        /// file persistenza generale
        /// </summary>
        public string histPersLayerFile
        {
            get
            {
                return string.Format(@"{0}\{1:yyyy}\{1:yyyy-MM-dd}.mtc", utils.dataDatDir, DateTime.Now);
            }
        }
        /// <summary>
        /// file persistenza generale data attuale ANTICIPATA di xx giorni
        /// </summary>
        /// <param name="numDD">num DD di anticipo</param>
        /// <returns></returns>
        public string prevPersLayerFile(int numDD)
        {
            return string.Format(@"{0}\{1:yyyy}\{1:yyyy-MM-dd}.mtc", utils.dataDatDir, DateTime.Now.AddDays(-numDD));
        }
        /// <summary>
        /// salva i valori attuali del file di conf sia in file corrente che in cartella valori storici
        /// </summary>
        public void persistData()
        {
            // salvo ogni "autoSaveSec" secondi dall'ultimo salvataggio...
            TimeSpan tempoMod = new TimeSpan(0);
            if (File.Exists(defPersLayerFile))
            {
                DateTime adesso = DateTime.Now;
                tempoMod = DateTime.Now.Subtract(File.GetLastWriteTime(defPersLayerFile));
            }
            if (tempoMod.TotalSeconds > utils.CRI("autoSaveSec"))
            {
                savePersistLayer(defPersLayerFile);
                savePersistLayer(histPersLayerFile);
            }
        }

        private void checkNormTask()
        {

            // decremento...
            normCount--;
            // se il counter è a zero eseguo...
            if (normCount <= 0)
            {
                normCount = utils.CRI("normCount");

                // avvio fase raccolta dati e invio con adapter
                agObj.gaterAndSend(gatherCycle.MF);
            }
        }
        /// <summary>
        /// Avanza la barra di stato...
        /// </summary>
        public void advProgBar()
        {
            try
            {
                MainProgrBar.PerformStep();
                MainProgrBar.Invalidate();
            }
            catch
            { }
        }

        private void checkFastTask()
        {
            // decremento...
            fastCount--;
            // se il counter è a zero eseguo...
            if (fastCount <= 0)
            {
                fastCount = utils.CRI("fastCount");

                // avvio fase raccolta dati e invio con adapter
                agObj.gaterAndSend(gatherCycle.HF);

                refreshVisualStrobes();
            }
        }

        private void message_Leave(object sender, EventArgs e)
        {
        }

        // apro eseguibile dump
        private void dump_Click(object sender, EventArgs e)
        {
            apriDumpAgent();
        }
        /// <summary>
        /// apre agent di dump in CMD
        /// </summary>
        private static void apriDumpAgent()
        {
            string path = Application.StartupPath;
            try
            {
                Process.Start(string.Format(@"{0}\..\..\dump\dump.exe", path));
            }
            catch
            {
                Process.Start(string.Format(@"{0}\dump\dump.exe", path));
            }
        }

        #region classi x simulazione valori vari

        /// <summary>
        /// simula alcuni dati generando ad esempio numeri casuali... SE abilitato e SE adapter è DEMO
        /// </summary>
        private void simulateData()
        {
            if (enableDataSim.Checked && tipoScelto == tipoAdapter.DEMO)
            {
                DateTime adesso = DateTime.Now;
                Random rnd = new Random();
                // 10% casi cambia riga
                if (rnd.Next(0, 100) > 90)
                {
                    PROG_ROW_NUM.Text = rnd.Next(1, 10000).ToString();
                }


                // cambio posizioni 6% casi: aggiungo codici M
                if (rnd.Next(0, 100) > 95)
                {
                    agObj.appendCodeMST("M", rnd.Next(1, 30).ToString());
                }

                // cambio posizioni 3% casi: aggiungo codici S
                if (rnd.Next(0, 100) > 97)
                {
                    agObj.appendCodeMST("S", rnd.Next(100, 10000).ToString());
                }
                // cambio posizioni 3% casi: aggiungo codici T
                if (rnd.Next(0, 100) > 97)
                {
                    agObj.appendCodeMST("T", rnd.Next(1, 100).ToString());
                }


                // aggiungo 1 pz al totale nel 0.3% dei casi (-->TC circa 333 x tick)...
                if (rnd.Next(0, 1000) > 997)
                {
                    pzOk++;
                    agObj.STROBE_PLC = agObj.STROBE_PLC | Strobe.PZ_OK;
                }

                // cambio posizioni XYZ/ijk nel 20% dei casi x ogni terna...
                if (rnd.Next(0, 100) > 80)
                {
                    PosAct.Rows[0].Cells[0].Value = rnd.Next(0, 100);
                    PosAct.Rows[0].Cells[1].Value = rnd.Next(0, 100);
                    PosAct.Rows[0].Cells[2].Value = rnd.Next(0, 100);
                    agObj.STROBE_PLC = agObj.STROBE_PLC | Strobe.POS_ACT;
                }
                if (rnd.Next(0, 100) > 80)
                {
                    PosAct.Rows[0].Cells[3].Value = rnd.Next(0, 100);
                    PosAct.Rows[0].Cells[4].Value = rnd.Next(0, 100);
                    PosAct.Rows[0].Cells[5].Value = rnd.Next(0, 100);
                    agObj.STROBE_PLC = agObj.STROBE_PLC | Strobe.POS_ACT;
                }


                // cambio power nel 15% dei casi...
                if (rnd.Next(0, 100) > 85)
                {
                    Power += rnd.Next(-10, 10);
                }
                // aggiungo 1 min AccTime nel 0.1% dei casi
                if (rnd.Next(0, 1000) > 999)
                {
                    AccTime++;
                }

                // toggle 1 allarme sys nello 0.5% dei casi
                if (rnd.Next(0, 1000) > 995)
                {
                    int codAlarm = rnd.Next(1, 3);
                    switch (codAlarm)
                    {
                        case 1:
                            SysErr_01.Checked = !SysErr_01.Checked;
                            break;
                        case 2:
                            SysErr_02.Checked = !SysErr_02.Checked;
                            break;
                        default:
                            SysErr_03.Checked = !SysErr_03.Checked;
                            break;
                    }
                    agObj.STATUS_FLAG = agObj.STATUS_FLAG | StatusBitMap.AL01;
                }
                // toggle 1 allarme PLC nello 0.4% dei casi
                if (rnd.Next(0, 1000) > 996)
                {
                    int codAlarm = rnd.Next(1, 3);
                    switch (codAlarm)
                    {
                        case 1:
                            PlcErr_01.Checked = !PlcErr_01.Checked;
                            break;
                        case 2:
                            PlcErr_02.Checked = !PlcErr_02.Checked;
                            break;
                        default:
                            PlcErr_03.Checked = !PlcErr_03.Checked;
                            break;
                    }
                    agObj.STATUS_FLAG = agObj.STATUS_FLAG | StatusBitMap.AL02;
                }
                // toggle 1 allarme CNC nello 0.3% dei casi
                if (rnd.Next(0, 1000) > 997)
                {
                    int codAlarm = rnd.Next(1, 3);
                    switch (codAlarm)
                    {
                        case 1:
                            CncErr_01.Checked = !CncErr_01.Checked;
                            break;
                        case 2:
                            CncErr_02.Checked = !CncErr_02.Checked;
                            break;
                        default:
                            CncErr_03.Checked = !CncErr_03.Checked;
                            break;
                    }
                    agObj.STATUS_FLAG = agObj.STATUS_FLAG | StatusBitMap.AL03;
                }

                // nel 2% dei casi imposto un RUN MODE diverso da RUN
                if (rnd.Next(0, 100) > 98)
                {
                    int codSel = rnd.Next(1, 3);
                    switch (codSel)
                    {
                        case 1:
                            manual.Checked = true;
                            break;
                        case 2:
                            mdi.Checked = true;
                            break;
                        default:
                            edit.Checked = true;
                            break;
                    }
                }
                // nel 3% degli altri casi riporto RUN MODE a RUN
                else
                {
                    if (rnd.Next(0, 100) > 97)
                    {
                        automatic.Checked = true;
                    }
                }


                // nel 2% dei casi imposto un EXE MODE diverso da AUTO
                if (rnd.Next(0, 100) > 98)
                {
                    int codSel = rnd.Next(1, 3);
                    switch (codSel)
                    {
                        case 1:
                            ready.Checked = true;
                            break;
                        case 2:
                            stopped.Checked = true;
                            break;
                        default:
                            feedhold.Checked = true;
                            break;
                    }
                }
                // nel 3% degli altri casi riporto EXE MODE a AUTO
                else
                {
                    if (rnd.Next(0, 100) > 97)
                    {
                        running.Checked = true;
                    }
                }



                // controllo se ci sia il flag di lettura di un evento M/S/T nel qual caso lo abbasso...
                if (utils.IsSetAll(agObj.STROBE_ADP, Strobe.M_CODE))
                {
                    if (utils.IsSetAll(agObj.STROBE_PLC, Strobe.M_CODE)) agObj.STROBE_PLC -= Strobe.M_CODE;
                }
                if (utils.IsSetAll(agObj.STROBE_ADP, Strobe.S_CODE))
                {
                    if (utils.IsSetAll(agObj.STROBE_PLC, Strobe.S_CODE)) agObj.STROBE_PLC -= Strobe.S_CODE;
                }
                if (utils.IsSetAll(agObj.STROBE_ADP, Strobe.T_CODE))
                {
                    if (utils.IsSetAll(agObj.STROBE_PLC, Strobe.T_CODE)) agObj.STROBE_PLC -= Strobe.T_CODE;
                }

                // controllo se ci sia il flag di lettura di un evento pz ok/ko nel qual caso lo abbasso...
                if (utils.IsSetAll(agObj.STROBE_ADP, Strobe.PZ_OK))
                {
                    if (utils.IsSetAll(agObj.STROBE_PLC, Strobe.PZ_OK)) agObj.STROBE_PLC -= Strobe.PZ_OK;
                }
                if (utils.IsSetAll(agObj.STROBE_ADP, Strobe.PZ_KO))
                {
                    if (utils.IsSetAll(agObj.STROBE_PLC, Strobe.PZ_KO)) agObj.STROBE_PLC -= Strobe.PZ_KO;
                }

                // controllo se ci sia il flag di lettura di un evento FEED_SPEED nel qual caso lo abbasso...
                if (utils.IsSetAll(agObj.STROBE_ADP, Strobe.FEED_SPEED))
                {
                    if (utils.IsSetAll(agObj.STROBE_PLC, Strobe.FEED_SPEED)) agObj.STROBE_PLC -= Strobe.FEED_SPEED;
                }

                // controllo se ci sia il flag di lettura di un evento POS_ACT nel qual caso lo abbasso...
                if (utils.IsSetAll(agObj.STROBE_ADP, Strobe.POS_ACT))
                {
                    if (utils.IsSetAll(agObj.STROBE_PLC, Strobe.POS_ACT)) agObj.STROBE_PLC -= Strobe.POS_ACT;
                }

                refreshVisualStrobes();
                refreshCodeMST();
            }
        }

        private void refreshVisualStrobes()
        {
            // aggiorno visualizzazione strobe!
            STATUS_STRB_DW0.Text = utils.binaryForm((int)agObj.STRB_DW0);
            STATUS_STRB_DW1.Text = utils.binaryForm((int)agObj.STRB_DW1);
            STATUS_STRB_DW2.Text = utils.binaryForm((int)agObj.STRB_DW2);
            STATUS_STRB_DW3.Text = utils.binaryForm((int)agObj.STRB_DW3);

            STATUS_ACK_DW0.Text = utils.binaryForm((int)agObj.ACK_DW0);
            STATUS_ACK_DW1.Text = utils.binaryForm((int)agObj.ACK_DW1);
            STATUS_ACK_DW2.Text = utils.binaryForm((int)agObj.ACK_DW2);
            STATUS_ACK_DW3.Text = utils.binaryForm((int)agObj.ACK_DW3);
        }



        /// <summary>
        /// aggiorna visualizzazione code...
        /// </summary>
        private void refreshCodeMST()
        {
            lblCodaM.Text = string.Join(",", agObj.codaM.ToArray());
            lblCodaT.Text = string.Join(",", agObj.codaT.ToArray());
            lblCodaS.Text = string.Join(",", agObj.codaS.ToArray());
        }

        private void accodaCodM()
        {
            if (addCodM.Text.Trim() != "")
            {
                agObj.appendCodeMST("M", addCodM.Text.Trim());
                addCodM.Text = "";
            }
            refreshCodeMST();
        }
        private void accodaCodS()
        {
            if (addCodS.Text.Trim() != "")
            {
                agObj.appendCodeMST("S", addCodS.Text.Trim());
                addCodS.Text = "";
            }
            refreshCodeMST();
        }
        private void accodaCodT()
        {
            if (addCodT.Text.Trim() != "")
            {
                agObj.appendCodeMST("T", addCodT.Text.Trim());
                addCodT.Text = "";
            }
            refreshCodeMST();
        }

        private void addCodM_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Enter)
            {
                // accodo testo
                accodaCodM();
            }
            else if (e.KeyCode == Keys.Escape)
            {
                // svuoto!
                addCodM.Text = "";
            }
        }
        private void addCodM_Leave(object sender, EventArgs e)
        {
            accodaCodM();
        }
        private void addCodS_KeyDown(object sender, KeyEventArgs e)
        {

            if (e.KeyCode == Keys.Enter)
            {
                // accodo testo
                accodaCodS();
            }
            else if (e.KeyCode == Keys.Escape)
            {
                // svuoto!
                addCodS.Text = "";
            }
        }
        private void addCodS_Leave(object sender, EventArgs e)
        {
            accodaCodS();
        }
        private void addCodT_KeyDown(object sender, KeyEventArgs e)
        {

            if (e.KeyCode == Keys.Enter)
            {
                // accodo testo
                accodaCodT();
            }
            else if (e.KeyCode == Keys.Escape)
            {
                // svuoto!
                addCodT.Text = "";
            }
        }
        private void addCodT_Leave(object sender, EventArgs e)
        {
            accodaCodT();
        }



        #endregion

        private void txtPathFeed_TextChanged(object sender, EventArgs e)
        {
            hsPathFeed.Value = Convert.ToInt32(txtPathFeed.Text);
        }

        private void txtPathFeedOver_TextChanged(object sender, EventArgs e)
        {
            hsPathFeedOver.Value = Convert.ToInt32(txtPathFeedOver.Text);
        }

        private void txtPathSpeedOver_TextChanged(object sender, EventArgs e)
        {
            hsPathSpeedOver.Value = Convert.ToInt32(txtPathSpeedOver.Text);
        }

        private void raiseFlag_FEED_SPEED()
        {
            // se non c'è flag lo alzo...
            if (!utils.IsSetAll(agObj.STROBE_PLC, Strobe.FEED_SPEED))
            {
                agObj.STROBE_PLC = agObj.STROBE_PLC | Strobe.FEED_SPEED;
            }
        }

        private void hsPathFeed_ValueChanged(object sender, EventArgs e)
        {
            txtPathFeed.Text = hsPathFeed.Value.ToString();
            raiseFlag_FEED_SPEED();
        }

        private void hsPathFeedOver_ValueChanged(object sender, EventArgs e)
        {
            txtPathFeedOver.Text = hsPathFeedOver.Value.ToString();
            raiseFlag_FEED_SPEED();
        }

        private void hsPathSpeedOver_ValueChanged(object sender, EventArgs e)
        {
            txtPathSpeedOver.Text = hsPathSpeedOver.Value.ToString();
            raiseFlag_FEED_SPEED();
        }

        #region gestione load conf

        private void mConfGen_Click(object sender, EventArgs e)
        {
            SetupAdapter setupWIndow = new SetupAdapter();
            setupWIndow.Show(this);
        }

        private void mLoadAdaptConf_Click(object sender, EventArgs e)
        {
            // mostro selettore file x leggere adapter..
            OpenFileDialog openFileDial = new OpenFileDialog();

            // directory iniziale
            openFileDial.InitialDirectory = utils.confDir; // string.Format(@"{0}\{1}", Application.StartupPath, utils.CRS("dataConfPath"));
            // Set filter options and filter index.
            openFileDial.Filter = "XML Files (.xml)|*.xml|All Files (*.*)|*.*";
            openFileDial.FilterIndex = 1;
            // altre opzioni
            openFileDial.Multiselect = false;

            // Call the ShowDialog method to show the dialog box.
            DialogResult userClickedOK = openFileDial.ShowDialog();

            // Process input if the user clicked OK.
            if (userClickedOK == DialogResult.OK)
            {
                string XmlConfFile = openFileDial.FileName;
                loadXmlFile(XmlConfFile);
                lg.Info("XML LOADED");
                loadPersistLayer(defPersLayerFile);
                lg.Info("PersLayerFile READ");
                agObj.loadPersData();
                lg.Info("PersLayerFile LOADED");
            }
        }
        /// <summary>
        /// Carica file XML della configurazione richiesta
        /// </summary>
        /// <param name="XmlConfFile"></param>
        private void loadXmlFile(string XmlConfFile)
        {
            displayTaskAndWait(string.Format("Loading XML: {0}", XmlConfFile));

            // Read the configuration object from a file
            adpConf = AdapterConf.Deserialize(XmlConfFile);

            // indico quale sia il tipo di adapter
            tipoScelto = adpConf.TipoAdapt;
            loadAdapterType();
            // carico file XML in web browser...
            wbXmlConf.DocumentText = AdapterConf.rawXml(XmlConfFile);
            displayTaskAndWait("XML loaded");

            // avvio macchina con adapter specificato...
            if (utils.CRB("autoStartOnLoad"))
            {
                displayTaskAndWait("Auto Starting...");
                // avvio!
                avviaAdapter();
                displayTaskAndWait("Auto Started!");
            }
        }
        /// <summary>
        /// salva su file l'oggetto AdapterConf
        /// </summary>
        /// <param name="XmlConfFile"></param>
        public void saveXmlFile(string XmlConfFile)
        {
            AdapterConf.Serialize(XmlConfFile, agObj.currAdpConf);
        }
        /// <summary>
        /// Salva su file l'oggetto di persistenza dati
        /// </summary>
        /// <param name="filePath"></param>
        public void savePersistLayer(string filePath)
        {
            // in primis check semaforo salvataggio...
            if (!agObj.adpSaving)
            {
                // alzo semaforo salvataggio
                agObj.adpSaving = true;
                // se HO dei dati...
                if (agObj.persistenceLayer != null)
                {
                    try
                    {
                        utils.WritePlain(agObj.persistenceLayer, filePath);
                    }
                    catch (Exception exc)
                    {
                        lg.Error(string.Format("Errore salvataggio file{0}{1}", Environment.NewLine, exc));
                    }
                }
                else
                {
                    lg.Info("persistenceLayer null, non salvato...");
                }
                // abbasso semaforo salvataggio
                agObj.adpSaving = false;
            }
        }
        /// <summary>
        /// Carica da file l'oggetto di persistenza dati
        /// </summary>
        /// <param name="filePath"></param>
        public void loadPersistLayer(string filePath)
        {
            // inizializzo prima di leggere...
            agObj.persistenceLayer = new Dictionary<string, string>();
            agObj.persistenceLayer = utils.ReadPlain(filePath);

            // 2017.03.23 check problema files corrotti...
            if (agObj.persistenceLayer.Count == 0)
            {
                // se avesse letto un valore NON coerente (senza righe) PROVA a leggere a ritroso vecchi files... da histPersLayerFile e precedenti...
                int numDD = 0;
                int maxNumDD = utils.CRI("maxNumDD");
                Dictionary<string, string> lastRead = new Dictionary<string, string>();
                // continuo fino a che non leggo almeno 1 riga valida e non ho raggiunto maxDD
                while (numDD < maxNumDD && lastRead.Count == 0)
                {
                    // leggo il file storico alla data anticipata... (ci provo...)
                    try
                    {
                        lastRead = utils.ReadPlain(prevPersLayerFile(numDD));
                    }
                    catch
                    { }
                    numDD++;
                }
                // se sono uscito PROVO a passare il file storico letto buono (oppure vuoto...)
                agObj.persistenceLayer = lastRead;
            }
        }

        #endregion

        #region accesso dati produzione

        /// <summary>
        /// Dati di produzione (su form)
        /// </summary>
        public prodData datiProd
        {
            get
            {
                prodData answ = new prodData();
                // carico da form
                answ.Operator = OPERATOR_ID.Text;

                // variabili lette da + controlli
                answ.Status = stop.Enabled;
                answ.Power = Power;
                answ.AccTime = AccTime;
                answ.EmrStop = estop.Checked;

                answ.FuncMode = ((KeyValuePair<string, string>)functionalMode.SelectedItem).Key;

                answ.MessageCode = messageCode.Text;
                answ.MessageText = messageText.Text;

                // parto vuoto con StatusBitMap...
                agObj.STATUS_FLAG = 0;
                // aggiorno status flag in base a valori...
                if (answ.EmrStop) agObj.STATUS_FLAG = agObj.STATUS_FLAG | StatusBitMap.ESTOP;
                if (automatic.Checked) agObj.STATUS_FLAG = agObj.STATUS_FLAG | StatusBitMap.RM_AUTO;
                else if (mdi.Checked) agObj.STATUS_FLAG = agObj.STATUS_FLAG | StatusBitMap.RM_MDI;
                else if (edit.Checked) agObj.STATUS_FLAG = agObj.STATUS_FLAG | StatusBitMap.RM_EDIT;
                else agObj.STATUS_FLAG = agObj.STATUS_FLAG | StatusBitMap.RM_MANUAL;

                if (running.Checked) agObj.STATUS_FLAG = agObj.STATUS_FLAG | StatusBitMap.EM_RUN;
                else if (feedhold.Checked) agObj.STATUS_FLAG = agObj.STATUS_FLAG | StatusBitMap.EM_FEEDHOLD;
                else if (stopped.Checked) agObj.STATUS_FLAG = agObj.STATUS_FLAG | StatusBitMap.EM_STOP;
                else if (ready.Checked) agObj.STATUS_FLAG = agObj.STATUS_FLAG | StatusBitMap.EM_READY;
                if (answ.FuncMode != "1") agObj.STATUS_FLAG = agObj.STATUS_FLAG | StatusBitMap.HM;

                // ritorno oggetto!
                return answ;
            }
        }

        private void pzKo_TextChanged(object sender, EventArgs e)
        {
            agObj.STROBE_PLC = agObj.STROBE_PLC | Strobe.PZ_KO;
            txtPzTot.Text = pzTot.ToString();
        }
        protected int Power
        {
            get
            {
                int answ = 0;
                try
                {
                    answ = Convert.ToInt32(txtPower.Text.Trim());
                }
                catch
                { }
                return answ;
            }
            set
            {
                txtPower.Text = value.ToString();
            }
        }
        protected int AccTime
        {
            get
            {
                int answ = 0;
                try
                {
                    answ = Convert.ToInt32(txtAccTime.Text.Trim());
                }
                catch
                { }
                return answ;
            }
            set
            {
                txtAccTime.Text = value.ToString();
            }
        }
        protected int pzOk
        {
            get
            {
                int answ = 0;
                try
                {
                    answ = Convert.ToInt32(txtPzOk.Text.Trim());
                }
                catch
                { }
                return answ;
            }
            set
            {
                txtPzOk.Text = value.ToString();
                txtPzTot.Text = pzTot.ToString();
            }
        }
        protected int pzKo
        {
            get
            {
                int answ = 0;
                try
                {
                    answ = Convert.ToInt32(txtPzKo.Text.Trim());
                }
                catch
                { }
                return answ;
            }
            set
            {
                txtPzKo.Text = value.ToString();
                txtPzTot.Text = pzTot.ToString();
            }
        }
        protected int pzTot
        {
            get
            {
                return pzOk + pzKo;
            }
        }

        #endregion

        #region gestione Path


        private void cbPathSel_SelectedIndexChanged(object sender, EventArgs e)
        {
            hsPathFeed.Value = 50;
            hsPathFeedOver.Value = 50;
            hsPathSpeedOver.Value = 50;
            Random rnd = new Random();
            PosAct.Rows[0].Cells[0].Value = rnd.Next(0, 1000);
            PosAct.Rows[0].Cells[1].Value = rnd.Next(0, 1000);
            PosAct.Rows[0].Cells[2].Value = rnd.Next(0, 1000);
            PosAct.Rows[0].Cells[3].Value = rnd.Next(0, 360);
            PosAct.Rows[0].Cells[4].Value = rnd.Next(0, 360);
            PosAct.Rows[0].Cells[5].Value = rnd.Next(0, 360);
        }

        /// <summary>
        /// Dati PATH
        /// </summary>
        public PathData CurrPath
        {
            get
            {
                PathData answ = new PathData();

                // modifiche dati portati da macchina a path...
                answ.ProgramName = program.Text;
                answ.ProgrRow = PROG_ROW_NUM.Text;
                answ.PartId = partID.Text;
                answ.PathType = "LAVORO";
                // pezzi
                answ.pzTot = pzOk + pzKo;

                if (automatic.Checked) answ.RunMode = "AUTOMATIC";
                else if (mdi.Checked) answ.RunMode = "MANUAL_DATA_INPUT";
                else if (edit.Checked) answ.RunMode = "EDIT";
                else answ.RunMode = "MANUAL";

                if (running.Checked) answ.ExeMode = "ACTIVE";
                else if (feedhold.Checked) answ.ExeMode = "FEED_HOLD";
                else if (stopped.Checked) answ.ExeMode = "STOPPED";
                else if (ready.Checked) answ.ExeMode = "READY";

                answ.ActiveAxes = "1 2 3 4 5 6"; // lascio sempre tutti attivi...

                answ.PathSel = cbPathSel.SelectedIndex;
                // FEED/SPEED
                answ.PathFeedrate = hsPathFeed.Value;
                answ.PathFeedrateOver = hsPathFeedOver.Value;
                answ.PathRapidOver = hsPathSpeedOver.Value;

                // posizione attuale
                position posAct = new position();
                DataGridViewCellCollection cells = PosAct.Rows[0].Cells;
                float.TryParse(cells[0].Value.ToString(), out posAct.x);
                float.TryParse(cells[1].Value.ToString(), out posAct.y);
                float.TryParse(cells[2].Value.ToString(), out posAct.z);
                float.TryParse(cells[3].Value.ToString(), out posAct.i);
                float.TryParse(cells[4].Value.ToString(), out posAct.j);
                float.TryParse(cells[5].Value.ToString(), out posAct.k);
                answ.PathPosAct = posAct;

                // aggiungo altri oggetti...
                answ.CodG_Act = "G01 G10 G34 G60";
                answ.SubMode = string.Format("# Asse selezionato {0} #", cbAxNum.SelectedIndex);

                // ritorno oggetto!
                return answ;
            }
        }

        #endregion

        #region gestione UnOp


        private void cbUnOpSel_SelectedIndexChanged(object sender, EventArgs e)
        {
            uoToolId.Text = "1";
            uoNumCU.Text = "2";
            uoStatus.Text = "RUN";
            uoVitaRes.Text = "100";
            uoSpeed.Text = "80";
            uoLoad.Text = "80";
            uoAccTime.Text = "0";
        }

        /// <summary>
        /// Dati UnOp
        /// </summary>
        public UnOpData CurrUnOp
        {
            get
            {
                UnOpData answ = new UnOpData();

                answ.UnOpSel = cbUnOpSel.SelectedIndex;

                int.TryParse(uoToolId.Text, out answ.UnOpToolId);
                int.TryParse(uoNumCU.Text, out answ.UnOpNumCU);
                answ.UnOpStatus = uoStatus.Text;
                int.TryParse(uoVitaRes.Text, out answ.UnOpVitaRes);
                answ.UnOpSpeed = uoSpeed.Value;
                answ.UnOpLoad = uoLoad.Value;
                int.TryParse(uoAccTime.Text, out answ.UnOpAccTime);

                // ritorno oggetto!
                return answ;
            }
        }

        private void uoLoad_Scroll(object sender, ScrollEventArgs e)
        {
            uoLoadVal.Text = uoLoad.Value.ToString();
        }

        private void uoSpeed_Scroll(object sender, ScrollEventArgs e)
        {
            uoSpeedVal.Text = uoSpeed.Value.ToString();
        }

        #endregion

        #region gestione assi

        private void cbAxNum_SelectedIndexChanged(object sender, EventArgs e)
        {
            // aggiorna visualizzazione asse... imposto valori standard x controlli
            AxMainProc.Text = "1";
            AxIsMaster.Checked = false;
            AxMastId.Text = "0";
            cbAxType.SelectedIndex = 0;
            AxDir.Text = "1";
            AxLoad.Value = 50;
            AxPosition.Value = 50;
            AxFeedAct.Value = 50;
            AxFeedOver.Value = 100;
            AxAccelAct.Text = "0";
            AxAccTime.Text = "0";
            AxBatt.Text = "100";
        }

        /// <summary>
        /// Dati di produzione (su form)
        /// </summary>
        public AxisData CurrAxis
        {
            get
            {
                Random rnd = new Random();
                AxisData answ = new AxisData();
                answ.AxisSel = cbAxNum.SelectedIndex;
                answ.AxisMainProc = AxMainProc.Text;
                answ.AxisIsMaster = AxIsMaster.Checked;
                answ.AxisMastId = AxMastId.Text;
                answ.AxisType = AxisType;
                answ.AxisDir = AxDir.Text;
                answ.AxisLoad = AxLoad.Value;
                answ.AxisPosAct = AxPosition.Value;// + rnd.Next(-2, 2);
                answ.AxisPosTgt = AxPosition.Value;
                answ.AxisFeedAct = AxFeedAct.Value;
                answ.AxisFeedOver = AxFeedOver.Value;
                answ.AxisAccel = AxAccelAct.Text;
                answ.AxisAccTime = AxAccTime.Text;
                answ.AxisBattery = AxBatt.Text;

                // restituisco oggetto
                return answ;
            }
        }

        protected string AxisType
        {
            get
            {
                string answ = "";
                try
                {
                    answ = cbAxType.SelectedItem.ToString(); ;
                }
                catch
                { }
                return answ;
            }
        }

        private void xLoad_Scroll(object sender, ScrollEventArgs e)
        {
            AxLoadValue.Text = AxLoad.Value.ToString();
        }

        private void xPosition_Scroll(object sender, ScrollEventArgs e)
        {

            AxPositionValue.Text = AxPosition.Value.ToString();
        }

        private void cLoad_Scroll(object sender, ScrollEventArgs e)
        {
            AxFeedActValue.Text = AxFeedAct.Value.ToString();
        }

        private void cSpeed_Scroll(object sender, ScrollEventArgs e)
        {
            AxFeedOverValue.Text = AxFeedOver.Value.ToString();
        }

        #endregion


        /// <summary>
        /// Stringa dati monitoraggio mostrata (1 SX)...
        /// </summary>
        public string dataMonitor_1
        {
            get
            {
                return lblOutMessage.Text;
            }
            set
            {
                lblOutMessage.Text = value;
            }
        }
        /// <summary>
        /// Stringa dati monitoraggio mostrata (2 centro)...
        /// </summary>
        public string dataMonitor_2
        {
            get
            {
                return lblOutMessage2.Text;
            }
            set
            {
                lblOutMessage2.Text = value;
            }
        }
        /// <summary>
        /// Stringa dati monitoraggio mostrata (3 dx)...
        /// </summary>
        public string dataMonitor_3
        {
            get
            {
                return lblOutMessage3.Text;
            }
            set
            {
                lblOutMessage3.Text = value;
            }
        }
        private void SysErr_01_CheckedChanged(object sender, EventArgs e)
        {
            // aggiorno il vettore allarmi (da 128 byte) sulla base della selezione dei checkbox (per i primi 9...) - ultimi 3 selezionano 8 allarmi ciascuno...
            BitArray bitArray = new BitArray(1024);

            bitArray[7] = SysErr_01.Checked;
            bitArray[6] = SysErr_02.Checked;
            bitArray[5] = SysErr_03.Checked;
            bitArray[4] = PlcErr_01.Checked;
            bitArray[3] = PlcErr_02.Checked;
            bitArray[2] = PlcErr_03.Checked;
            bitArray[1] = CncErr_01.Checked;
            bitArray[0] = CncErr_02.Checked;
            bitArray[15] = CncErr_03.Checked;

            // ne assegno 8 alla volta...
            for (int i = 0; i < 8; i++)
            {
                bitArray[16 + i] = ErrRT_01.Checked;
                bitArray[24 + i] = ErrRT_02.Checked;
                bitArray[32 + i] = ErrRT_03.Checked;
            }
            byte[] newAlarm = utils.ToByteArray(bitArray);
            Buffer.BlockCopy(newAlarm, 0, agObj.AlarmFlags, 0, 32);
        }

        private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            closeAdapter();
        }

        private void closeAdapter()
        {
            fermaTutto(true, false);
        }
        /// <summary>
        /// Ferma tutti i componenti adapter + update buttons
        /// </summary>
        /// <param name="stopTimer">determina se fermare il timer (gather) principale (solo se non si chiude)</param>
        /// <param name="tryRestart">determina se tentare di riconnettersi</param>
        private void fermaTutto(bool stopTimer, bool tryRestart)
        {
            agObj.stopAdapter(tryRestart);
            // salvo!
            savePersistLayer(defPersLayerFile);
            savePersistLayer(histPersLayerFile);

            stop.Enabled = false;
            dump.Enabled = false;
            start.Enabled = true;

            if (stopTimer)
            {
                gather.Enabled = false;
                agObj.tryDisconnect();
            }
        }

    }
}
