using Maser.Feanor.Biz;
using Maser.Feanor.Model;
using System;
using System.Collections.Generic;
using System.Net;
using System.Windows.Forms;
using System.IO;
using System.Text;



namespace Maser.Feanor.Client
{
    public partial class FeanorClient : Form
    {
        private List<ClientWorker> _ClientWorkers = new List<ClientWorker>();

#warning Form laten zien in het midden van het scherm always on top als er iets fout gaat!

        public FeanorClient()
        {
            InitializeComponent();

            System.Reflection.Assembly ass = System.Reflection.Assembly.GetEntryAssembly(); // report build version 
            string exe = System.IO.Path.GetFullPath(ass.Location);
            DateTime dt = new System.IO.FileInfo(exe).LastWriteTimeUtc;
            this.Text = String.Format("Feanor - Clients" + "   v{0:0000}{1:00}{2:00}", dt.Year, dt.Month, dt.Day);
        }

        private Server.Server _Server;
        public Server.Server Server { get { return _Server; } }

        public DateTime LastHTTP { get { return _LastHTTP; } }
        private DateTime _LastHTTP;

        private DateTime _LastDBWrite; // Used for detecting idling of server


        public ChamberStatus Status { get { return _status; } }
        private ChamberStatus _status;

        private Chamber _Chamber;
        public Chamber Chamber { get { return _Chamber; } }

        private void FeanorClient_Load(object sender, EventArgs e)
        {
            StartWorkers();           
        }

        private void StartWorkers()
        {
            Console.WriteLine("Checking if DB is online...");
            lblStatus.Text = "Connecting to database...";
            if (!SQLMethods.DatabaseOnline(60))
            {
                lblStatus.Text = "Could not connect to database...";
                Console.WriteLine("Database OFFLINE");
                return;
            }
            else
            {
                Console.WriteLine("Database online");
            }

            // Construct ClientWorkers from all active Chambers
            _ClientWorkers = new List<ClientWorker>();
            foreach (Chamber c in new Chambers().GetAllActive())
                _ClientWorkers.Add(new ClientWorker(c));

            // Initiate gv
            Initialize_dgvChambers(_ClientWorkers.Count); 

            // Start workers
            foreach (ClientWorker cw in _ClientWorkers)
                cw.Start();

            timer.Start();
            LastStartupTimer.Start();           
        }

        private void Initialize_dgvChambers(int rows)
        {
            // Initiate in dgv
            // dgvChambers.DefaultCellStyle.SelectionBackColor = dgvChambers.DefaultCellStyle.BackColor;
            // dgvChambers.DefaultCellStyle.SelectionForeColor = dgvChambers.DefaultCellStyle.ForeColor;
            foreach (DataGridViewColumn column in dgvChambers.Columns)
            {
                column.SortMode = DataGridViewColumnSortMode.NotSortable;                           
                column.DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleCenter;
                column.HeaderCell.Style.Alignment = DataGridViewContentAlignment.MiddleCenter;
            }
            while (dgvChambers.Rows.Count > 0)
                dgvChambers.Rows.RemoveAt(0);
            dgvChambers.Rows.Add(rows);
            foreach (DataGridViewRow row in dgvChambers.Rows)
            {
                //
            }            
            //LastStartupTimer_Tick(null, null);      // Obtain last startup of RPI
            //CheckDBstatus();                      // Check if SQL DB is online
            UpdateRaspberryTime_Tick(null, null);   // Set internal time of RPI
        }


        private void timer_Tick(object sender, EventArgs e)
        {
            lblStatus.Text = Time.Local.ToString() + " (UTC+1)"; // was lblStatus.Text = Time.UTC.ToString() +" (UTC)";


        // Show ClientWorker that aren't running properly if cboxShowAll not checked
        List<ClientWorker> workers;
            workers = cboxShowAll.Checked ? _ClientWorkers : _ClientWorkers.FindAll(delegate (ClientWorker w) { return (w.Status != ChamberStatus.Running); });

            if (workers.Count == 0)
            {
                dgvChambers.Visible = false;
                return;
            }

            dgvChambers.Visible = true;

            if (dgvChambers.Rows.Count != workers.Count)
            {
                while (dgvChambers.Rows.Count > 0)
                    dgvChambers.Rows.RemoveAt(0);
                dgvChambers.Rows.Add(workers.Count);
            }

            int ConnTotal = workers.Count;  // total amount of chambers            

            int ConnCounter = 0;            // amount of chambers which are 'running' 
            int OfflineCounter = 0;

            for (int i = 0; i < workers.Count; i++)
            {
                ClientWorker cw = workers[i];
                dgvChambers[0, i].Value = String.Format("{0:00000}", cw.Chamber.MIDS);  // MIDS ID of node
                dgvChambers[1, i].Value = cw.Chamber.Network;                           // IP of node              
                dgvChambers[2, i].Value = cw.Status.ToText();                           // Communication status with node
                
                if (cw.Status.ToText() == "Running")  ConnCounter++;
               // Console.WriteLine(cw.Status.ToText().ToString());
                if (cw.Status.ToText() == "No connection") OfflineCounter++;

                if (cw.LastHTTP < new DateTime(2000, 1, 1))
                    dgvChambers[3, i].Value = "-";
                else
                    dgvChambers[3, i].Value = cw.LastHTTP.ToString();
            }

            try
            {
                if (OfflineCounter > 1 ) // show panel stating that more than 2 nodes are offline!
                {
                    pnlNodesOffline.Visible = true;                    
                }
                if (OfflineCounter <= 1) // show panel stating that more than 2 nodes are offline!
                {
                    pnlNodesOffline.Visible = false;
                }
            }
            catch { }
            
                    
            double ConnPercentageDouble = ((double)ConnCounter / (double)ConnTotal) * 100.0;      // percentage 'running'  nodes (double)      
            int ConnPercentageInt = (int)ConnPercentageDouble;                                    // percentage 'running'  nodes (int)

            PercProgress.Maximum = 100;
            PercProgress.Step = 1;
            PercProgress.Value = ConnPercentageInt;

            statusPercentage.Text = ConnPercentageInt.ToString() + "%";
        }


