using AutoUpdaterDotNET;
using IOB_UT;
using MapoSDK;
using Newtonsoft.Json;
using NLog;
using NLog.Config;
using NLog.Targets;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Net;
using System.Net.NetworkInformation;
using System.Threading;
using System.Windows.Forms;

namespace IOB_WIN
{
    public partial class MainForm : Form
    {
        #region Protected Fields

        /// <summary>
        /// Ramo applicazione (x update)
        /// </summary>
        protected string branchName = "master";

        /// <summary>
        /// chiamata x check alive di base
        /// </summary>
        protected string CMDALIVE = "";

        /// <summary>
        /// chiamata x ricevere un codice IOB da gestire/acquisire
        /// </summary>
        protected string CMDIOB2CALL = "";

        /// <summary>
        /// chiamata x invio comunicazioen reboot dell'IOBMAN
        /// </summary>
        protected string CMDREBO = "";

        /// <summary>
        /// Data Avvio form
        /// </summary>
        protected DateTime formStartTime;

        /// <summary>
        /// Lista delle IOB da avviare
        /// </summary>
        protected List<string> IOB2START;

        /// <summary>
        /// Num max di CNC da gestire
        /// </summary>
        protected int MAXCNC = 1;

        /// <summary>
        /// Modalità di avvio
        /// </summary>
        protected StartMode ModoAvvio = StartMode.STD;

        /// <summary>
        /// Indirizzo server
        /// </summary>
        protected string MPIP = "";

        /// <summary>
        /// URL base applicazione
        /// </summary>
        protected string MPURL = "";

        /// <summary>
        /// Parametri (opzionali) di avvio
        /// </summary>
        protected string[] myArgs;

        /// <summary>
        /// var x gestione reset progBar... arrivato a 3 faccio reset
        /// </summary>
        protected int resetProgBar = 0;

        /// <summary>
        /// Dizionario dei parametri di avvio (da elenco args...)
        /// </summary>
        protected Dictionary<string, string> startParams = new Dictionary<string, string>();

        #endregion Protected Fields

        #region Public Fields

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

        /// <summary>
        /// Data ultimo controllo comunicazione
        /// </summary>
        public DateTime lastComCheck;

        /// <summary>
        /// Oggetto connessioen REDIS
        /// </summary>
        public RedisIobCache redisMan;

        #endregion Public Fields

        #region Public Constructors

        /// <summary>
        /// Init Main Form
        /// </summary>
        public MainForm(string[] args)
        {
            // salvo aprametri avvio...
            saveArgs(args);
            // continuo iNIT!!!
            InitializeComponent();
            myInit();
            if (args != null)
            {
                if (args.Length > 0)
                {
                    lgInfo("Argomenti di avvio:");
                    foreach (var item in myArgs)
                    {
                        lgInfo(item);
                    }
                }
                else
                {
                    lgInfo("NESSUN Argomento di avvio trovato");
                }
            }
        }

        #endregion Public Constructors

        #region Private Properties

        /// <summary>
        /// test ping all'indirizzo impostato nei parametri
        /// </summary>
        /// <returns></returns>
        private IPStatus testPingServer
        {
            get
            {
                IPStatus answ = IPStatus.Unknown;
                IPAddress address;
                PingReply reply;
                Ping pingSender = new Ping();
                address = IPAddress.Loopback;
                string ipAdrr = MPIP;
                IPAddress.TryParse(ipAdrr, out address);
                try
                {
                    reply = pingSender.Send(address, 500);
                    answ = reply.Status;
                }
                catch (Exception exc)
                {
                    lgError($"testPingServer EXCEPTION in fase di ping{Environment.NewLine}{exc}");
                }
                return answ;
            }
        }

        #endregion Private Properties

        #region Protected Properties

        /// <summary>
        /// IP del PC
        /// </summary>
        protected static string currIP
        {
            get
            {
                string answ = "127.0.0.1";

                return answ;
            }
        }

        /// <summary>
        /// URL per recuperare i file dell'IOB su CLOUD (SENZA IOB)
        /// </summary>
        protected static string urlDownloadFileCloud
        {
            get
            {
                return @"http://seriate.steamware.net:8083/MP/IO/IOB/getFiles/";
            }
        }

