using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO.Ports;



namespace TERMOBOX
{
    public partial class Form1 : Form
    {

        /*************************************************************
        -------- GLOBALNI PROMENE --------
        **************************************************************/
        string RxString;    //přijímaný řetězec
        double T_I2C;       //teplota z digitálního čidla
        int T_pozadovana = 20;  //žádaná teplota při automatické regulaci
       
        int napajeni = 0;   //výchozí stav pro h-můstek (napájení vypnuto)
        int polarita = 0;   //výchozí stav pro h-můstek (na polarite nezáleží, v tomto případě chladí)
        string aktualni_stav_hmustku = "Vypnuto";   //hlídání aktuálního stavu h-můstku pro vizualizaci

        int w = 0;  //hlídá aktuální počet řádků v DGV
       
        double[] cislo_x = new double[240]; //pocet hodnot v pameti grafu
       
        double R_ref = 1000;    //hodnota referenčního odporu k PT1000
        double T_PT1000_red;    //vypočítaná teplota z PT1000 na červeném drátu
        double T_PT1000_green;  //vypočítaná teplota z PT1000 na zeleném drátu

        int Height_animation = 25;  //základní nastavení pro animaci tlačítka info
        int Width_animation = 40;    //základní nastavení pro animaci tlačítka info
        int Height_animation_final = 25;     //základní nastavení pro animaci tlačítka info
        int Width_animation_final = 40;      //základní nastavení pro animaci tlačítka info

        int switch_autoreg = 1; //výběr autoregulace (při více programech regulace)

        int animation_prepinac = 0; //prepínač pro animaci tlačítek
        int pomocna_switch = 1; //prepínač pro animaci tlačítek
        int krok = 0;   

        /**************************************************************
        -------- FUNKCE --------
        **************************************************************/

        public Form1()
        {
            InitializeComponent();
            this.MaximizeBox = false;
            this.FormBorderStyle = FormBorderStyle.FixedDialog;
        }
        
        private void Form1_Load(object sender, EventArgs e) //funkce se spouší při otevření programu
        {
            foreach (string str in SerialPort.GetPortNames())           // zde se zjisti, ktere porty jsou dostupne
            {
                comboBox_port.Items.Add(str);   
            }
            if (comboBox_port.Items.Count > 0)
            {
                comboBox_port.SelectedIndex = 0;
                b_start.Enabled = true;
            }
            else
            {
                MessageBox.Show("Nelze najít žádný COM port");
                b_start.Enabled = false;
            }

            pB_uvod.Width = 995;    //nastavení velikosti pozadí úvodní strany
            pB_uvod.Height = 575;   //nastavení velikosti pozadí úvodní strany

            //nastavení pozic 
            b_start.Location = new Point(729,207);
            b_scan.Location = new Point(600, 250);
            comboBox_port.Location = new Point(600,220);
            pB_uvod.Location = new Point(-2, -6);
        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)   
            //akce vykonané při uzavření okna
        {
            timer_DGV_print.Enabled = false;
            timer_autoreg.Enabled = false;
            timer_value_sender.Enabled = false;
            if (serialPort.IsOpen)  //uzavření komunikace se serial portem
                serialPort.Close();
        }

        private void DisplayText(object sender, EventArgs e)
            //zobrazuje text v textboxu (není normálně zobrazen)
        {
            textBox1.AppendText(RxString);  //tisk znaku z uP do pole
        }

        private void serialPort_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
            //funkce se stará o příjem dat ze serial portu
        {
            try
            {
                RxString = serialPort.ReadLine();
            }
            catch
            {
                MessageBox.Show("Bylo nutne dokončit některé operace");
            }
          //  this.Invoke(new EventHandler(DisplayText)); //tisk hodnot do textboxu
            this.Invoke(new EventHandler(zpracovani_dat));  //pokud přišly nové data, tak získáme nové hodnoty
        }

        private void zpracovani_dat(object sender, EventArgs e)
            //zpracuje přijatá data a získám hodnoty teplot
        {

            if (RxString.Length != 24) return;   // pokud by se stalo, ze data nemaji dany format, tak je zahodim
            updateQueues(ConvertToInt(RxString.Substring(0, 4)), ConvertToInt(RxString.Substring(5, 4)), ConvertToInt(RxString.Substring(10, 4)), ConvertToInt(RxString.Substring(15, 4)), ConvertToInt(RxString.Substring(20, 4)));
        }

        private short ConvertToInt(string hex)
            //fuknkce pro konverzi hexa hodnoty na int
        {
            short result = 0;
            try
            {
                result = Convert.ToInt16(hex.Substring(0, 4), 16);    
            }
            catch
            {     
            }
            return result;
        }