        private void FeanorClient_FormClosing(object sender, FormClosingEventArgs e)
        {
            // Stop workers
            foreach (ClientWorker cw in _ClientWorkers)
                cw.Stop();
        }

        private void cboxShowAll_CheckedChanged(object sender, EventArgs e)
        {
            timer_Tick(null, null);            
        }
               

        private void LastStartupTimer_Tick(object sender, EventArgs e)
        {           
            List<ClientWorker> workers;
            workers = cboxShowAll.Checked ? _ClientWorkers : _ClientWorkers.FindAll(delegate (ClientWorker w) { return (w.Status != ChamberStatus.Running); });
            
            for (int i = 0; i < workers.Count; i++)
            {
                ClientWorker cw = workers[i];
               
                string url;
                string data;
                url = "http://" + cw.Chamber.Network + ":8080/" + "startuptime";
                DateTime lastStartup;
                try
                {
                    using (WebClient client = new WebClient())
                    {                        
                        data = client.DownloadString(url);
                        lastStartup = Time.UnixToDatetime(int.Parse(data));
                        //Console.WriteLine(lastStartup.ToLocalTime());
                        dgvChambers[4, i].Value = lastStartup.ToLocalTime().ToString();
                    }
                }
                catch
                {
                    // Continue with next object, ignoring exception
                }
                
            }
            
        }                

        private void UpdateRaspberryTime_Tick(object sender, EventArgs e)
        {
            List<ClientWorker> workers;
            workers = cboxShowAll.Checked ? _ClientWorkers : _ClientWorkers.FindAll(delegate (ClientWorker w) { return (w.Status != ChamberStatus.Running); });

            for (int i = 0; i < workers.Count; i++) // for all chambers
            {
                ClientWorker cw = workers[i];                
               
                // Construct unix timestamp string
                string http = "<time>,";
                Int32 unixTimestamp = (Int32)(DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1))).TotalSeconds;
                http += unixTimestamp.ToString();
                http += ",</time>";

                // Send unix timestamp string to RPI
                try
                {
                    using (WebClient client = new WebClient())
                    {                       
                        string URL = "http://" + cw.Chamber.Network + ":8080/";
                        string url = client.UploadString(URL, http);                        
                    }
                }
                catch
                {

                }
            }
        }

        private void lblStatus_Click(object sender, EventArgs e)
        {

        }

        private void PercProgress_Click(object sender, EventArgs e)
        {

        }

        private void panel1_Paint(object sender, PaintEventArgs e)
        {

        }

        private void label1_Click(object sender, EventArgs e)
        {

        }

        private void btnDismiss_Click(object sender, EventArgs e)
        {
            pnlNodesOffline.Visible = false;
        }

        private void timerSaveStatusPage_Tick(object sender, EventArgs e)
        {
            List<ClientWorker> workers;
            workers = cboxShowAll.Checked ? _ClientWorkers : _ClientWorkers.FindAll(delegate (ClientWorker w) { return (w.Status != ChamberStatus.Running); });

            for (int i = 0; i < workers.Count; i++)
            {
                ClientWorker cw = workers[i];

                string url;
                string data;
                url = "http://" + cw.Chamber.Network + ":8080/" + "status";
               
                try
                {
                    using (WebClient client = new WebClient())
                    {
                        data = client.DownloadString(url);
                        
                        string fileName = $"Node_{cw.Chamber.MIDS}_status.html";
                       
                        string outputDirectory = "\\\\silicium\\projects\\2020\\P201339\\sub1\\4. Software\\8. Nodestatus";
                        Directory.CreateDirectory(outputDirectory); 
                       
                        string filePath = Path.Combine(outputDirectory, fileName);                       
                        File.WriteAllText(filePath, data);
                    }
                }
                catch
                {
                    // Continue with next object, ignoring exception
                }

            }
        }
    }
}