        /// <summary>
        /// URL per salvare i file dell'IOB su CLOUD (SENZA IOB)
        /// </summary>
        protected static string urlUploadFileCloud
        {
            get
            {
                return @"http://seriate.steamware.net:8083/MP/IO/IOB/uploadFile/";
            }
        }

        /// <summary>
        /// URL stringa di UPDATE...
        /// </summary>
        protected string updateUrl
        {
            get
            {
                return string.Format("http://seriate.steamware.net:8083/SWS/MAPO/IOB-WIN/{0}/manifest.xml", branchName);
            }
        }

        /// <summary>
        /// URL per recuperare i file dell'IOB (SENZA IOB)
        /// </summary>
        protected string urlDownloadFile
        {
            get
            {
                string answ = "";
                try
                {
                    answ = string.Format(@"http://{0}{1}/IOB/getFiles/", MPIP, MPURL);
                }
                catch
                { }
                return answ;
            }
        }

        /// <summary>
        /// URL per chiedere quale sia la IOB da acquisire/gestire (se c'è...)
        /// </summary>
        protected string urlIob2call
        {
            get
            {
                string answ = "";
                try
                {
                    answ = string.Format(@"http://{0}{1}{2}{3}", MPIP, MPURL, CMDIOB2CALL, utils.GetIP());
                }
                catch
                { }
                return answ;
            }
        }

        /// <summary>
        /// URL per segnalazione reboot...
        /// </summary>
        protected string urlReboot
        {
            get
            {
                string answ = "";
                try
                {
                    answ = string.Format(@"http://{0}{1}{2}{3}&mac={4}", MPIP, MPURL, CMDREBO, utils.GetIP(), utils.GetMACAddress());
                }
                catch
                {
                    answ = string.Format(@"http://{0}{1}{2}{3}", MPIP, MPURL, CMDREBO, utils.GetIP());
                }
                return answ;
            }
        }

        /// <summary>
        /// URL per salvare i file dell'IOB (SENZA IOB)
        /// </summary>
        protected string urlUploadFile
        {
            get
            {
                string answ = "";
                try
                {
                    answ = string.Format(@"http://{0}{1}/IOB/uploadFile/", MPIP, MPURL);
                }
                catch
                { }
                return answ;
            }
        }

        #endregion Protected Properties

        #region Public Properties

        /// <summary>
        /// Visualizzazione stato di comunicazione attiva con PLC
        /// </summary>
        public bool commPlcActive
        {
            set
            {
                // se true --> comunica/verde, altrimenti grigio
                lblApp.ForeColor = value ? Color.SeaGreen : Color.Black;
                lblVers.ForeColor = value ? Color.SeaGreen : Color.DarkSlateGray;
                statusStrip1.Refresh();
            }
        }

        /// <summary>
        /// Verifica il server: esiste IP, risponde a ping, risponde a pagina ALIVE
        /// </summary>
        public bool testServer
        {
            get
            {
                bool answ = false;
                if (!string.IsNullOrEmpty(MPIP))
                {
                    if (utils.dtVetoPing < DateTime.Now)
                    {
                        IPStatus pingStatus = testPingServer;
                        // se passa il ping faccio il resto...
                        if (pingStatus == IPStatus.Success)
                        {
                            try
                            {
                                // chiamo URL, se restituisce "OK" è alive!
                                string callResp = utils.callUrl(urlAlive);
                                answ = (callResp == "OK");
                            }
                            catch (Exception exc)
                            {
                                lgError($"Errore in checkServerAlive:{Environment.NewLine}{exc}");
                            }
                            // verifico SE è variato stato online/offline...
                            if (utils.MPIO_Online != answ)
                            {
                                // se ORA sono online riporto...
                                if (answ)
                                {
                                    lgInfo("SERVER ONLINE");
                                    utils.dtVetoPing = DateTime.Now.AddMilliseconds(baseUtils.nextPauseSendMSec);
                                }
                                else
                                {
                                    lgInfo("SERVER OFFLINE in MainForm:testServer");
                                }
                                // salvo nuovo status...
                                utils.MPIO_Online = answ;
                            }
                            else
                            {
                                // allungo periodo controllo...
                                utils.dtVetoPing = DateTime.Now.AddMilliseconds(baseUtils.nextPauseSendMSec * 3);
                            }
                        }
                        else
                        {
                            lgInfo($"SERVER NOT RESPONDING (PING at {MPIP})");
                            utils.MPIO_Online = false;
                            updateComStats(0, 0, false);
                            // imposto veto a 10 volte reinvio dati standard...
                            utils.dtVetoPing = DateTime.Now.AddMilliseconds(baseUtils.nextPauseSendMSec * 10);
                            utils.dtVetoSend = utils.dtVetoPing;
                        }
                    }
                    else
                    {
                        // altrimenti passo ultimo valore noto...
                        answ = utils.MPIO_Online;
                    }
                }
                return answ;
            }
        }

