using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
using Maser.Feanor.Model;
using Maser.Feanor.Biz;
using Maser.Feanor.MIDSInterface;
using System.IO;
using MySqlConnector;

using System.Data.SqlClient;

using OxyPlot;
using OxyPlot.Series;
using OxyPlot.WindowsForms;
using OxyPlot.Legends;
using System.Text.RegularExpressions;
using System.Xml.Linq;
using OxyPlot.Annotations;

using System;
using System.Net.Http;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Net.Http;
using System.Threading.Tasks; // Nodig voor async/await



/*
 *  Transparant --> geen test in kast
 *  Groen --> test in kast, alles OK
 *  EUrofins-donker-oranje --> test in kast, iets niet OK 
 *  Eurofins-licht-oranje --> Kast heeft general data error! 
 *  Paars --> Kast heeft geen status!? (dit is niet te bedoeling)
 */





namespace HalCheck
{
    public partial class HalControle : Form
    {
        private PlotModel plotModel;
        private PlotView plotView;
        private Dictionary<int, List<SensorReading>> sensorValues;
        private Dictionary<object, int> sensorAttempts = new Dictionary<object, int>();

        // save location for dgvProjects information xml file
        string filePath = @"Z:\projects\2025\P250082\sub1\dgvProjects.xml";

        bool isLoadingData = true; // Vlag om aan te geven of data wordt geladen

        bool lbSensorChanged = false;

        bool humidityLOW = false;

        List<CabinetStatus> cabinets = new List<CabinetStatus>{ // links/recht , hoogte     Color.Purple/Orange/Red
        new CabinetStatus { Name = "1120", Position = new Point(430, 470), StatusColor = Color.Purple },
         new CabinetStatus { Name = "3094", Position = new Point(520, 470), StatusColor = Color.Purple },
        new CabinetStatus { Name = "1865", Position = new Point(620,470), StatusColor = Color.Purple },
        new CabinetStatus { Name = "2750", Position = new Point(250, 470), StatusColor = Color.Purple },
        new CabinetStatus { Name = "3097", Position = new Point(160, 470), StatusColor = Color.Purple },
        new CabinetStatus { Name = "986", Position = new Point(340, 470), StatusColor = Color.Purple },

        new CabinetStatus { Name = "1593", Position = new Point(260, 330), StatusColor = Color.Purple },
        new CabinetStatus { Name = "1586", Position = new Point(260, 380), StatusColor = Color.Purple },
        new CabinetStatus { Name = "2249", Position = new Point(340, 330), StatusColor = Color.Purple },
        new CabinetStatus { Name = "2250", Position = new Point(340, 380), StatusColor = Color.Purple },
        new CabinetStatus { Name = "2798", Position = new Point(415, 330), StatusColor = Color.Purple },
        new CabinetStatus { Name = "2799", Position = new Point(415, 380), StatusColor = Color.Purple },
        new CabinetStatus { Name = "2443", Position = new Point(490, 370), StatusColor = Color.Purple },
        new CabinetStatus { Name = "77", Position = new Point(560, 370), StatusColor = Color.Purple },
        new CabinetStatus { Name = "526", Position = new Point(630, 370), StatusColor = Color.Purple },

        new CabinetStatus { Name = "18", Position = new Point(710, 260), StatusColor = Color.Purple },

        new CabinetStatus { Name = "2318", Position = new Point(220, 630), StatusColor = Color.Purple },
        new CabinetStatus { Name = "2319", Position = new Point(285, 630), StatusColor = Color.Purple },
        new CabinetStatus { Name = "2599", Position = new Point(345, 630), StatusColor = Color.Purple },
        new CabinetStatus { Name = "3096", Position = new Point(430, 630), StatusColor = Color.Purple },
        new CabinetStatus { Name = "3095", Position = new Point(530, 630), StatusColor = Color.Purple },
        new CabinetStatus { Name = "1056", Position = new Point(620, 630), StatusColor = Color.Purple },

        new CabinetStatus { Name = "3098", Position = new Point(530, 700), StatusColor = Color.Purple },
        new CabinetStatus { Name = "3140", Position = new Point(430, 700), StatusColor = Color.Purple },

        new CabinetStatus { Name = "38", Position = new Point(830, 300), StatusColor = Color.Purple },
        new CabinetStatus { Name = "1232", Position = new Point(830, 400), StatusColor = Color.Purple },
        new CabinetStatus { Name = "1233", Position = new Point(830, 500), StatusColor = Color.Purple },

        new CabinetStatus { Name = "1238", Position = new Point(1020, 50), StatusColor = Color.Purple },
        new CabinetStatus { Name = "1728", Position = new Point(1020, 150), StatusColor = Color.Purple },
        new CabinetStatus { Name = "2222", Position = new Point(1020, 260), StatusColor = Color.Purple },
        new CabinetStatus { Name = "2546", Position = new Point(1020, 360), StatusColor = Color.Purple },//
        new CabinetStatus { Name = "2547", Position = new Point(1020, 410), StatusColor = Color.Purple },//
        new CabinetStatus { Name = "3050", Position = new Point(1020,490), StatusColor = Color.Purple },//
        new CabinetStatus { Name = "3051", Position = new Point(1020,540), StatusColor = Color.Purple },//

        new CabinetStatus { Name = "1880", Position = new Point(1120, 80), StatusColor = Color.Purple },
        new CabinetStatus { Name = "987", Position = new Point(1120, 160), StatusColor = Color.Purple },
        new CabinetStatus { Name = "847", Position = new Point(1120, 230), StatusColor = Color.Purple },
        new CabinetStatus { Name = "947", Position = new Point(1120, 310), StatusColor = Color.Purple },
        new CabinetStatus { Name = "680", Position = new Point(1120,380), StatusColor = Color.Purple },
        new CabinetStatus { Name = "1281", Position = new Point(1120, 440), StatusColor = Color.Purple },
        new CabinetStatus { Name = "1282", Position = new Point(1120,500), StatusColor = Color.Purple },

        new CabinetStatus { Name = "1991", Position = new Point(1280, 80), StatusColor = Color.Purple },
        new CabinetStatus { Name = "2183", Position = new Point(1280, 160), StatusColor = Color.Purple },
        new CabinetStatus { Name = "2420", Position = new Point(1280, 250), StatusColor = Color.Purple },
        new CabinetStatus { Name = "3111", Position = new Point(1280, 330), StatusColor = Color.Purple },
        new CabinetStatus { Name = "3112", Position = new Point(1280, 380), StatusColor = Color.Purple },


        new CabinetStatus { Name = "2745", Position = new Point(1380, 250), StatusColor = Color.Purple },
        new CabinetStatus { Name = "2998", Position = new Point(1380, 160), StatusColor = Color.Purple },

        new CabinetStatus { Name = "1999", Position = new Point(1185, 630), StatusColor = Color.Purple },

        new CabinetStatus { Name = "2325", Position = new Point(1215, 710), StatusColor = Color.Purple },
    };

        List<RTHSensor> rthSensors = new List<RTHSensor>
        {
    new RTHSensor { Id = 35, Position = new Point(400, 250) }, // linksboven   IP .191
    new RTHSensor { Id = 8, Position = new Point(1200, 40) }, // compressor IP .166
    new RTHSensor { Id = 31, Position = new Point(1400, 40) }, // rechtsboven IP .187
    new RTHSensor { Id = 9, Position = new Point(940, 635) } // cms2 pc IP .167
        };