        public void updateQueues(double V0, double V1_red, double V2, double V1_green, double I2C)
            //vypocet a tisk teploty, volani ze zpracovani dat
        {          
            double R_PT1000_red = R_ref * ((V1_red - V2) / (V0 - V1_red));
            double R_PT1000_green = R_ref * ((V1_green - V2) / (V0 - V1_green));
            double offset_red = 2;
            double offset_green = 2.2;

            label6.Text = R_PT1000_green.ToString();
            label7.Text = R_PT1000_red.ToString();

            if (R_PT1000_red >= 1000)
                T_PT1000_red = ((3383.81 - 0.287154 * Math.Sqrt(1.59862 * 100000000 - 21000 * R_PT1000_red))) - offset_red;
            else
                T_PT1000_red = (0.2539 * R_PT1000_red - 253.92) - offset_red;

            if (R_PT1000_green >= 1000)
                T_PT1000_green = ((3383.81 - 0.287154 * Math.Sqrt(1.59862 * 100000000 - 21000 * R_PT1000_green))) - offset_green;
            else
                T_PT1000_green = (0.2539 * R_PT1000_green - 253.92) - offset_green;

            T_I2C = I2C / 128;
            l_PT1000.Text = Math.Round((T_PT1000_red), 1).ToString() + " °C";
            l_PT1000_green.Text = Math.Round((T_PT1000_green), 1).ToString();
            l_I2C.Text = Math.Round((T_I2C), 1).ToString() + " °C";
            update_chart();
            l_T_aktualni.Text = "Aktuální " +  Math.Round((T_PT1000_red), 0).ToString() + " °C";
            //l_T_aktualni.Text = "Aktuální " + Math.Round((T_PT1000_green), 0).ToString() + " °C";
        }

        private void Hmustek_ohrivani()
            //nastavení hodnot pro h-mustek aby ohříval
        {
            napajeni = 1;
            polarita = 1;
            l_stav.Text = " Topeni";
            pB_anim.BackColor = Color.MistyRose;
            l_stav.BackColor = Color.MistyRose;
            aktualni_stav_hmustku = "Topeni";
        }

        private void Hmustek_chlazeni()
            //nastavení hodnot pro h-mustek aby chladil
        {
           napajeni = 1;
           polarita = 0;
           l_stav.Text = "Chlazeni";
           pB_anim.BackColor = Color.LightSteelBlue;
           l_stav.BackColor = Color.LightSteelBlue;
           aktualni_stav_hmustku = "Chlazeni";

        }

        private void Hmustek_vypnuto()
            //nastavení hodnot pro h-mustek aby byl vypnut
        {
            napajeni = 0;
            polarita = 0;
            l_stav.Text = "Vypnuto";
            pB_anim.BackColor = Color.White;
            l_stav.BackColor = Color.White;
            aktualni_stav_hmustku = "Vypnuto";

        }

        private void update_chart()
            //funkce aktualizující celý graf
        {
            double x = Convert.ToDouble(Math.Round((T_PT1000_red), 0));
           // int y = Convert.ToInt32(Math.Round((T_I2C), 2));
      


            cislo_x[cislo_x.Count() - 1] = x; //zobrazovana hodnota
           // cislo_y[cislo_y.Count() - 1] = y; //zobrazovana hodnota

            for (int i = 0; i < cislo_x.Count() - 1; i++)
            {
                cislo_x[i] = cislo_x[i + 1];
               // cislo_y[i] = cislo_y[i + 1];
            }
            cislo_x[cislo_x.Count() - 1] = x; //zobrazovana hodnota
            //cislo_y[cislo_y.Count() - 1] = y; //zobrazovana hodnota

            Chart.Series["Series1"].Points.Clear();
            //Chart.Series["Series2"].Points.Clear();
            for (int i = 0; i < cislo_x.Count(); i++)
            {
                Chart.Series["Series1"].Points.AddY(cislo_x[i]);
                //Chart.Series["Series2"].Points.AddY(cislo_y[i]);
             
            }

        }