        /// <summary>
        /// URL per check alive...
        /// </summary>
        public string urlAlive
        {
            get
            {
                return string.Format(@"http://{0}{1}/IOB", MPIP, MPURL);
            }
        }

        #endregion Public Properties

        #region Private Methods

        private void arrangeWindowsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            // ferma tutti i child form...
            foreach (var ChildForm in this.MdiChildren)
            {
                try
                {
                    //ChildForm.Show();
                    ChildForm.WindowState = FormWindowState.Normal;
                }
                catch
                { }
            }
            this.LayoutMdi(MdiLayout.TileHorizontal);
        }

        private void AutoUpdater_ApplicationExitEvent()
        {
            displayTaskAndLog("Chiusura Adapters");
            Thread.Sleep(100);
            // chiudo tutto
            closeAllChild();
            displayTaskAndLog("Chiusura Applicazione");
            // attendo 1 sec...
            Thread.Sleep(1000);
            // ESCO!
            Application.Exit();
        }

        /// <summary>
        /// Effettua verifiche varie comunicazione verso PLC e verso server
        /// </summary>
        private void checkCom()
        {
            // eseguo update se è passato almeno comCheckTOut secondi da ultimo check...
            if (DateTime.Now.Subtract(lastComCheck).TotalSeconds > utils.CRI("comCheckTOut"))
            {
                lastComCheck = DateTime.Now;
                // conta quanti child form di adapter verso PLC siano aperti !!!FARE!!! chiedere con un metodo che siano ATTIVI e contare quello...
                int numPLC = this.MdiChildren.Length;
                int numAttivi = 0;
                foreach (var item in this.MdiChildren)
                {
                    try
                    {
                        var currForm = (AdapterForm)item;
                        numAttivi += currForm.iobObj.IobOnline ? 1 : 0;
                    }
                    catch
                    { }
                }

                // update stato!
                updateComStats(numPLC, numAttivi, testServer);
            }
        }