        public HalControle()
        {
            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 - Halcontrole" + "   v{0:0000}{1:00}{2:00}", dt.Year, dt.Month, dt.Day);

            obtainActiveProjects();
            obtainActiveChambers();
            LoadDataFromXML();

            tabControl.SelectedTab = tpHal;

            timerProjectDataCheck_Tick(null, null); // Direct de eerste tick uitvoeren
        }


        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new HalControle());
        }

        void obtainActiveChambers()
        {
            try
            {
                List<Chamber> chambers;
                chambers = new Chambers().GetAllActive();

                lbChambers.Items.Clear();

                foreach (Chamber chamber in chambers)
                {
                    lbChambers.Items.Add(chamber.MIDSandDescription); // MD                  
                }

            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "Chambers", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }
        }

        void fixedChambers() // chambers with fixed values, project is not started in CMS --> dummy projects which are invisible (3 LHU chamber + 2 bake ovens)
        {
            int rowIndex1 = dgvProjects.Rows.Add();
            dgvProjects.Rows[rowIndex1].Cells[0].Value = "LHU chamber 2318";
            dgvProjects.Rows[rowIndex1].Cells[3].Value = "02318";
            dgvProjects.Rows[rowIndex1].Cells[6].Value = "30"; // temp
            dgvProjects.Rows[rowIndex1].Cells[7].Value = "60"; // rh
            dgvProjects.Rows[rowIndex1].Cells[8].Value = "Climate"; // chamber type
            dgvProjects.Rows[rowIndex1].Cells[9].Value = true; // check
            dgvProjects.Rows[rowIndex1].DefaultCellStyle.BackColor = Color.LightGray;
            dgvProjects.Rows[rowIndex1].DefaultCellStyle.ForeColor = Color.Black;
            //dgvProjects.Rows[rowIndex1].Visible = false;

            rowIndex1 = dgvProjects.Rows.Add();
            dgvProjects.Rows[rowIndex1].Cells[0].Value = "LHU chamber 2319";
            dgvProjects.Rows[rowIndex1].Cells[3].Value = "02319";
            dgvProjects.Rows[rowIndex1].Cells[6].Value = "30"; // temp
            dgvProjects.Rows[rowIndex1].Cells[7].Value = "60"; // rh
            dgvProjects.Rows[rowIndex1].Cells[8].Value = "Climate"; // chamber type
            dgvProjects.Rows[rowIndex1].Cells[9].Value = true; // check
            dgvProjects.Rows[rowIndex1].DefaultCellStyle.BackColor = Color.LightGray;
            dgvProjects.Rows[rowIndex1].DefaultCellStyle.ForeColor = Color.Black;
            //dgvProjects.Rows[rowIndex1].Visible = false;

            rowIndex1 = dgvProjects.Rows.Add();
            dgvProjects.Rows[rowIndex1].Cells[0].Value = "LHU chamber 2599";
            dgvProjects.Rows[rowIndex1].Cells[3].Value = "02599";
            dgvProjects.Rows[rowIndex1].Cells[6].Value = "30"; // temp
            dgvProjects.Rows[rowIndex1].Cells[7].Value = "60"; // rh
            dgvProjects.Rows[rowIndex1].Cells[8].Value = "Climate"; // chamber type
            dgvProjects.Rows[rowIndex1].Cells[9].Value = true; // check
            dgvProjects.Rows[rowIndex1].DefaultCellStyle.BackColor = Color.LightGray;
            dgvProjects.Rows[rowIndex1].DefaultCellStyle.ForeColor = Color.Black;
            //dgvProjects.Rows[rowIndex1].Visible = false;

            rowIndex1 = dgvProjects.Rows.Add();
            dgvProjects.Rows[rowIndex1].Cells[0].Value = "Oven 1281";
            dgvProjects.Rows[rowIndex1].Cells[3].Value = "01281";
            dgvProjects.Rows[rowIndex1].Cells[6].Value = "125"; // temp
            dgvProjects.Rows[rowIndex1].Cells[7].Value = "N/A"; // rh
            dgvProjects.Rows[rowIndex1].Cells[8].Value = "HTOL"; // chamber type
            dgvProjects.Rows[rowIndex1].Cells[9].Value = true; // check
            dgvProjects.Rows[rowIndex1].DefaultCellStyle.BackColor = Color.LightGray;
            dgvProjects.Rows[rowIndex1].DefaultCellStyle.ForeColor = Color.Black;
            //dgvProjects.Rows[rowIndex1].Visible = false;

            rowIndex1 = dgvProjects.Rows.Add();
            dgvProjects.Rows[rowIndex1].Cells[0].Value = "Oven 1282";
            dgvProjects.Rows[rowIndex1].Cells[3].Value = "01282";
            dgvProjects.Rows[rowIndex1].Cells[6].Value = "150"; // temp
            dgvProjects.Rows[rowIndex1].Cells[7].Value = "N/A"; // rh
            dgvProjects.Rows[rowIndex1].Cells[8].Value = "HTOL"; // chamber type
            dgvProjects.Rows[rowIndex1].Cells[9].Value = true; // check
            dgvProjects.Rows[rowIndex1].DefaultCellStyle.BackColor = Color.LightGray;
            dgvProjects.Rows[rowIndex1].DefaultCellStyle.ForeColor = Color.Black;
            //dgvProjects.Rows[rowIndex1].Visible = false;
        }

        void obtainActiveProjects()
        {
            
            List<Project> projects = new List<Project>();
            try
            {                  
                isLoadingData = true;
                dgvProjects.Rows.Clear();
                List<Project> list;
                list = new Projects().GetAllActive();

                Chambers cBiz = new Chambers();
                String c = "";

                for (int i = 0; i < list.Count; i++)
                {
                    Project p = list[i];

                    if (p.ProjectDescription == "Maintenance and calibration" )
                    {
                        dgvProjects.Rows.Add();
                        dgvProjects[0, i].Value = String.Format("I{0:00000} sub {1:00} step {2:00}", p.ProjectID, p.SubProject, p.Step);

                    }
                    else 
                    {
                        dgvProjects.Rows.Add();
                        dgvProjects[0, i].Value = String.Format("P{0:00000} sub {1:00} step {2:00}", p.ProjectID, p.SubProject, p.Step);
                    }
                    dgvProjects[8, i].Value = "Unknown";

                    dgvProjects[2, i].Value = p.StepDescription;
                    dgvProjects[4, i].Value = p.Customer;
                    double min = p.Stop == null ? (Time.UTC - p.Start).TotalMinutes : ((DateTime)p.Stop - p.Start).TotalMinutes;
                    double hrs = Math.Floor(min / 60);
                    min -= hrs * 60;
                    dgvProjects[1, i].Value = String.Format("{0:0}h{1:0}", hrs, min);

                    // Chamber description
                    try { c = cBiz.GetByPK(p.Chamber).MIDSandDescription; } catch { c = "Chamber not found!"; }
                    dgvProjects[3, i].Value = c;

                    dgvProjects.Rows[i].DefaultCellStyle.ForeColor = System.Drawing.SystemColors.ControlText;

                    System.Drawing.Color rowColor = MIDSinterface.RowColor(cBiz.GetByPK(p.Chamber).MIDS);      // obtain row color (from MIDS) for each chamber                   
                    dgvProjects.Rows[i].DefaultCellStyle.BackColor = rowColor;

                    try
                    {
                        var xml = XElement.Load(filePath);

                        if (xml.Elements("Project").FirstOrDefault(k => k.Element("Project")?.Value == dgvProjects[0, i].Value) == null)
                        {
                            var result = AnalyzeProject(p.StepDescription, rowColor);
                            string testtype = result[3].ToString();
                            
                            dgvProjects[5, i].Value = result[2];
                            dgvProjects[6, i].Value = result[0];
                            dgvProjects[7, i].Value = result[1];
                            dgvProjects[8, i].Value = testtype;
                            dgvProjects[10, i].Value = result[4];
                            dgvProjects[11, i].Value = result[5];
                            // if (row.Cells[9].Value.ToString() == "True") // only check project data if check == True
                        }
                    }
                    catch { }

                    // only enable check checkbox for P-projects, not for I-projects
                    if (p.ProjectDescription == "Maintenance and calibration")
                        dgvProjects[9, i].Value = false;
                    else
                        dgvProjects[9, i].Value = true;
                }
                
                try
                {
                    foreach (DataGridViewRow row in dgvProjects.Rows)
                    {
                        // Controleer of de eerste kolom (bijv. index 0) leeg is
                        if (row.Cells[0].Value == null || string.IsNullOrEmpty(row.Cells[0].Value.ToString()))
                        {
                            // Verwijder de rij
                            dgvProjects.Rows.Remove(row);
                        }
                    }
                }
                catch {}
            }
            catch (Exception ex)
            {
                MessageBox.Show("Could not retrieve projects from database!" + ex.Message, "Projects", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            finally
            {
                dgvProjects.ClearSelection();               
                fixedChambers();
                LoadDataFromXML();
                isLoadingData = false;
            }
        }



        private void LoadDataFromXML()
        {
            try
            {
                isLoadingData = true;
                if (!System.IO.File.Exists(filePath))
                {
                    MessageBox.Show($"XML-bestand '{filePath}' niet gevonden.", "Fout", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                    return;
                }
                var xml = XElement.Load(filePath);
                foreach (var project in xml.Elements("Project"))
                {
                    string name = project.Element("Project")?.Value; // Child <Project>

                    if (string.IsNullOrEmpty(name))
                    {
                        MessageBox.Show("Geen waarde gevonden in <Project> tag.", "Waarschuwing", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                        continue;
                    }
                    foreach (DataGridViewRow row in dgvProjects.Rows)
                    {
                        if (row.Cells[0].Value?.ToString() == name) // Kolom 1 (Name)
                        {
                            row.Cells[5].Value = project.Element("Hours")?.Value ?? string.Empty;
                            row.Cells[6].Value = project.Element("Temperature")?.Value ?? string.Empty;
                            row.Cells[7].Value = project.Element("Humidity")?.Value ?? string.Empty;
                            row.Cells[8].Value = project.Element("Testtype")?.Value ?? string.Empty;
                            row.Cells[9].Value = project.Element("Check")?.Value ?? string.Empty;
                            row.Cells[10].Value = project.Element("TempHigh")?.Value ?? string.Empty;
                            row.Cells[11].Value = project.Element("TempLow")?.Value ?? string.Empty;                            

                            break;
                        }
                    }
                }

            }
            catch (Exception ex)
            {
                MessageBox.Show($"Fout bij het laden van XML: {ex.Message}", "Fout", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            finally
            {
                isLoadingData = false;
            }
        }




        private void lbChambers_SelectedIndexChanged(object sender, EventArgs e)
        {
            updateLiveView();
        }

        private double ParseValidDouble(object value)
        {
            if (value == null) return 0.0;

            string strValue = value.ToString().Trim();
            if (string.IsNullOrEmpty(strValue) || strValue == "N/A") return 0.0;

            if (double.TryParse(strValue, out double result))
                return result;

            return 0.0;
        }


       



        void updateLiveView()
        {
            if (lbChambers.SelectedItems.Count == 0)
                return;

            Cursor.Current = Cursors.WaitCursor;

            Chamber chamber;
            try
            {
                chamber = new Chambers().GetAll().ToList().Find(delegate (Chamber c) { return (c.MIDSandDescription == (string)lbChambers.SelectedItem); });
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "Chamber", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }

            // Fill Sensors
            if (lbSensorChanged == false)
                lbSensors.Items.Clear();
            List<Sensor> sensors;
            try
            {
                sensors = new Sensors().GetByChamber(chamber.PK);
                if (sensors.Count > 0)
                {
                    lbSensors.SelectedIndexChanged -= lbSensors_SelectedIndexChanged;
                    int index = 0;
                    foreach (Sensor s in sensors)
                    {
                       
                        if (lbSensorChanged == false)
                        {
                            lbSensors.Items.Add(s.ToString());
                            lbSensors.SetSelected(index, true); // Selecteer dit item direct
                        }
                            
                        index++;
                    }
                    lbSensors.SelectedIndexChanged += lbSensors_SelectedIndexChanged;
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
                return;
            }
            lbSensorChanged = false;

            int lastHours = 0;
            if (int.TryParse(tbLastHours.Text, out lastHours))
            { }
            else
            {
                MessageBox.Show("Voer een geldig aantal uren in.");
            }

            var sensorValues = new Dictionary<int, List<SensorReading>>(); // Dictionary per sensor


            List<string> sensorWithDatalist = new List<string>();
            List<string> selectedSensorList = new List<string>();
            int sensorid = 0;
            foreach (var sensor in sensors)
            {         
                if(!sensor.ToString().Contains("Air"))  
                    if (!lbSensors.SelectedItems.Contains(sensor.ToString()))
                    {
                        sensorid++;
                        continue;
                    }                      

                if (lbSensors.SelectedItems.Contains(sensor.ToString()))
                    selectedSensorList.Add(sensor.PK.ToString());
                                  

                    SqlConnection connection = new SqlConnection("Data Source=tcp:10.126.21.47\\FEANOR,1434; Initial Catalog=FEANOR; User ID=sa; Password=resam@123resam; timeout=15; Persist Security Info=True; TrustServerCertificate=True");
                try
                {
                    using (connection)
                    {
                        string query = string.Empty;

                        if (chamber.Humidity)
                        {
                            query = "SELECT Value, TimeStamp FROM Results WHERE SensorPK = @SensorPK AND TimeStamp >= DATEADD(HOUR, -@lasthours, GETUTCDATE()) ORDER BY TimeStamp ASC";
                        }
                        else
                        {
                            query = "SELECT Value, TimeStamp FROM ResultsOudeHal WHERE SensorPK = @SensorPK AND TimeStamp >= DATEADD(HOUR, -@lasthours, GETUTCDATE()) ORDER BY TimeStamp ASC";
                        }
                       
                        SqlCommand command = new SqlCommand(query, connection);
                        command.Parameters.AddWithValue("@SensorPK", sensor.PK);
                        command.Parameters.AddWithValue("@lasthours", lastHours);

                        connection.Open();

                        
                        using (SqlDataReader reader = command.ExecuteReader())
                        {
                            var readings = new List<SensorReading>(); // Lijst voor de readings van de huidige sensor

                            while (reader.Read())
                            {
                                float resultValue = reader.IsDBNull(0) ? 0.0f : reader.GetFloat(0); // Haal de waarde op, standaard 0 als null
                                DateTime timestamp = reader.IsDBNull(1) ? DateTime.MinValue : reader.GetDateTime(1); // Haal de timestamp op

                                readings.Add(new SensorReading
                                {
                                    Value = resultValue,
                                    Timestamp = timestamp
                                });
                            }
                            if (readings.Count > 0)
                            {
                                sensorWithDatalist.Add(lbSensors.Items[sensorid].ToString());
                                sensorValues[sensor.PK] = readings;
                            }
                        }
                        
                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine($"Error for Sensor {sensor.PK}: {ex.Message}");
                }
                finally { sensorid++; }
            }

            int viewHours = lastHours;
           

            if (panelPlot.Controls.Count > 0)
            {
                panelPlot.Controls.Clear();
            }
            plotModel = new PlotModel
            {
                Title = "CMS 2 Sensor Data",
            };

            plotModel.Legends.Add(new Legend
            {
                LegendPosition = LegendPosition.RightTop, // Plaats de legenda rechtsboven
                LegendOrientation = LegendOrientation.Vertical, // Oriëntatie van de legenda
                LegendPlacement = LegendPlacement.Outside, // Plaats de legenda buiten de plot
                LegendBackground = OxyColors.White, // Achtergrondkleur van de legenda
                LegendBorder = OxyColors.Black // Randkleur van de legenda
            });

           
            var plotView = new PlotView
            {
                Model = plotModel,
                Dock = DockStyle.Fill
            };
            panelPlot.Controls.Add(plotView);
            plotModel.Series.Clear();

            plotModel.Axes.Add(new OxyPlot.Axes.LinearAxis // x-as
            {
                Position = OxyPlot.Axes.AxisPosition.Bottom,
                Title = "Hours since last point [h]",
                MajorGridlineStyle = LineStyle.Solid,
                MinorGridlineStyle = LineStyle.Dot,
                StartPosition = 1, // Begin van de as rechts
                EndPosition = 0,    // Eind van de as links
                Minimum = 0,       // Begin bij 0 uur (laatste punt)
                Maximum = viewHours,      // Toon slechts 24 uur in de view
                IsPanEnabled = true, // Schakel scrollen/pannen in
                IsZoomEnabled = true, // Schakel in- en uitzoomen in
                AbsoluteMinimum = 0,  // Minimum waarde voor pannen
                AbsoluteMaximum = lastHours // Maximum waarde voor pannen
            });

            var yAxis1 = new OxyPlot.Axes.LinearAxis // y-as 1 voor temp en RH
            {
                Position = OxyPlot.Axes.AxisPosition.Left,
                Title = "Temperature [°C] / RH [%]",
                MajorGridlineStyle = LineStyle.Solid,
                MinorGridlineStyle = LineStyle.Dot,
                Minimum = 0,
                Maximum = 110,
                Key = "TempRH"
            };


            var yAxis2 = new OxyPlot.Axes.LinearAxis// y-as 1 voor spanning en stroom
            {
                Position = OxyPlot.Axes.AxisPosition.Right,
                Title = "Voltage [V]",
                MajorGridlineStyle = LineStyle.Solid,
                MinorGridlineStyle = LineStyle.Dot,
                Minimum = 0,
                Maximum = 30,
                Key = "Volt"
            };

            int sensorCount = 0;
            DateTime? lastTimestamp = null;

            double maxVoltage = 0.0;
            double minVoltage = 0.0;
            double maxTempRH = 0.0;
            double minTempRH = 0.0;

            var sensorValuesSync = new Dictionary<int, List<SensorReading>>(); // Dictionary per sensor

                
            try
            {
                // Selecteer de eerste sensor als referentie
                var referenceSensor = sensorValues.First();
                int referenceKey = referenceSensor.Key;
                var referenceTimestamps = referenceSensor.Value.Select(r => r.Timestamp).ToList();


                // Ga per tijdstip in de referentiesensor door alle andere sensoren heen
                foreach (var timestamp in referenceTimestamps)
                {
                    foreach (var sensor in sensorValues)
                    {
                        var sensorKey = sensor.Key;

                        // Maak een nieuwe lijst voor sensorwaarden als deze nog niet bestaat
                        if (!sensorValuesSync.ContainsKey(sensorKey))
                        {
                            sensorValuesSync[sensorKey] = new List<SensorReading>();
                        }

                        if (sensorKey == referenceKey)
                        {
                            var referenceValue = referenceSensor.Value.First(r => r.Timestamp == timestamp).Value;

                            sensorValuesSync[sensorKey].Add(new SensorReading
                            {
                                Value = referenceValue,
                                Timestamp = timestamp
                            });
                        }
                        else
                        {
                            // Zoek de dichtstbijzijnde waarde binnen 20 seconden
                            var closestReading = sensor.Value
                                .Where(r => Math.Abs((r.Timestamp - timestamp).TotalSeconds) <= 20)
                                .OrderBy(r => Math.Abs((r.Timestamp - timestamp).TotalSeconds))
                                .FirstOrDefault();

                            double value = closestReading != null ? closestReading.Value : 0;

                            // Voeg de gevonden waarde toe aan de sync dictionary
                            sensorValuesSync[sensorKey].Add(new SensorReading
                            {
                                Value = (float)value,
                                Timestamp = timestamp
                            });
                        }
                    }
                }
            }
            catch{}
            


            sensorValues = sensorValuesSync;

            foreach (var sensor in sensorValues.Keys.ToList())
            {
                var readings = sensorValues[sensor];
                if (readings.Count > 1)
                    readings.RemoveAt(readings.Count - 1);
                else
                    readings.Clear();
            }

            foreach (var sensor in sensorValues)
            {                
                if(!selectedSensorList.Contains(sensor.Key.ToString()))
                {
                    sensorCount++;
                    continue;
                }

                // calibration correction!
                var sensorPK = sensor.Key; // Haal de sensor.PK op                   
                double a = 1.0;
                double b = 0.0;
                try
                {
                    Calibration t = new Calibrations().GetLastCreatedBySensorPK(sensorPK);
                    if (t != null) // calibration found
                    {
                        a = t.Coefficients[1];  // gain
                        b = t.Coefficients[0]; // offset
                    }
                    else // no calibration found
                    {
                        a = 1.0; // gain
                        b = 0.0; // offset
                    }
                }
                catch
                {
                    string msg = "Could not retrieve calibrations for sensor ";
                }


                var series = new LineSeries
                {
                    Title = $"Sensor {sensorCount}",
                    StrokeThickness = 2,                  
                    MarkerType = MarkerType.Circle,         // Punt zichtbaar maken
                    MarkerSize = 2,                         // Grootte van de punten
                };

                foreach (var reading in sensor.Value)
                {
                    if (lastTimestamp == null || reading.Timestamp > lastTimestamp)
                    {
                        lastTimestamp = reading.Timestamp;
                    }
                }

                double hoursSinceNow = 0;
                if (lastTimestamp.HasValue)
                {
                    TimeSpan timeSinceLast = DateTime.UtcNow - lastTimestamp.Value;
                    hoursSinceNow = timeSinceLast.TotalHours;

                    if (timeSinceLast > TimeSpan.FromMinutes(10))                    
                        Console.WriteLine("Laatste meting is meer dan 10 minuten geleden.");
                    
                }

                if (sensorCount ==0)
                {
                    int cycleCount = 0;
                    bool upCrossed = false;
                    bool downCrossed = false;
                    double uppercountvalue = Double.Parse(tbHighTC.Text);
                    double lowercountvalue = Double.Parse(tbLowTC.Text);

                    foreach (var reading in sensor.Value)
                    {
                        double hoursSinceLast = (lastTimestamp.Value - reading.Timestamp).TotalHours + hoursSinceNow;
                        double temperature = (double)(reading.Value * a + b); // Correctie toegepast

                        series.Points.Add(new DataPoint(hoursSinceLast, temperature));

                        if (temperature >= uppercountvalue)
                            upCrossed = true; // Opgaande overgang

                        if (temperature <= lowercountvalue && upCrossed)
                            downCrossed = true; // Neergaande overgang

                        if (upCrossed && downCrossed)
                        {
                            cycleCount++; // Volledige cyclus geteld
                            upCrossed = false;
                            downCrossed = false;
                        }
                    }
                    lblCycles.Text = string.Format(cycleCount.ToString() + " cycles in last " + tbLastHours.Text + " hours");                                      
                }
                else
                {
                    foreach (var reading in sensor.Value)
                    {
                        double hoursSinceLast = (lastTimestamp.Value - reading.Timestamp).TotalHours + hoursSinceNow;
                        series.Points.Add(new DataPoint(hoursSinceLast, (double)(reading.Value * a + b))); // CORRECTION!!!!!!!!!!!!!!!!!!!!
                    }
                }

                              

                series.Title = sensorWithDatalist[sensorCount];
                
                if (sensorWithDatalist[sensorCount].ToLower().Contains("rh"))
                    series.Color = OxyColors.DarkBlue;
                else if (sensorWithDatalist[sensorCount].ToLower().Contains("air"))
                    series.Color = OxyColors.Red;
                else if (sensorWithDatalist[sensorCount].ToLower().Contains("water"))
                    series.Color = OxyColors.LightBlue;

                if (sensorWithDatalist[sensorCount].ToLower().Contains("voltage")) // koppel sensordata aan juiste as 
                {
                    maxVoltage = Math.Max(maxVoltage, series.Points.Max(point => point.Y));
                    minVoltage = Math.Min(minVoltage, series.Points.Min(point => point.Y));
                    series.YAxisKey = "Volt";
                }
                else
                {
                    maxTempRH = Math.Max(maxTempRH, series.Points.Max(point => point.Y));
                    minTempRH = Math.Min(minTempRH, series.Points.Min(point => point.Y));
                    series.YAxisKey = "TempRH";
                }
                plotModel.Series.Add(series);
                sensorCount++;
            }
            //Console.WriteLine("max temp/RH " + maxTempRH.ToString() + "   min temp/RH " + minTempRH.ToString());
            yAxis1.Maximum = (int)maxTempRH + 10;
            yAxis1.Minimum = (int)minTempRH - 10;
            yAxis1.AbsoluteMaximum = yAxis1.Maximum;
            yAxis1.AbsoluteMinimum = yAxis1.Minimum;

            // Console.WriteLine("max voltage " + maxVoltage.ToString() + "   min voltage " + minVoltage.ToString());
            if (cbVoltageScale.Checked == false)
            {
                yAxis2.Maximum = (int)maxVoltage + 1;
                yAxis2.Minimum = (int)minVoltage - 1;
                yAxis2.AbsoluteMaximum = yAxis2.Maximum;
                yAxis2.AbsoluteMinimum = yAxis2.Minimum;
            }
            else
            {
                yAxis2.Maximum = yAxis1.Maximum;
                yAxis2.Minimum = yAxis1.Minimum;
                yAxis2.AbsoluteMaximum = yAxis1.AbsoluteMaximum;
                yAxis2.AbsoluteMinimum = yAxis1.AbsoluteMinimum;
            }


            plotModel.Axes.Add(yAxis1);
            plotModel.Axes.Add(yAxis2);

            if (cbShowEnvelope.Checked == true)
            {
                if (dgvProjects.Rows.Count > 0)
                {
                    foreach (DataGridViewRow row in dgvProjects.Rows)
                    {
                        if (!row.IsNewRow)
                        {
                            var chamberValue = row.Cells["dgvProjects_Chamber"].Value;
                            if (chamberValue != null)
                            {
                                if (chamberValue.ToString() == (string)lbChambers.SelectedItem) // chamber has an active project running --> show envelope!
                                {
                                    Console.WriteLine("project found for " + chamber.MIDS.ToString());

                                    string testtype = row.Cells[8].Value.ToString();

                                    double tempdiff = ParseValidDouble(tbTempDev.Text);
                                    double rhdiff = ParseValidDouble(tbHumidityDev.Text);
                                    double testtemp = ParseValidDouble(row.Cells[6].Value);                                   
                                    double testrh = ParseValidDouble(row.Cells[7].Value);
                                    double settempH = ParseValidDouble(row.Cells["CTempHigh"].Value);
                                    double settempL = ParseValidDouble(row.Cells["CTempLow"].Value);

                                    // steady temperature + humidity
                                    if (testtype.Contains("HAST") || testtype.Contains("THB") || testtype.Contains("THB_cycledbias") ||  testtype.Contains("Climate"))
                                    {                                       
                                        var tempBand = new RectangleAnnotation
                                        {
                                            MinimumY = testtemp - tempdiff,
                                            MaximumY = testtemp + tempdiff,
                                            MinimumX = double.NegativeInfinity,  // Volledige breedte
                                            MaximumX = double.PositiveInfinity,  // Volledige breedte
                                            Fill = OxyColor.FromAColor(20, OxyColors.Red)  // Doorzichtige rode band
                                        };
                                        plotModel.Annotations.Add(tempBand);
                                       
                                        var rhBand = new RectangleAnnotation
                                        {
                                            MinimumY = testrh - rhdiff,
                                            MaximumY = testrh + rhdiff,
                                            MinimumX = double.NegativeInfinity,  // Volledige breedte
                                            MaximumX = double.PositiveInfinity,  // Volledige breedte
                                            Fill = OxyColor.FromAColor(20, OxyColors.Blue)  // Doorzichtige blauwe band
                                        };
                                        plotModel.Annotations.Add(rhBand);
                                    }

                                    // steady temperature
                                    else if (testtype.Contains("HTOL") || testtype.Contains("Bake"))
                                    {                                       
                                        var tempBand = new RectangleAnnotation
                                        {
                                            MinimumY = testtemp - tempdiff,
                                            MaximumY = testtemp + tempdiff,
                                            MinimumX = double.NegativeInfinity,  // Volledige breedte
                                            MaximumX = double.PositiveInfinity,  // Volledige breedte
                                            Fill = OxyColor.FromAColor(20, OxyColors.Red)  // Doorzichtige blauwe band
                                        };
                                        plotModel.Annotations.Add(tempBand);
                                    }


                                    // temperature cycling
                                    else if (testtype.Contains("TC") || testtype.Contains("PTC"))                             
                                    {
                                        try
                                        {                                            
                                            var tempBandH = new RectangleAnnotation
                                            {
                                                MinimumY = settempH - tempdiff,
                                                MaximumY = settempH + tempdiff,
                                                MinimumX = double.NegativeInfinity,  // Volledige breedte
                                                MaximumX = double.PositiveInfinity,  // Volledige breedte
                                                Fill = OxyColor.FromAColor(20, OxyColors.Red)  // Doorzichtige band
                                            };
                                            plotModel.Annotations.Add(tempBandH);
                                                                                       
                                            var tempBandL = new RectangleAnnotation
                                            {
                                                MinimumY = settempL - tempdiff,
                                                MaximumY = settempL + tempdiff,
                                                MinimumX = double.NegativeInfinity,  // Volledige breedte
                                                MaximumX = double.PositiveInfinity,  // Volledige breedte
                                                Fill = OxyColor.FromAColor(20, OxyColors.Red)  // Doorzichtige band
                                            };
                                            plotModel.Annotations.Add(tempBandL);
                                        }
                                        catch {}                                       
                                    }
                                }
                            }
                        }
                    }
                }
            }

            Cursor.Current = Cursors.Default;
        }

        private void HalControle_Load(object sender, EventArgs e)
        {

        }

        private void fileSystemWatcher1_Changed(object sender, FileSystemEventArgs e)
        {

        }



        void GeneralDataCheck()
        {
            Console.WriteLine("general data check started...");

            sensorAttempts.Clear();

            double Tmin = Double.Parse(tbTmin.Text);
            double Tmax = Double.Parse(tbTmax.Text);
            double RHmin = Double.Parse(tbRHmin.Text);
            double RHmax = Double.Parse(tbRHmax.Text);
            double Vmin = Double.Parse(tbVmin.Text);
            double Vmax = Double.Parse(tbVmax.Text);
           
           
            try
            {
                foreach (var Item in lbChambers.Items)
                {
                    Chamber chamber = new Chambers().GetAll().ToList().Find(c => c.MIDSandDescription == (string)Item);
                    List<string> sensorname = new List<string>();
                    if (chamber != null)
                    {
                        Console.WriteLine("Checking chamber " + chamber.MIDS);
                        List<Sensor> sensors;
                        try
                        {
                            sensors = new Sensors().GetByChamber(chamber.PK);
                            if (sensors.Count > 0)
                            {
                                foreach (Sensor s in sensors)
                                {
                                    sensorname.Add(s.Description);
                                }
                            }
                        }
                        catch (Exception ex)
                        {
                            MessageBox.Show(ex.Message, String.Format("Sensors in chamber {0:00000}", chamber.MIDS), MessageBoxButtons.OK, MessageBoxIcon.Error);
                            return;
                        }

                        var sensorValues = new Dictionary<int, List<SensorReading>>(); // Dictionary per sensor

                        List<string> sensorWithDatalist = new List<string>();
                        int sensorid = 0;
                       
                        foreach (var sensor in sensors)
                        {
                            SqlConnection connection = new SqlConnection("Data Source=tcp:10.126.21.47\\FEANOR,1434; Initial Catalog=FEANOR; User ID=sa; Password=resam@123resam; timeout=15; Persist Security Info=True; TrustServerCertificate=True");
                            try
                            {
                                using (connection)
                                {
                                    string query = string.Empty;

                                    if (chamber.Humidity)
                                    {
                                        query = "SELECT Value, TimeStamp FROM Results WHERE SensorPK = @SensorPK AND TimeStamp >= DATEADD(HOUR, -@lasthours, GETUTCDATE()) ORDER BY TimeStamp ASC";
                                    }
                                    else
                                    {
                                        query = "SELECT Value, TimeStamp FROM ResultsOudeHal WHERE SensorPK = @SensorPK AND TimeStamp >= DATEADD(HOUR, -@lasthours, GETUTCDATE()) ORDER BY TimeStamp ASC";
                                    }

                                    SqlCommand command = new SqlCommand(query, connection);
                                    command.Parameters.AddWithValue("@SensorPK", sensor.PK);
                                    command.Parameters.AddWithValue("@lasthours", Int32.Parse(tbCheckLastHour.Text));

                                    connection.Open();

                                    using (SqlDataReader reader = command.ExecuteReader())
                                    {
                                        var readings = new List<SensorReading>();

                                        while (reader.Read())
                                        {
                                            float resultValue = reader.IsDBNull(0) ? 0.0f : reader.GetFloat(0); // Haal de waarde op, standaard 0 als null
                                            DateTime timestamp = reader.IsDBNull(1) ? DateTime.MinValue : reader.GetDateTime(1); // Haal de timestamp op

                                            readings.Add(new SensorReading
                                            {
                                                Value = resultValue,
                                                Timestamp = timestamp
                                            });
                                        }
                                        if (readings.Count > 0)
                                        {
                                            //sensorWithDatalist.Add(lbSensors.Items[sensorid].ToString());
                                            sensorValues[sensor.PK] = readings;
                                            
                                        }
                                        

                                        // calibration correction!
                                        var sensorPK = sensor.PK; // Haal de sensor.PK op                   
                                        double a = 1.0;
                                        double b = 0.0;
                                        try
                                        {
                                            Calibration t = new Calibrations().GetLastCreatedBySensorPK(sensorPK);
                                            if (t != null) // calibration found
                                            {
                                                a = t.Coefficients[1];  // gain
                                                b = t.Coefficients[0]; // offset
                                            }
                                            else // no calibration found
                                            {
                                                a = 1.0; // gain
                                                b = 0.0; // offset
                                            }
                                        }
                                        catch
                                        {
                                            string msg = "Could not retrieve calibrations for sensor ";
                                        }

                                        foreach (var reading in readings)
                                        {
                                            double value = (double)(reading.Value * a + b);
                                            //Console.WriteLine("SENSORPK " + sensor.PK +"  type " +  sensorname[sensorid] +  $"  Value: value}, Timestamp: {reading.Timestamp}");

                                            if (sensorname[sensorid].ToLower().Contains("temperature"))
                                            {
                                                if (value < Tmin || value > Tmax)
                                                {
                                                    if (!RowExists(dgvGeneralErrors, sensorPK))
                                                        dgvGeneralErrors.Rows.Add(chamber.MIDS, sensorPK, reading.Timestamp, Math.Round(value, 2), sensorname[sensorid], 1);
                                                }
                                            }
                                            else if (sensorname[sensorid].ToLower().Contains("rh"))
                                            {
                                                if (value < RHmin || value > RHmax)
                                                {
                                                    if (!RowExists(dgvGeneralErrors, sensorPK))
                                                        dgvGeneralErrors.Rows.Add(chamber.MIDS, sensorPK, reading.Timestamp, Math.Round(value, 2), sensorname[sensorid], 1);
                                                }
                                            }
                                            else if (sensorname[sensorid].ToLower().Contains("voltage"))
                                            {
                                                if (value < Vmin || value > Vmax)
                                                {
                                                    if (!RowExists(dgvGeneralErrors, sensorPK))
                                                        dgvGeneralErrors.Rows.Add(chamber.MIDS, sensorPK, reading.Timestamp, Math.Round(value, 2), sensorname[sensorid], 1);
                                                }
                                            }
                                        }

                                        try
                                        {
                                            //if (sensorValues.Count > 0 && sensorname[sensorid].ToLower().Contains("air temperature"))
                                            if (sensorname[sensorid].ToLower().Contains("air temperature"))
                                            {
                                                DateTime meestRecenteUtc = sensorValues
                                                    .SelectMany(kvp => kvp.Value)
                                                    .Max(r => r.Timestamp);

                                                TimeZoneInfo nlTz = TimeZoneInfo.FindSystemTimeZoneById("W. Europe Standard Time");
                                                DateTime meestRecenteLocal = TimeZoneInfo.ConvertTimeFromUtc(meestRecenteUtc, nlTz);
                                                TimeSpan verschil = DateTime.Now - meestRecenteLocal;
                                                bool ouderDan20Min = verschil.TotalMinutes > 20;

                                                if (ouderDan20Min == true)
                                                {
                                                    Console.WriteLine("Meer dan 20 minuten geen data!");
                                                    if (!RowExists(dgvGeneralErrors, sensorPK))
                                                        dgvGeneralErrors.Rows.Add(chamber.MIDS, sensorPK, 0, 0, sensorname[sensorid], 1);
                                                }
                                            }
                                        }
                                        catch
                                        {
                                            Console.WriteLine("Geen data gevonden voor deze kamer");
                                            if (!RowExists(dgvGeneralErrors, sensorPK))
                                                dgvGeneralErrors.Rows.Add(chamber.MIDS, sensorPK, 0, 0, sensorname[sensorid], 1);
                                        }                                        


                                        sensorid++;
                                    }
                                }
                            }
                            catch (Exception ex)
                            {
                                Console.WriteLine($"Error for Sensor {sensor.PK}: {ex.Message}");
                            }                          

                        }
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "Chamber", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }

            
            try
            {
                // Lees uitgesloten kamernummers vanuit bestand
                var excludedChambers = File.ReadAllLines(@"Z:\projects\2020\P201339\sub1\4. Software\1. Feanor\excluded_chambers.txt")
                                            .Select(line => line.Trim())
                                            .Where(line => !string.IsNullOrEmpty(line))
                                            .ToHashSet(); // Snelle lookup

                foreach (var cabinet in cabinets)
                {
                    bool generalerror = false;
                    foreach (DataGridViewRow row in dgvGeneralErrors.Rows)
                    {
                        string chambernumber = row.Cells[0].Value?.ToString();
                        if (!string.IsNullOrEmpty(chambernumber) &&
                            Int32.TryParse(cabinet.Name, out int cabinetNr) &&
                            Int32.TryParse(chambernumber, out int chamberNr))
                        {
                            // Check of er een error is én het kamernummer NIET is uitgesloten
                            if (cabinetNr == chamberNr && !excludedChambers.Contains(chambernumber))
                            {
                                generalerror = true;
                                break;
                            }
                        }
                    }

                    if (generalerror)
                        cabinet.StatusColor = Color.FromArgb(247, 180, 116);
                }

                updateOverview();
            }
            catch (Exception ex)
            {               
                Console.WriteLine("Fout bij het verwerken van fouten: " + ex.Message);
            }   
            Console.WriteLine("general data check finished");
        }

        int HaalUrenUitTijdsduur(string tijdsduur)
        {
            if (tijdsduur == null)
                return 0;

            int indexH = tijdsduur.IndexOf('h');

            if (indexH > 0)
            {
                string urenString = tijdsduur.Substring(0, indexH);
                if (int.TryParse(urenString, out int uren))
                {
                    return uren;
                }
            }

            // Als iets misgaat, bijvoorbeeld geen 'h' of geen geldig getal
            throw new FormatException("Ongeldige tijdsduurstring. Verwacht formaat '22h50'.");
        }

        void projectDataCheck()
        {
            Console.WriteLine("project data check started...");

            sensorAttempts.Clear();            

            try
            {
                foreach (DataGridViewRow row in dgvProjects.Rows)
                {
                    string chambernumber = row.Cells[3].Value.ToString();                                     

                    if (row.Cells[9].Value.ToString() == "True") // only check project data if check == True
                    {                       
                        int uren = HaalUrenUitTijdsduur(row.Cells["dgvProjects_Duration"].Value?.ToString()); // haal duration op in volle uren (getal voor de "h")                       

                        Chamber chamber = new Chambers().GetAll().ToList().Find(c => c.MIDSandDescription == chambernumber);
                        List<string> sensorname = new List<string>();
                        if (chamber != null)
                        {
                            Console.WriteLine("Checking chamber " + chamber.MIDS);
                            List<Sensor> sensors;
                            try
                            {
                                sensors = new Sensors().GetByChamber(chamber.PK);
                                if (sensors.Count > 0)
                                {
                                    foreach (Sensor s in sensors)
                                    {
                                        sensorname.Add(s.Description);
                                    }
                                }
                            }
                            catch (Exception ex)
                            {
                                MessageBox.Show(ex.Message, String.Format("Sensors in chamber {0:00000}", chamber.MIDS), MessageBoxButtons.OK, MessageBoxIcon.Error);
                                return;
                            }

                            var sensorValues = new Dictionary<int, List<SensorReading>>(); // Dictionary per sensor

                            List<string> sensorWithDatalist = new List<string>();
                            int sensorid = 0;
                            SensorReading mostRecentReading = null;

                            foreach (var sensor in sensors)
                            {
                                SqlConnection connection = new SqlConnection("Data Source=tcp:10.126.21.47\\FEANOR,1434; Initial Catalog=FEANOR; User ID=sa; Password=resam@123resam; timeout=15; Persist Security Info=True; TrustServerCertificate=True");
                                try
                                {
                                    using (connection)
                                    {
                                        string query = string.Empty;

                                        if (chamber.Humidity)
                                        {
                                            query = "SELECT Value, TimeStamp FROM Results WHERE SensorPK = @SensorPK AND TimeStamp >= DATEADD(HOUR, -@lasthours, GETUTCDATE()) ORDER BY TimeStamp ASC";
                                        }
                                        else
                                        {
                                            query = "SELECT Value, TimeStamp FROM ResultsOudeHal WHERE SensorPK = @SensorPK AND TimeStamp >= DATEADD(HOUR, -@lasthours, GETUTCDATE()) ORDER BY TimeStamp ASC";
                                        }

                                        SqlCommand command = new SqlCommand(query, connection);
                                        command.Parameters.AddWithValue("@SensorPK", sensor.PK);
                                        command.Parameters.AddWithValue("@lasthours", Int32.Parse(tbCheckLastProjectData.Text));

                                        connection.Open();

                                        using (SqlDataReader reader = command.ExecuteReader())
                                        {
                                            var readings = new List<SensorReading>();

                                            while (reader.Read())
                                            {
                                                float resultValue = reader.IsDBNull(0) ? 0.0f : reader.GetFloat(0); // Haal de waarde op, standaard 0 als null
                                                DateTime timestamp = reader.IsDBNull(1) ? DateTime.MinValue : reader.GetDateTime(1); // Haal de timestamp op

                                                readings.Add(new SensorReading
                                                {
                                                    Value = resultValue,
                                                    Timestamp = timestamp
                                                });
                                            }
                                            if (sensorname[sensorid].ToLower().Contains("air temperature"))
                                                mostRecentReading = readings.OrderByDescending(r => r.Timestamp).FirstOrDefault();
                                           

                                            if (readings.Count > 0)
                                            {
                                                //sensorWithDatalist.Add(lbSensors.Items[sensorid].ToString());
                                                sensorValues[sensor.PK] = readings;
                                            }

                                            // calibration correction!                                                   
                                            double a = 1.0;
                                            double b = 0.0;
                                            try
                                            {
                                                Calibration t = new Calibrations().GetLastCreatedBySensorPK(sensor.PK);
                                                if (t != null) // calibration found
                                                {
                                                    a = t.Coefficients[1];  // gain
                                                    b = t.Coefficients[0]; // offset
                                                }
                                                else // no calibration found
                                                {
                                                    a = 1.0; // gain
                                                    b = 0.0; // offset
                                                }
                                            }
                                            catch
                                            {
                                                string msg = "Could not retrieve calibrations for sensor ";
                                            }

                                            string testtype = row.Cells[8].Value.ToString();

                                            double tempdiff = ParseValidDouble(tbTempDev.Text);
                                            double rhdiff = ParseValidDouble(tbHumidityDev.Text);
                                            double testtemp = ParseValidDouble(row.Cells[6].Value);
                                            double testrh = ParseValidDouble(row.Cells[7].Value);


                                            // only detect project data after the project runs for 1 hour                                           

                                            int onlyhours = 1;
                                            if(row.Cells[1].Value!= null)                                           
                                            {
                                                Match match = Regex.Match(row.Cells[1].Value.ToString(), @"^(\d+)h");
                                                onlyhours = int.Parse(match.Groups[1].Value);
                                            }                                          
                                                                                      

                                            if(onlyhours>=1)
                                            {
                                                // steady temperature + humidity
                                                if (testtype.Contains("HAST") || testtype.Contains("Climate") || testtype.Contains("THB") || testtype.Contains("THB_cycledbias"))
                                                {
                                                    foreach (var reading in readings)
                                                    {
                                                        double value = reading.Value * a + b; // gecorrigeerde waarde!
                                                                                              //Console.WriteLine("SENSORPK " + sensor.PK + "  type " + sensorname[sensorid] + $"  Value: {value}, Timestamp: {reading.Timestamp}");
                                                        if (sensorname[sensorid].ToLower().Contains("air temperature")) // don't check water temperature (not neccessary, only air temp + rh)
                                                        {
                                                            if (value > (testtemp + tempdiff) || value < (testtemp - tempdiff))
                                                            {
                                                                //Console.WriteLine("temperature too high/low --> SENSORPK " + sensor.PK + "  type " + sensorname[sensorid] + "  Value: " + value + "  Refvalue: " + testtemp + "  +/- " + tempdiff + "  Timestamp: " + reading.Timestamp);
                                                                if (!RowExists(dgvProjectErrors, sensor.PK))
                                                                    dgvProjectErrors.Rows.Add(chamber.MIDS, sensor.PK, reading.Timestamp, Math.Round(value, 2), sensorname[sensorid], 1);
                                                            }
                                                        }
                                                        else if (sensorname[sensorid].ToLower().Contains("rh"))
                                                        {
                                                            if (row.Cells[7].Value.ToString() == "N/A")
                                                            {
                                                                //MessageBox.Show("Invalid RH for " + row.Cells[0].Value.ToString());
                                                                break;
                                                            }
                                                            if (value > (testrh + rhdiff) || value < (testrh - rhdiff))
                                                            {
                                                                //Console.WriteLine("rh too high/low --> SENSORPK " + sensor.PK + "  type " + sensorname[sensorid] + "  Value: " + value + "  Refvalue: " + testrh + "  +/- " + rhdiff + "  Timestamp: " + reading.Timestamp);
                                                                if (!RowExists(dgvProjectErrors, sensor.PK))
                                                                    dgvProjectErrors.Rows.Add(chamber.MIDS, sensor.PK, reading.Timestamp, Math.Round(value, 2), sensorname[sensorid], 1);
                                                            }
                                                        }                                                       
                                                    }
                                                }

                                                // steady temperature
                                                else if (testtype.Contains("HTOL") || testtype.Contains("Bake"))
                                                {
                                                    foreach (var reading in readings)
                                                    {
                                                        double value = reading.Value * a + b; // gecorrigeerde waarde!
                                                                                              //Console.WriteLine("SENSORPK " + sensor.PK + "  type " + sensorname[sensorid] + $"  Value: {value}, Timestamp: {reading.Timestamp}");
                                                        if (sensorname[sensorid].ToLower().Contains("air temperature")) // 
                                                        {
                                                            if (value > (testtemp + tempdiff) || value < (testtemp - tempdiff))
                                                            {
                                                                //Console.WriteLine("temperature too high/low --> SENSORPK " + sensor.PK + "  type " + sensorname[sensorid] + "  Value: " + value + "  Refvalue: " + testtemp + "  +/- " + tempdiff + "  Timestamp: " + reading.Timestamp);
                                                                if (!RowExists(dgvProjectErrors, sensor.PK))
                                                                    dgvProjectErrors.Rows.Add(chamber.MIDS, sensor.PK, reading.Timestamp, Math.Round(value, 2), sensorname[sensorid], 1);
                                                            }
                                                        }                                                       
                                                    }
                                                }

                                                // temperature cycling
                                                // voor TC en PTC wordt er naar de air temp gekeken of de min en max waarde gehaald worden (1 min en 1 max = 1 cycle), wordt er 1 of meer cycles gevonden, goedgekeurd!
                                                else if ((testtype.Contains("TC") || testtype.Contains("PTC")) && sensorname[sensorid].Contains("Air"))
                                                {
                                                    // Alle Air-sensormetingen verzamelen
                                                    List<double> airTemperatures = new List<double>();
                                                    foreach (var reading in readings)
                                                    {                                                        
                                                        double value = reading.Value * a + b; // gecorrigeerde waarde
                                                        airTemperatures.Add(value);                                                                                                              
                                                    }
                                                    // Analyseer op cycles: detecteer of beide extremen zijn bereikt
                                                    double minThreshold = Double.Parse(row.Cells["CTempLow"].Value.ToString());
                                                    double maxThreshold = Double.Parse(row.Cells["CTempHigh"].Value.ToString());                                                                                                         

                                                    bool minReached = false;
                                                    bool maxReached = false;
                                                    int cycleCount = 0;

                                                    foreach (var value in airTemperatures)
                                                    {
                                                        if (value <= minThreshold)
                                                            minReached = true;

                                                        if (value >= maxThreshold)
                                                            maxReached = true;

                                                        if (minReached && maxReached)
                                                        {
                                                            cycleCount++;
                                                            //Console.WriteLine($"Cycle {cycleCount}: Beide extremen bereikt.");
                                                            minReached = false;
                                                            maxReached = false;
                                                        }
                                                    }

                                                    if (cycleCount == 0)
                                                    {
                                                        //Console.WriteLine("Geen volledige cycles met beide extremen gevonden.");
                                                        if (!RowExists(dgvProjectErrors, sensor.PK))
                                                            dgvProjectErrors.Rows.Add(chamber.MIDS, sensor.PK, readings[0].Timestamp, Math.Round(readings[0].Value, 2), sensorname[sensorid], 1);
                                                    }
                                                }
                                            }

                                            // check for falling voltages for all tests except for PTC and THB_cycledbias tests ofcourse    (drops with 50%)                                        
                                            double previousValue = 0.0;
                                            // Check voor elke test (behalve PTC-tests)
                                            if (!testtype.Contains("PTC") && !testtype.Contains("THB_cycledbias"))
                                            {                                                
                                                if (sensorname[sensorid].ToLower().Contains("voltage")) // alleen voor spanningskanalen
                                                {
                                                    foreach (var reading in readings)
                                                    {                                                        
                                                        double value = reading.Value * a + b; // gecorrigeerde waarde!
                                                        //Console.WriteLine("voltage " + value.ToString() + " prevValue " + previousValue.ToString() +"  timestamp " + reading.Timestamp.ToString());

                                                        // controleer of spanning met meer dan 50% daalt
                                                        if (value < previousValue * 0.5)
                                                        {                                                                
                                                                Console.WriteLine("Spanning is meer dan 50% gedaald: " + value);
                                                                if (!RowExists(dgvProjectErrors, sensor.PK))
                                                                    dgvProjectErrors.Rows.Add(chamber.MIDS, sensor.PK, reading.Timestamp, Math.Round(value, 2), sensorname[sensorid], 1);
                                                        }                                                        

                                                        previousValue = value;
                                                    }
                                                    try
                                                    {
                                                        DateTime mostRecentTimestamp = mostRecentReading.Timestamp;
                                                   
                                                    // controleer of spanning wegzakt naar 0
                                                   
                                                    if (readings.Count > 0)
                                                    {
                                                        DateTime lastTimestamp = readings.Last().Timestamp; // Haal de timestamp van de laatste reading
                                                        TimeSpan timeDifference = lastTimestamp - mostRecentTimestamp;                                                       
                                                        if (timeDifference.TotalMinutes < -5)
                                                        {
                                                            Console.WriteLine("Spanning gedaald naar 0!");
                                                            if (!RowExists(dgvProjectErrors, sensor.PK))
                                                                dgvProjectErrors.Rows.Add(chamber.MIDS, sensor.PK, lastTimestamp, 0.0, sensorname[sensorid], 1);
                                                        }
                                                    }
                                                    }
                                                    catch { }
                                                }
                                            }






                                            sensorid++;
                                        }
                                    }
                                }
                                catch (Exception ex)
                                {
                                    Console.WriteLine($"Error for Sensor {sensor.PK}: {ex.Message}");
                                }
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "Chamber", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }



            try
            {
                foreach (var cabinet in cabinets)
                {
                    Boolean projecterror = false;
                    Boolean projectprogress = false;
                    foreach (DataGridViewRow row in dgvProjectErrors.Rows)
                    {
                        string chambernumber = row.Cells[0].Value.ToString();
                        if (Int32.Parse(cabinet.Name) == Int32.Parse(chambernumber))
                        {
                            Console.WriteLine("project error in chamber " + cabinet.Name);
                           
#warning controle of test binnen uur geleden gestart is
                            projecterror = true;
                        }
                    }
                    foreach (DataGridViewRow row in dgvProjects.Rows)
                    {
                        string chambernumber = row.Cells[3].Value.ToString();
                        if (Int32.Parse(cabinet.Name) == Int32.Parse(chambernumber))
                        {
                            projectprogress = true;
                        }
                    }


                    if (cabinet.StatusColor != Color.FromArgb(247, 180, 116))
                    {
                        if (projecterror == true)
                            cabinet.StatusColor = Color.FromArgb(238, 126, 16); // eurofins oranje
                        else if (projectprogress == true)
                        {
                            cabinet.StatusColor = Color.FromArgb(34, 177, 76); // bijpassende groene kleur

                        }
                        else
                        {
                            cabinet.StatusColor = Color.Transparent;
                        }
                    }                   
                }
            }
            catch { }

            Console.WriteLine("project data check finished");
        }



        private bool RowExists(DataGridView dgv, object sensorPK)
        {
            if (sensorAttempts.ContainsKey(sensorPK))
            {
                sensorAttempts[sensorPK]++;
            }
            else
            {
                sensorAttempts[sensorPK] = 1;
            }

            foreach (DataGridViewRow row in dgv.Rows)
            {
                if (row.IsNewRow) continue;
                if (row.Cells[1].Value?.Equals(sensorPK) == true)
                {
                    row.Cells[dgv.Columns.Count - 1].Value = sensorAttempts[sensorPK];
                    return true;
                }
            }
            return false;
        }




        private void tbGeneralDataInterval_TextChanged(object sender, EventArgs e)
        {
            try
            {
                //timerGeneralDataCheck.Interval = Int32.Parse(tbGeneralDataInterval.Text) * 60 * 1000;
            }
            catch
            {
                MessageBox.Show("Invalid interval value");
            }

        }


        private void btnGeneralCheck_Click(object sender, EventArgs e)
        {
            GeneralDataCheck();
        }

        private void dgvGeneralErrors_CellContentClick(object sender, DataGridViewCellEventArgs e)
        {
        }



        private void dgvGeneralErrors_Click(object sender, EventArgs e)
        {
            if (dgvGeneralErrors.SelectedRows.Count > 0)
            {
                DataGridViewRow selectedRow = dgvGeneralErrors.SelectedRows[0];
                tabControl.SelectedTab = tpDataView;

                var roomNumber = selectedRow.Cells[0].Value?.ToString();
                if (roomNumber != null)
                {
                    string formattedRoomNumber = int.TryParse(roomNumber, out int roomNum) ? roomNum.ToString("D5") : roomNumber;

                    if (lbChambers.Items.Contains(formattedRoomNumber))
                        lbChambers.SelectedItem = formattedRoomNumber;
                    else
                        lbChambers.ClearSelected();
                }
            }
        }

        private void dgvProjects_CellClick(object sender, DataGridViewCellEventArgs e)
        {
            if (dgvProjects.SelectedRows.Count > 0)
            {
                DataGridViewRow selectedRow = dgvProjects.SelectedRows[0];
            }
        }



        static string[] AnalyzeProject(string stepstring, Color backColor)
        {
            //Console.WriteLine(stepstring);
            string temperature = "N/A";
            string rh = "N/A";
            string duration = "N/A";
            string testtype = "N/A";
            string tempH = "N/A";
            string tempL = "N/A";

            if (backColor == Color.FromArgb(191, 226, 248))
                testtype = "HAST";
            else if (backColor == Color.FromArgb(196, 249, 235))
                testtype = "HTOL";
            else if (backColor == Color.FromArgb(235, 243, 253))
                testtype = "Unknown";
            else if (backColor == Color.FromArgb(197, 249, 199)) // Green TC 2 chamber
                testtype = "TC";
            else if (backColor == Color.Pink) // Pink
                testtype = "Unknown";
            else if (backColor == Color.FromArgb(208, 195, 249)) // Purple
                testtype = "Climate";
            else if (backColor == Color.FromArgb(249, 243, 195)) // Yellow TC 1 chamber
                testtype = "TC";
            else
                testtype = "Unknown";
            

            

            if(testtype=="TC")
            {

                // Regex om temperaturen zoals "-40 °C" of "+150°C" te vinden
                Regex regex = new Regex(@"([-+]?\d+)\s?°C", RegexOptions.IgnoreCase);
                MatchCollection matches = regex.Matches(stepstring);

                if (matches.Count >= 2)
                {
                    double t1 = double.Parse(matches[0].Groups[1].Value);
                    double t2 = double.Parse(matches[1].Groups[1].Value);

                    // Sorteer zodat de laagste waarde tempL is en de hoogste tempH
                    if (t1 < t2)
                    {
                        tempL = t1.ToString();
                        tempH = t2.ToString();
                    }
                    else
                    {
                        tempL = t2.ToString();
                        tempH = t1.ToString();
                    }
                    return new string[] { temperature, rh, duration, testtype, tempH, tempL };
                }
            }

            // Regex voor temperatuur (bijv. 125°C, 110±2 °C)  
            string tempPattern = @"(\d+)(?:±\d+)?\s*°C";
            Match tempMatch = Regex.Match(stepstring, tempPattern);

            if (tempMatch.Success)
            {
                temperature = tempMatch.Groups[1].Value;
            }

            // Regex voor relatieve luchtvochtigheid (bijv. 85% R.H., 85±5% R.H.)
            string rhPattern = @"(\d+)(?:±\d+)?\s*%\s*(?:R\.?H\.?|rh)";

            Match rhMatch = Regex.Match(stepstring, rhPattern);
            if (rhMatch.Success)
            {
                rh = rhMatch.Groups[1].Value;
            }

            // Regex voor duur (bijv. 24h, 68 hours, 1 hour)
            string durationPattern = @"(\d+)(?:\s*\(\+?-?\d+/-?\d+\))?\s*(?:hours?|hrs?|h)";
            Match durationMatch = Regex.Match(stepstring, durationPattern);
            if (durationMatch.Success)
            {
                duration = durationMatch.Groups[1].Value;
            }
            // Retourneer de resultaten als een array
            return new string[] { temperature, rh, duration, testtype, tempH, tempL };
        }

      

        private void dgvProjects_CellContentClick(object sender, DataGridViewCellEventArgs e)
        {

        }

        private void tpProjectData_Click(object sender, EventArgs e)
        {

        }

        private void btnProjectDataCheck_Click(object sender, EventArgs e)
        {
            projectDataCheck();
        }




        // 1x per 3 minuten ProjectdataCheck en 1x per 30 minuten GeneralDataCheck
        private int timerCount = 0;
        private void timerProjectDataCheck_Tick(object sender, EventArgs e)
        {
            Cursor = Cursors.WaitCursor;

            obtainActiveProjects();

            string timestamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
                       
            if ( timerCount % 3 == 0)     
                projectDataCheck();            

            if (timerCount % 30 == 0)
                GeneralDataCheck();            

            Cursor = Cursors.Default;
            updateOverview();

            // Teller verhogen en resetten bij 30 om oneindige groei te voorkomen
            timerCount = (timerCount + 1) % 30;
        }


        private void dgvProjects_CellValueChanged(object sender, DataGridViewCellEventArgs e)
        {
            if (isLoadingData)
                return;

            Console.WriteLine("save");

            try
            {
                var xml = new XElement("Projects",
    from DataGridViewRow row in dgvProjects.Rows
    where !row.IsNewRow // Sla lege rijen over
    select new XElement("Project",
        dgvProjects.Columns.Cast<DataGridViewColumn>()
            .Where(col => row.Cells[col.Index].Value != null) // Voorkom null waarden
            .Select(col => new XElement(col.HeaderText, row.Cells[col.Index].Value?.ToString() ?? ""))
    )
);
                xml.Save(filePath);
            }
            catch (Exception ex)
            {
                MessageBox.Show($"Fout bij het opslaan van XML: {ex.Message}", "Fout", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private void dgvProjects_DoubleClick(object sender, EventArgs e)
        {
            if (dgvProjects.SelectedRows.Count > 0)
            {
                DataGridViewRow selectedRow = dgvProjects.SelectedRows[0];

                var roomNumber = selectedRow.Cells[3].Value?.ToString();
                if (roomNumber != null)
                {
                    string formattedRoomNumber = int.TryParse(roomNumber, out int roomNum) ? roomNum.ToString("D5") : roomNumber;

                    if (lbChambers.Items.Contains(formattedRoomNumber))
                        lbChambers.SelectedItem = formattedRoomNumber;
                    else
                        lbChambers.ClearSelected();
                }
                tabControl.SelectedTab = tpDataView;
                updateLiveView();
            }
        }

        private void timerLiveData_Tick(object sender, EventArgs e)
        {
            if (cbLiveData.Checked == true)
            {
                updateLiveView();
            }
        }

        private void btnUpdateOverview_Click(object sender, EventArgs e)
        {

        }

        private void StatusIndicator_Click(object sender, MouseEventArgs e)
        {  
            CabinetStatus cabinet = null;

            if (sender is Panel panel && panel.Tag is CabinetStatus cab1)
            {
                cabinet = cab1;
            }
            else if (sender is Label label && label.Parent is Panel parentPanel && parentPanel.Tag is CabinetStatus cab2)
            {
                cabinet = cab2;
            }

            if (cabinet != null)
            {
               // MessageBox.Show($"Je hebt geklikt op: {cabinet.Name}, Positie: {cabinet.Position}, Kleur: {cabinet.StatusColor}");
                string roomNumber = cabinet.Name;
                string formattedRoomNumber = int.TryParse(roomNumber, out int roomNum) ? roomNum.ToString("D5") : roomNumber;

                if (lbChambers.Items.Contains(formattedRoomNumber))
                    lbChambers.SelectedItem = formattedRoomNumber;
                else
                    lbChambers.ClearSelected();

                tabControl.SelectedTab = tpDataView;
            }
        }

        private System.Drawing.Drawing2D.GraphicsPath RoundedRect(Rectangle bounds, int radius)
        {
            int diameter = radius * 2;
            var path = new System.Drawing.Drawing2D.GraphicsPath();

            path.AddArc(bounds.Left, bounds.Top, diameter, diameter, 180, 90);
            path.AddArc(bounds.Right - diameter, bounds.Top, diameter, diameter, 270, 90);
            path.AddArc(bounds.Right - diameter, bounds.Bottom - diameter, diameter, diameter, 0, 90);
            path.AddArc(bounds.Left, bounds.Bottom - diameter, diameter, diameter, 90, 90);
            path.CloseFigure();
            return path;
        }




        void updateOverview()
        {
            // Update RTH-sensoren
            List<int> sensorIds = rthSensors.Select(s => s.Id).ToList();
            List<(double temperature, double humidity)> sensorData = GetTemperaturesAndHumidity(sensorIds);

            lblLastCheckTimeStamp.BringToFront();
            lblLastCheckTimeStamp.Visible = true;
            lblLastCheckTimeStamp.Text = "Last checked: " + DateTime.Now.ToString("HH:mm:ss");

            for (int i = 0; i < sensorData.Count; i++)
            {
                rthSensors[i].Temperature = sensorData[i].temperature;
                rthSensors[i].Humidity = sensorData[i].humidity;
            }

            humidityLOW = false;

            foreach (var sensor in rthSensors)
            {
                // Controleer of er al een panel voor deze sensor bestaat
                Panel statusIndicator = pcHal.Controls.OfType<Panel>().FirstOrDefault(p => p.Tag is RTHSensor s && s.Id == sensor.Id);

                if (statusIndicator == null)
                {
                    // Nieuw statuspanel voor RTH-sensor aanmaken
                    statusIndicator = new Panel
                    {
                        Size = new Size(55, 55),
                        BackColor = GetColorFromHumidity(sensor.Humidity),
                        Location = sensor.Position,
                        Cursor = Cursors.Hand,
                        Tag = sensor
                    };

                    // Maak cirkelvorm
                    System.Drawing.Drawing2D.GraphicsPath path = new System.Drawing.Drawing2D.GraphicsPath();
                    path.AddEllipse(0, 0, statusIndicator.Width, statusIndicator.Height);
                    statusIndicator.Region = new Region(path);

                    statusIndicator.Paint += (sender, e) =>
                    {
                        e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
                        e.Graphics.DrawEllipse(Pens.Black, 0, 0, statusIndicator.Width - 1, statusIndicator.Height - 1);
                    };

                    // Label
                    Label sensorLabel = new Label
                    {
                        Text = $"{sensor.Temperature:F1}\n{sensor.Humidity:F1}",
                        ForeColor = Color.Black,
                        BackColor = Color.Transparent,
                        TextAlign = ContentAlignment.MiddleCenter,
                        Dock = DockStyle.Fill,
                        Font = new Font("Arial", 12, FontStyle.Bold)
                    };

                    statusIndicator.Controls.Add(sensorLabel);
                    pcHal.Controls.Add(statusIndicator);
                }
                else
                {
                    // Alleen kleur en tekst updaten
                    statusIndicator.BackColor = GetColorFromHumidity(sensor.Humidity);
                    Label label = statusIndicator.Controls.OfType<Label>().FirstOrDefault();
                    if (label != null)
                    {
                        label.Text = $"{sensor.Temperature:F1}\n{sensor.Humidity:F1}";
                    }
                }

                // Klik-event altijd toevoegen
                statusIndicator.MouseClick -= StatusIndicator_Click;
                statusIndicator.MouseClick += StatusIndicator_Click;
            }

            if(humidityLOW==true)           
                pnlESDwarning.Visible = true;            
            else            
                pnlESDwarning.Visible = false;
            

            // Update cabinets
            foreach (var cabinet in cabinets)
            {
                Panel statusIndicator = pcHal.Controls.OfType<Panel>().FirstOrDefault(p => p.Tag is CabinetStatus cab && cab.Name == cabinet.Name);

                if (statusIndicator == null)
                {
                    statusIndicator = new Panel
                    {
                        Size = new Size(55, 55),
                        BackColor = Color.Transparent, // <--- Zet BACKGROUND transparant
                        Location = cabinet.Position,
                        Cursor = Cursors.Hand,
                        Tag = cabinet
                    };
                    /*
                    statusIndicator = new Panel
                    {
                        Size = new Size(55, 55),
                        BackColor = cabinet.StatusColor,
                        Location = cabinet.Position,
                        Cursor = Cursors.Hand,
                        Tag = cabinet
                    };

                    
                    statusIndicator.Paint += (sender, e) =>
                    {
                        e.Graphics.DrawRectangle(Pens.Black, 0, 0, statusIndicator.Width - 1, statusIndicator.Height - 1);
                    };
                    */

                    //
                    statusIndicator.Paint += (sender, e) =>
                    {
                        var panel = sender as Panel;
                        e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;

                        int radius = 15; // Rondingsstraal
                        var rect = new Rectangle(0, 0, panel.Width - 1, panel.Height - 1);

                        using (var path = RoundedRect(rect, radius))
                        {
                            using (var brush = new SolidBrush(cabinet.StatusColor))
                            {
                                e.Graphics.FillPath(brush, path); // <-- TEKEN GEKLEURDE GEVULDE VORM
                            }

                            e.Graphics.DrawPath(Pens.Black, path); // <-- TEKEN RAND
                        }
                    };

                    //

                    Label numberLabel = new Label
                    {
                        Text = cabinet.Name,
                        ForeColor = Color.Black,
                        BackColor = Color.Transparent,
                        TextAlign = ContentAlignment.MiddleCenter,
                        Dock = DockStyle.Fill,
                        Font = new Font("Arial", 14, FontStyle.Bold)
                    };
                    numberLabel.MouseClick += StatusIndicator_Click; // <- toevoegen

                    statusIndicator.Controls.Add(numberLabel);
                    pcHal.Controls.Add(statusIndicator);
                }
                else
                {
                    //statusIndicator.BackColor = cabinet.StatusColor;
                }

                statusIndicator.MouseClick -= StatusIndicator_Click;
                statusIndicator.MouseClick += StatusIndicator_Click;
            }

            pcHal.BringToFront();
            pcHal.Invalidate();
        }



        Color GetColorFromHumidity(double humidity)
        {
            if (humidity < 30)
            {
                humidityLOW = true;
                return Color.FromArgb(205, 45, 45); // rth rood               
            }
            if (humidity >=30) return Color.FromArgb(34, 177, 76); // rth groen
            return Color.Red;
        }





        private void tabControl_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (tabControl.SelectedTab == tpHal)
            {
                updateOverview();
            }
        }

        private void pcHal_MouseMove(object sender, MouseEventArgs e)
        {
            if (false)
                Console.WriteLine($"X: {e.X}, Y: {e.Y}");
        }

        private void bgwGeneralDataCheck_DoWork(object sender, DoWorkEventArgs e)
        {
            GeneralDataCheck();
        }

        private void bgwProjectDataCheck_DoWork(object sender, DoWorkEventArgs e)
        {
            projectDataCheck();
        }

     

       

        private void tbLastHours_TextChanged(object sender, EventArgs e)
        {

        }

        private void tbHourView_TextChanged(object sender, EventArgs e)
        {

        }

        private void cbLiveData_CheckedChanged(object sender, EventArgs e)
        {

        }

        private void cbShowEnvelope_CheckedChanged(object sender, EventArgs e)
        {
            updateLiveView();
        }

        private void cbVoltageScale_CheckedChanged(object sender, EventArgs e)
        {
            updateLiveView();
        }

        private void tbLastHours_Leave(object sender, EventArgs e)
        {
            updateLiveView();
        }

        private void tbHourView_Leave(object sender, EventArgs e)
        {
            updateLiveView();
        }

        private void tbLastHours_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Enter)
            {
                updateLiveView();
            }
        }




        public class SensorReading
        {
            public float Value { get; set; }
            public DateTime Timestamp { get; set; }
        }

        public class RTHSensor
        {
            public int Id { get; set; }
            public double Temperature { get; set; }
            public double Humidity { get; set; }
            public Point Position { get; set; } // Positie in de PictureBox
        }

        public class CabinetStatus
        {
            public string Name { get; set; }
            public Point Position { get; set; }
            public Color StatusColor { get; set; }
        }



        private void tbHourView_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Enter)
            {
                updateLiveView();
            }

        }

        private void button1_Click(object sender, EventArgs e)
        {
            tbLastHours.Text = "10";
            updateLiveView();
        }

        private void btn1d_Click(object sender, EventArgs e)
        {
            tbLastHours.Text = "24";
            updateLiveView();
        }

        private void btn2d_Click(object sender, EventArgs e)
        {
            tbLastHours.Text = "48";
            updateLiveView();
        }

        private void btn1w_Click(object sender, EventArgs e)
        {
            tbLastHours.Text = "168";
            updateLiveView();
        }

        // Server acces parameters
        const string UserID = "mids_userquery";
        const string Password = "23uRUVfq6dXXHMWN";
        const string Catalog = "mids_maser";
        const string Server = "meeu001sqvp007.itiz-me-eu.local";

        private static MySqlConnection GetConnection()
        {
            try
            {
                string ConnectionString = String.Format("DataSource={0};Persist Security Info=False;Initial Catalog={1};Connect Timeout=30;Username={2}; Password={3};", Server, Catalog, UserID, Password);
                MySqlConnection myConnection = new MySqlConnection();
                myConnection.ConnectionString = ConnectionString;
                return myConnection;
            }
            catch (Exception e)
            {
                throw e;
            }
        }

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

        private List<(double temperature, double humidity)> GetTemperaturesAndHumidity(List<int> sensorIds)
        {
            MySqlCommand cmd;
            MySqlConnection connection = null;
            var results = new List<(double temperature, double humidity)>(); // Lijst om de resultaten op te slaan

            try
            {
                foreach (int sensorId in sensorIds)
                {
                    string query = $"SELECT temperature, humidity FROM `sensor_data` WHERE sensor_id = {sensorId} ORDER BY timestamp DESC LIMIT 1";

                    // Verbinding maken
                    connection = GetConnection();
                    if (connection == null)
                    {
                        return results; // Geen verbinding, lege lijst retourneren
                    }

                    cmd = new MySqlCommand(query, connection);

                    connection.Open();

                    // Voer de query uit
                    MySqlDataReader reader = cmd.ExecuteReader();

                    if (reader.HasRows)
                    {
                        while (reader.Read())
                        {
                            double temperature = reader.IsDBNull(0) ? 0.0 : reader.GetDouble(0);
                            double humidity = reader.IsDBNull(1) ? 0.0 : reader.GetDouble(1);

                            // Voeg de opgehaalde waarden toe aan de lijst
                            results.Add((temperature, humidity));
                        }
                    }

                    reader.Close();
                    connection.Close();
                }
            }
            catch (MySqlException ex)
            {
                // Foutmelding voor MySQL
                Console.WriteLine("MySQL fout: " + ex.Message);
            }
            catch (Exception ex)
            {
                // Algemene foutmelding voor andere fouten
                Console.WriteLine("Fout: " + ex.Message);
            }
            finally
            {
                if (connection != null)
                {
                    connection.Close();
                }
            }

            return results; // Retourneer de lijst met de opgehaalde waarden
        }

        private void lbSensors_SelectedIndexChanged(object sender, EventArgs e)
        {
            lbSensorChanged = true;
            updateLiveView();
        }
    }
}