        private void auto_regulace()
            //automatická regulace s hysterezí
        {
           double aktualni = T_PT1000_red;   
           double hystereze = 0.4;
           int T_kriticka_chladic = 65;

           if ((T_pozadovana <= (aktualni + hystereze)) && (T_pozadovana >= (aktualni - hystereze)) || (T_kriticka_chladic < T_PT1000_green))
               Hmustek_vypnuto();
                else
                {
                    if (T_pozadovana <= aktualni)
                        Hmustek_chlazeni();
                    else
                       if (T_pozadovana >= 50)  //pokud ohřívám na 50°C jsme omezen jen horni teplotou
                           Hmustek_ohrivani();
                       else
                       {
                           if (T_PT1000_green > T_pozadovana + 6) //nepustí ohřívání dál než o 6°C
                               Hmustek_vypnuto();
                           else
                               Hmustek_ohrivani();
                       }
                }
        }
 
        private void DGW_print()
            //funkce pro tisknuti grafu (volá ji timer)
        {
            DateTime time = DateTime.Now;             
            string format = "HH:mm:ss";    
            Console.WriteLine(time.ToString(format));  

            if (dataGridView.RowCount < 1)
                dataGridView.RowCount = 1;

            DataGridViewRow row = new DataGridViewRow();
            
            dataGridView.Rows.Add();
            dataGridView.Rows[w].Cells[0].Value = time.ToString(format);
            dataGridView.Rows[w].Cells[1].Value = (Math.Round((T_PT1000_red), 2));  
            dataGridView.Rows[w].Cells[2].Value = (Math.Round((T_I2C), 2));
            dataGridView.Rows[w].Cells[3].Value = (aktualni_stav_hmustku);
            dataGridView.Rows[w].Cells[4].Value = (T_pozadovana);
            //dataGridView.Rows[w].Cells[5].Value = (Math.Round((T_PT1000_green), 2));
            w++;      
        }

        private void prepinac()
            //prepina animaci
        {
            if (animation_prepinac == 1)    //zvetsovani
            {
                animation_prepinac = 0;
                b_info_DVG.Text = "info";
                b_info_graf.Text = "info";
                b_info_auto.Text = "info";
                b_info_rucn.Text = "info";
            }
            else //zmensovaní
            {
                animation_prepinac = 1;

            }

        }


        private void auto_kmity()
            //automaticke kmitani, použito pri vývoji
        {
            double moje_teplota;

            //vyber podle kmitat:
            moje_teplota = T_PT1000_red;    //bedna
            //moje_teplota = T_PT1000_green;  //chladič

            //hranice kmitani
            int dolni = 15;
            int horni = 30;

            switch (krok)
            {
                case 1: Hmustek_chlazeni();
                    if (moje_teplota >= dolni)
                        krok = 2;
                    break;
                case 2: Hmustek_ohrivani();
                    if (moje_teplota <= horni)
                        krok = 1;
                    break;
            }

        }

        /**************************************************************
        -------- TLAČÍTKA --------
         **************************************************************/
        private void b_start_Click(object sender, EventArgs e)
            //zapíná komunikaci s hardwarem
        {
            serialPort.BaudRate = 9600;
            try
            {
                serialPort.Open();
                textBox1.AppendText("serial port otevřen" + Environment.NewLine);
            }
            catch
            {
                serialPort.Close();
                textBox1.AppendText("serial port neotevřen" + Environment.NewLine);
                MessageBox.Show("Serial port nelze otevřít");
            }

            if (serialPort.IsOpen)
            {
               
                b_start.Visible = false;
                Hmustek_vypnuto();

                b_ohrivani.Enabled = true;
                b_chlazeni.Enabled = true;
                b_vypnuto.Enabled = true;
                b_aut_reg.Enabled = true;
                b_write_DGV.Enabled = true;
                

                timer_value_sender.Enabled = true;

                pB_uvod.Visible = false;
                comboBox_port.Visible = false;
                b_scan.Visible = false;
                timer_DGV_print.Enabled = true;
            }
        }

        private void b_stop_Click(object sender, EventArgs e)
            //původně ukončovalo komunikaci s hardwarem, ted je ukončována automaticky uzavřením programu
        {   
            Hmustek_vypnuto();
            timer_value_sender.Enabled = false;           

                b_stop.Visible = false;
                b_start.Visible = true;
                serialPort.Close();

                b_ohrivani.Enabled = false;
                b_chlazeni.Enabled = false;
                b_vypnuto.Enabled = false;
                b_aut_reg.Enabled = false;
                b_pause_DGV.Enabled = false;
                b_write_DGV.Enabled = false;
                comboBox_port.Enabled = true;
        }

        private void b_write_DGV_Click(object sender, EventArgs e)
            //spustí zápis hodnot do DGV
        {
            timer_DGV_print.Enabled = true;
            b_pause_DGV.Visible = true;
            b_write_DGV.Visible = false;     
        }