        /// <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;
            }
            // SOLO SE se sono in modo STD
            if (ModoAvvio == StartMode.STD)
            {
                // controllo cosa devo mostrare...
                if (WindowState == FormWindowState.Minimized)
                {
                    notifyIcon1.Visible = false;
                    sendToTray();
                }
                else
                {
                    notifyIcon1.Visible = false;
                }
            }
            else
            {
                notifyIcon1.Visible = false;
            }
            // fix child!
            this.LayoutMdi(MdiLayout.TileHorizontal);
        }

        /// <summary>
        /// FIx finestre restanti post chiusura di una finestra...
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Child_FormClosed(object sender, FormClosedEventArgs e)
        {
            this.LayoutMdi(MdiLayout.TileHorizontal);
        }

        /// <summary>
        /// Sistemazione finestre POST visualizzazione...
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Child_Shown(object sender, EventArgs e)
        {
            this.LayoutMdi(MdiLayout.TileHorizontal);
        }

        private void closeALLAdaptersToolStripMenuItem_Click(object sender, EventArgs e)
        {
            // chiudo tutte
            closeAllChild();
        }

        /// <summary>
        /// Chiusura applicazione
        /// </summary>
        private void closeAllChild()
        {
            // ferma tutti i child form...
            foreach (var ChildForm in this.MdiChildren)
            {
                try
                {
                    ChildForm.Close();
                }
                catch
                { }
            }
        }

        /// <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 IOB-WIN");
            }
            // se è permesso tray close...
            if (utils.CRB("trayClose"))
            {
                trayMenu.Items.Add("Close IOB-WIN");
            }
        }

        private void doConfDownload()
        {
            // ciclo su IOB configurati
            foreach (var currIob in IOB2START)
            {
                fileEmbed objFiles = new fileEmbed();
                string rawData = "";
                string url2call = "";
                if (utils.CRB("ConfToCloud"))
                {
                    // invio su cloud...
                    url2call = $"{urlDownloadFileCloud}{currIob}";
                }
                else
                {
                    // invio in locale!
                    url2call = $"{urlDownloadFile}{currIob}";
                }
                rawData = utils.callUrlNow(url2call);
                if (!string.IsNullOrEmpty(rawData))
                {
                    // deserializzo
                    objFiles = JsonConvert.DeserializeObject<fileEmbed>(rawData);
                    if (objFiles != null)
                    {
                        // salvo!
                        foreach (var item in objFiles.fileList)
                        {
                            fileMover.obj.salvaFileString(utils.confDir, item.fileName, item.content);
                        }
                        displayTaskAndLog("Download conf files aggiornati");
                    }
                    else
                    {
                        displayTaskAndLog($"Error: invalid file data received, deserialized to null ({rawData})");
                    }
                }
                else
                {
                    displayTaskAndLog("Error: no file data downloaded");
                }
            }
        }

        private void downloadIOBConfToolStripMenuItem_Click(object sender, EventArgs e)
        {
            try
            {
                displayTaskAndLog("Attesa chiusura Adapters");
                Thread.Sleep(100);
                // fermo gli IOB
                closeAllChild();
                Thread.Sleep(100);
                // download da su server di TUTTI i file CONF delle IOB
                doConfDownload();
                // riavvio gli IOB
                Thread.Sleep(100);
                startAdapters();
            }
            catch (Exception exc)
            {
                lgError($"Eccezzione in download IOB conf files{Environment.NewLine}{exc}");
            }
        }

        private void getIOBAssignmentsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            // !!!FARE!!!
            // fa un check su server di quali IOB siano assegnate al PC (e modifica il file MAIN di avvio ripartendo...)
        }

        /// <summary>
        /// Carica file ini della configurazione richiesta
        /// </summary>
        /// <param name="iniConfFile"></param>
        private void loadIniFile(string iniConfFile)
        {
            displayTaskAndLog($"[STARTUP] Loading iniConfFile: {iniConfFile}");

            IniFile fIni = new IniFile(iniConfFile);
            // salvo valori letti da INI file...
            branchName = fIni.ReadString("BRANCH", "NAME", "master");
            MPIP = fIni.ReadString("SERVER", "MPIP", "ND");
            MPURL = fIni.ReadString("SERVER", "MPURL", "/MP/IO");
            CMDALIVE = fIni.ReadString("SERVER", "CMDALIVE", "/IOB");
            CMDREBO = fIni.ReadString("SERVER", "CMDREBO", "/IOB/sendRebootGateway?GWIP=");
            CMDIOB2CALL = fIni.ReadString("SERVER", "CMDIOB2CALL", "/IOB/getIob2call?GWIP=");
            MAXCNC = fIni.ReadInteger("IOB", "MAXCNC", 1);
            string STARTLIST = fIni.ReadString("IOB", "STARTLIST", "");
            // Gestione IOB da avviare
            IOB2START = new List<string>();
            // SE se sono in modo UPD --> nessuno
            if (ModoAvvio == StartMode.UPD)
            {
                IOB2START.Add("NONE");
            }
            else
            {
                string[] elenco = null;
                // se modalità MAN CERCO se sostituire STARTLIST
                if (ModoAvvio == StartMode.MAN)
                {
                    if (!string.IsNullOrEmpty(startParams["IOB"]))
                    {
                        STARTLIST = startParams["IOB"];
                    }
                }
                // se ho qualcosa...
                if (!string.IsNullOrEmpty(STARTLIST))
                {
                    elenco = STARTLIST.Split(',');
                    // inserisco da elenco!
                    foreach (var item in elenco)
                    {
                        IOB2START.Add(item);
                    }
                }
                else
                {
                    IOB2START.Add("NONE");
                }
            }

            // init redis...
            string firstIob = "00";
            if (IOB2START.Count > 0)
            {
                firstIob = IOB2START[0];
            }
            redisMan = new RedisIobCache(MPIP, firstIob);
        }

        /// <summary>
        /// evento chiusura
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            closeAllChild();
        }

        /// <summary>
        /// evento resize
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void MainForm_Resize(object sender, EventArgs e)
        {
            checkFormVisibility();
        }

        /// <summary>
        /// evento visualizzazione
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void MainForm_Shown(object sender, EventArgs e)
        {
            // SOLO SE se sono in modo STD
            if (ModoAvvio == StartMode.STD)
            {
                // avvio minimizzato se richiesto
                if (utils.CRB("startMinimized"))
                {
                    // controllo e mando a tray...
                    sendToTray();
                }
            }
            displayTaskAndLog("Main Form SHOWN (MDI)");
        }

        /// <summary>
        /// timer principale
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void MainTimer_Tick(object sender, EventArgs e)
        {
            // inizio a riportare che sto funzionando..
            advProgBar();
            checkCom();
        }

        /// <summary>
        /// Richeista verifica update
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void mCheckUpdates_Click(object sender, EventArgs e)
        {
            lg.Info(string.Format("Avvio procedura controllo update:{0}branch: {1} | url: {2}", Environment.NewLine, branchName, updateUrl));
            // avvio controllo
            AutoUpdater.ShowSkipButton = false;
            AutoUpdater.ShowRemindLaterButton = false;
            AutoUpdater.RunUpdateAsAdmin = utils.CRB("AUpdAsAdm");
            AutoUpdater.ReportErrors = false;
            AutoUpdater.DownloadPath = @"C:\Steamware\src\";
            AutoUpdater.ApplicationExitEvent += AutoUpdater_ApplicationExitEvent;
            AutoUpdater.Start(updateUrl);
        }

        private void minimizeALLToolStripMenuItem_Click(object sender, EventArgs e)
        {
            // ferma tutti i child form...
            foreach (var ChildForm in this.MdiChildren)
            {
                try
                {
                    ChildForm.WindowState = FormWindowState.Minimized;
                }
                catch
                { }
            }
        }

        private void MShowMainLog_Click(object sender, EventArgs e)
        {
            try
            {
                string logPath = $"{System.AppDomain.CurrentDomain.BaseDirectory}logs\\MAIN\\{DateTime.Today:yyyy-MM-dd}.log";
                Process.Start(logPath);
            }
            catch (Exception exc)
            {
                lgError($"Eccezione in show log (MAIN):{Environment.NewLine}{exc}");
            }
        }

        /// <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;
            }
        }

        private void restartALLAdaptersToolStripMenuItem_Click(object sender, EventArgs e)
        {
            // chiudo
            closeAllChild();
            Thread.Sleep(1000);
            // riapro
            startAdapters();
        }

        private void sendIOBAssignmentsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            // !!!FARE!!!
            // salva su server quali IOB siano gestite dal PC (da conf su MAIN...)
        }

        /// <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();
        }

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

        /// <summary>
        /// Avvio gli adapters richeisti
        /// </summary>
        private void startAdapters()
        {
            // avvio child richiesti
            foreach (var item in IOB2START)
            {
                openChild(item);
            }
            // effettuo upload dei file di configurazione...
            uploadIobConfFile();
        }

        /// <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 child adapters...
                closeAllChild();
                // chiudo!
                Close();
            }
            else if (e.ClickedItem.Text.StartsWith("Show"))
            {
                if (utils.CRB("windowCanMax"))
                {
                    Show();
                    WindowState = FormWindowState.Normal;
                }
            }
        }

        /// <summary>
        /// Effettua upload dei file di configurazione IOB
        /// </summary>
        private void uploadIobConfFile()
        {
            // upload su server i file CONF delle IOB attive...
            string answ = "";
            smallFile currFile = null;
            string fileContent = "";
            // ciclo su IOB configurati
            foreach (var currIob in IOB2START)
            {
                fileEmbed objFiles = new fileEmbed();
                try
                {
                    fileMover.obj.setDirectory(utils.confDir);
                    var fileList = fileMover.obj.elencoFiles_FI(currIob + ".*");

                    foreach (var item in fileList)
                    {
                        fileContent = System.IO.File.ReadAllText($"{item.FullName}");
                        currFile = new smallFile()
                        {
                            fileName = item.Name,
                            content = fileContent.Replace("\r\n", Environment.NewLine)
                        };
                        objFiles.fileList.Add(currFile);
                    }
                    // serializzo
                    string rawData = JsonConvert.SerializeObject(objFiles);
                    if (utils.CRB("ConfToCloud"))
                    {
                        // invio su cloud...
                        answ = utils.callUrl($"{urlUploadFileCloud}{currIob}", rawData);
                    }
                    else
                    {
                        // invio in locale!
                        answ = utils.callUrl($"{urlUploadFile}{currIob}", rawData);
                    }
                }
                catch (Exception exc)
                {
                    lgError($"Eccezzione in upload IOB conf files{Environment.NewLine}{exc}");
                }
            }
        }

        private void uploadIOBConfToolStripMenuItem_Click(object sender, EventArgs e)
        {
            uploadIobConfFile();
        }

        #endregion Private Methods

        #region Protected Methods

        /// <summary>
        /// Effettua logging ERROR corretto impostanto anche la variabile IOB prima di scrivere...
        /// </summary>
        /// <param name="txt2log"></param>
        protected static void lgError(string txt2log)
        {
            lg.Factory.Configuration.Variables["codIOB"] = "MAIN";
            lg.Error(txt2log);
        }

        /// <summary>
        /// Effettua logging INFO corretto impostando anche la variabile IOB prima di scrivere...
        /// </summary>
        /// <param name="txt2log"></param>
        protected static void lgInfo(string txt2log)
        {
            lg.Factory.Configuration.Variables["codIOB"] = "MAIN";
            lg.Info(txt2log);
        }

        /// <summary>
        /// CHiude le finestre child attive
        /// </summary>
        protected void closeActiveChild()
        {
            if (this.HasChildren)
            {
                try
                {
                    this.ActiveMdiChild.Close();
                    this.LayoutMdi(MdiLayout.TileHorizontal);
                }
                catch
                { }
            }
        }

        protected void myInit()
        {
            DateTime adesso = DateTime.Now;
            resetProgBar = 0;
            formStartTime = adesso;
            lastComCheck = adesso.AddHours(-1);
            lblStatus.Text = "Loading";

            // fix icon!
            notifyIcon1.Text = string.Format("IOB-WIN | {0}", System.Reflection.Assembly.GetExecutingAssembly().GetName().Version);
            Icon = Icon.ExtractAssociatedIcon(utils.defIconFilePath);
            notifyIcon1.Icon = Icon.ExtractAssociatedIcon(utils.defIconFilePath);

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

            LogManager.ReconfigExistingLoggers();

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

            // salvo versione SW!
            lgInfo("------ STARTUP DATA ------");
            lgInfo($"App Mode : {nomeApp}");
            lgInfo($"Versione : {versione}");
            lgInfo("--------------------------");

            // se abilitato autoload conf leggo file corretto...
            if (utils.CRB("autoLoadConf"))
            {
                try
                {
                    loadIniFile(utils.mainConfFilePath);
                    lgInfo("INI LOADED");
                    // avvio child come richiesto!
                    startAdapters();
                }
                catch (Exception exc)
                {
                    displayTaskAndLog(string.Format("Eccezione in myInit: {0}", exc));
                }
            }
            else
            {
                displayTaskAndLog("Waiting for config file selection");
            }

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

            // avvio minimizzato se richiesto
            if (utils.CRB("startMinimized"))
            {
                // imposto minimized se necessario!
                if (WindowState != FormWindowState.Minimized)
                {
                    WindowState = FormWindowState.Minimized;
                }
                displayTaskAndLog("Minimized");
            }
            try
            {
                IPStatus pingStatus = testPingServer;
                // se passa il ping faccio il resto...
                if (pingStatus == IPStatus.Success)
                {
                    // segnalo reboot (programma)...
                    utils.callUrl(urlReboot);
                }
                else
                {
                    displayTaskAndLog("Server unreachable, cannot send urlReboot for MAIN FORM");
                }
            }
            catch (Exception exc)
            {
                lgError(string.Format("MainForm myInit EXCEPTION in fase di chiamata URL di reboot:{0}{1}{2}", urlReboot, Environment.NewLine, exc));
            }
            displayTaskAndLog("Main Form OK");
        }

        /// <summary>
        /// Apre la finestra child con conf
        /// </summary>
        protected void openChild(string IOB)
        {
            if (IOB == null)
            {
                throw new ArgumentNullException(nameof(IOB));
            }

            AdapterForm child = new AdapterForm(IOB);
            child.MdiParent = this;
            child.Text = IOB;
            child.Show();
            child.Shown += Child_Shown;
            child.FormClosed += Child_FormClosed;
        }

        /// <summary>
        /// effettua salvataggio argomenti
        /// </summary>
        /// <param name="args"></param>
        protected void saveArgs(string[] args)
        {
            if (args != null)
            {
                // salvo args di avvio (sono parametri tipo param1=val1 param2=test1,test2,test3
                myArgs = args;
                if (myArgs.Length > 0)
                {
                    // salvo dictionary!
                    foreach (var item in myArgs)
                    {
                        var kvp = item.Split('=');
                        startParams.Add(kvp[0], kvp[1]);
                    }
                }
                // verifico gli args...
                if (startParams.ContainsKey("MODE"))
                {
                    try
                    {
                        ModoAvvio = (StartMode)Enum.Parse(typeof(StartMode), startParams["MODE"]);
                    }
                    catch
                    { }
                }
            }
        }

        #endregion Protected Methods

        #region Public Methods

        /// <summary>
        /// Avanza la barra di stato...
        /// </summary>
        public void advProgBar()
        {
            try
            {
                // aggiorno runtime...
                TimeSpan uptime = DateTime.Now.Subtract(formStartTime);
                tslRunTime.Text = string.Format("Running: {0}gg {1:00}:{2:00}:{3:00}", uptime.Days, uptime.Hours, uptime.Minutes, uptime.Seconds);
                if (MainProgrBar.Style != ProgressBarStyle.Marquee)
                {
                    // se è arrivato a MAX resetto...
                    MainProgrBar.PerformStep();
                    // verifico SE deve resettare progress bar
                    if (resetProgBar > 10)
                    {
                        MainProgrBar.Value = 0;
                        resetProgBar = 0;
                    }
                    // se arrivoa  max imposto richiesta reset...
                    if (MainProgrBar.Value == MainProgrBar.Maximum)
                    {
                        resetProgBar++;
                    }
                    // invalido x ridisegnare...
                    MainProgrBar.Invalidate();
                }
            }
            catch (Exception exc)
            {
                lgError($"Eccezione in advProgBar:{Environment.NewLine}{exc}");
            }
        }

        /// <summary>
        /// mostra un testo sulla status bar + LOG
        /// </summary>
        /// <param name="txt2show"></param>
        public void displayTaskAndLog(string txt2show)
        {
            lblStatus.Text = txt2show;
            lblStatus.Invalidate();
            lgInfo(txt2show);
        }

        /// <summary>
        /// Mostra update delle statistiche di comunicazione (num plc connessi, indirizzo server) con colore ad indicare anomalie...
        /// </summary>
        /// <param name="numPLC"></param>
        /// <param name="numAttivi"></param>
        /// <param name="serverOk"></param>
        public void updateComStats(int numPLC, int numAttivi, bool serverOk)
        {
            // testo
            lblComStats.Text = $"{numAttivi}/{numPLC} PLC --> {MPIP} (MP/IO)";
            // colore secondo valori... server !="ND" è ok, PLC > 0 è OK
            int score = 0;
            if (serverOk)
            {
                score++;
            }

            if (numPLC > 0 && numAttivi == numPLC)
            {
                score++;
            }

            switch (score)
            {
                case 0:
                    lblComStats.ForeColor = Color.Red;
                    break;

                case 1:
                    lblComStats.ForeColor = Color.Orange;
                    break;

                case 2:
                    lblComStats.ForeColor = Color.Green;
                    break;

                default:
                    lblComStats.ForeColor = Color.Gray;
                    break;
            }
        }

        #endregion Public Methods
    }
}