        private void b_pause_DGV_Click(object sender, EventArgs e)
            //přeruší zápis do DGV
        {
            timer_DGV_print.Enabled = false;
            b_write_DGV.Visible = true;
            b_pause_DGV.Visible = false;
        }

        private void b_aut_reg_Click(object sender, EventArgs e)
            //spustí automatickou regulaci
        {
            switch_autoreg = 2;
            b_aut_reg.Visible = false;
            b_aut_reg_stop.Visible = true;

            b_ohrivani.Enabled = false;
            b_chlazeni.Enabled = false;
            b_vypnuto.Enabled = false;

        }

        private void b_aut_reg_stop_Click(object sender, EventArgs e)
            //zastaví automatickou regulaci
        {
            switch_autoreg = 1;
            b_aut_reg_stop.Visible = false;
            b_aut_reg.Visible = true;
            Hmustek_vypnuto();

            b_ohrivani.Enabled = true;
            b_chlazeni.Enabled = true;
            b_vypnuto.Enabled = true;
        }

        private void b_mazani_DGV_Click(object sender, EventArgs e)
            //smaže hodnoty v DGV 
        {
            w = 0;
            dataGridView.RowCount = 0;
        }

        private void b_ohrivani_Click(object sender, EventArgs e)
        { 
            Hmustek_ohrivani();
        }

        private void b_chlazeni_Click(object sender, EventArgs e)
        {
            Hmustek_chlazeni();
        }

        private void b_vypnuto_Click(object sender, EventArgs e)
        {
            Hmustek_vypnuto();
        }
    
        private void vScrollBar_ValueChanged(object sender, EventArgs e)
            //přepočet nastavovaných hodnot na posuvníku automatické regulace
        {
            T_pozadovana = -vScrollBar.Value;
            l_T_pozadovana.Text = "Žádaná teplota " + T_pozadovana.ToString() + " °C";
        }

        private void b_info_DVG_Click(object sender, EventArgs e)
            //info tlačítko pro DVG
        {
            b_info_DVG.Text = "Tabulka ukládá informace o hodnotě v určitém čase, lze nastavit interval zápisu a zápis lze libovolně pozastavit nebo smazat. Export do tabulkového programu provedete zkopírováním.";

            Height_animation_final = 100;    //výška
            Width_animation_final = 180;    //šířka
            prepinac();
            pomocna_switch = 1;

            timer_animation.Enabled = true;
        }

        private void b_info_graf_Click(object sender, EventArgs e)
            //info tlačítko pro graf
        {
            b_info_graf.Text = "Graf zobrazuje vývoj reálné teploty v termoboxu za poslední 2 minuty";

            Height_animation_final = 60;    //výška
            Width_animation_final = 150;    //šířka
            prepinac();
            pomocna_switch = 2;

            timer_animation.Enabled = true;
        }

        private void b_info_auto_Click(object sender, EventArgs e)
            //info tlačítko pro autoregulaci
        {
            b_info_auto.Text = "Spuštění automatické regulace. Je možné nastavit rozsah 0 - 60 °C. Teplota v komoře je regulovaná s maximální odchylkou 2 °C.";

            Height_animation_final = 90;    //výška
            Width_animation_final = 150;    //šířka
            prepinac();
            pomocna_switch = 3;

            timer_animation.Enabled = true;
        }

        private void b_info_rucn_Click(object sender, EventArgs e)
            //info tlačítko pro rucni ovladani
        {
            b_info_rucn.Text = "Při ručním ovládání je možné dosáhnout i většího rozsahu teplot, není to však zaručeno vždy. Termobox má pojistku proti přehřátí a následnému roztavení.";

            Height_animation_final = 100;    //výška
            Width_animation_final = 150;    //šířka
            prepinac();
            pomocna_switch = 4;

            timer_animation.Enabled = true;
        }

        private void b_kmity_Click(object sender, EventArgs e)
        {
            switch_autoreg = 3;
        }

        private void b_auto_vylepsena_Click(object sender, EventArgs e)
        {
            switch_autoreg = 4;
        }

        private void b_zastav_regulace_Click(object sender, EventArgs e)
        {
            switch_autoreg = 1;
        }

        private void b_scan_Click(object sender, EventArgs e)
            //hledání portů
        {
            foreach (string str in SerialPort.GetPortNames())           // zde se zjisti, ktere porty jsou dostupne
            {
                comboBox_port.Items.Add(str);
            }
            if (comboBox_port.Items.Count > 0)
            {
                comboBox_port.SelectedIndex = 0;
                b_start.Enabled = true;
            }
            else
            {
                MessageBox.Show("Nelze najít žádný COM port");
                b_start.Enabled = false;
            }
        }

        /**************************************************************
        -------- TIMERY --------
         **************************************************************/
        private void timer_autoreg_Tick(object sender, EventArgs e)
            //krok pro vyhodnocování hodnot z autoregulace, každých 500ms
        {
            switch (switch_autoreg)
                {
                case 1:
                    break;
                case 2: auto_regulace();
                    break;
                case 3: auto_kmity();
                    break;

                }
        }
        private void timer_DGV_print_Tick(object sender, EventArgs e)
            //timer pro zápis hodnot do DGV pole
        {
            DGW_print();
        }
    
        private void timer_value_sender_Tick(object sender, EventArgs e)
            //timer pro odesílaní hodnot do HW
        {
            try
            {
                if(T_PT1000_green < 65)
                serialPort.Write("8 " + napajeni + " " + polarita + Environment.NewLine); //8-kod, 1-zapnuto, 1-ohřev
                else
                serialPort.Write("8 " + "0" + " " + polarita + Environment.NewLine); //8-kod, 1-zapnuto, 1-ohřev
               
                textBox1.AppendText("data odeslána" + Environment.NewLine);
            }
            catch
            {
                timer_value_sender.Enabled = false;
                serialPort.Close();
                textBox1.AppendText("data neodeslána" + Environment.NewLine);
                timer_DGV_print.Enabled = false;
                MessageBox.Show("Komunikace s termoboxem přerušena");
                
                b_stop.Visible = false;
                b_start.Visible = true;
                serialPort.Close();

                pB_uvod.Visible = true;
                comboBox_port.Visible = true;
                b_scan.Visible = true;
            }     
        }

        private void timer_animation_Tick(object sender, EventArgs e)
            //časovač pro rychlost animace tlačítek
        {


            int animation_speed = 15;

            if (animation_prepinac == 1)    //zvetsovani
            {
                if (Height_animation <= Height_animation_final)
                    Height_animation = Height_animation + animation_speed;
                if (Width_animation <= Width_animation_final)
                    Width_animation = Width_animation + animation_speed;

                if (Height_animation >= Height_animation_final && Width_animation >= Width_animation_final)
                    timer_animation.Enabled = false;
            }
            else //zmensovaní
            {
                if ((Height_animation - animation_speed) < 25)
                    Height_animation = 25;
                else
                    Height_animation = Height_animation - animation_speed;

                if ((Width_animation - animation_speed) < 40)
                    Width_animation = 40;
                else
                    Width_animation = Width_animation - animation_speed;


                if (Height_animation <= 25 && Width_animation <= 40)
                {
                    timer_animation.Enabled = false;

                }

            }

            switch (pomocna_switch)
            {
                case 1:
                    b_info_DVG.Height = Height_animation;
                    b_info_DVG.Width = Width_animation;

                    b_info_graf.Enabled = false;
                    b_info_auto.Enabled = false;
                    b_info_rucn.Enabled = false;
                    break;

                case 2:
                    b_info_graf.Height = Height_animation;
                    b_info_graf.Width = Width_animation;

                    b_info_DVG.Enabled = false;
                    b_info_auto.Enabled = false;
                    b_info_rucn.Enabled = false;
                    break;

                case 3:
                    b_info_auto.Height = Height_animation;
                    b_info_auto.Width = Width_animation;

                    b_info_DVG.Enabled = false;
                    b_info_graf.Enabled = false;
                    b_info_rucn.Enabled = false;

                    break;

                case 4:
                    b_info_rucn.Height = Height_animation;
                    b_info_rucn.Width = Width_animation;

                    b_info_DVG.Enabled = false;
                    b_info_graf.Enabled = false;
                    b_info_auto.Enabled = false;

                    break;
            }

            if (timer_animation.Enabled == false && animation_prepinac == 0)
            {
                b_info_graf.Enabled = true;
                b_info_DVG.Enabled = true;
                b_info_auto.Enabled = true;
                b_info_rucn.Enabled = true;
            }

        }

        /**************************************************************
        -------- NUMERIKY a COMBO_BOXY --------
         **************************************************************/
        private void numericUpDown1_ValueChanged_1(object sender, EventArgs e)
            // numericUpDown1_ValueChanged - mění rychlost zapisování hodnot do DGV pole
        {
            timer_DGV_print.Interval = Convert.ToInt16(numericUpDown1.Value) * 1000;

        }

        private void comboBox_port_SelectedIndexChanged(object sender, EventArgs e)
            //výběr a nastavení serial portu
        {
            serialPort.PortName = comboBox_port.Text;
        }
    }
}
