using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace Shlukova_Analyza_BP
{
    public partial class Form3 : Form
    {
        progressReporter progr;
        ucZarizeni zarizeniInstance;
        ucOblasti oblastiInstance;
        ucShluky shlukyInstance;
        Form4 forma;
        Form1 datovaForma;
        System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
        private double[][] nactenaData;
        private bool[] zarizeni;
        private int[] oblasti;
        private ZpracovaniTxt zpracovanyTxt;
        private Promenne promenne;
        private string fileName;
        private int typOblasti, iter, min, max;
        private int metoda, vzdalenost;
        private double konstantaM;
        public Form3()
        {
            InitializeComponent();
            zarizeniInstance = ucZarizeni.Instance;
            oblastiInstance = ucOblasti.Instance;
            shlukyInstance = ucShluky.Instance;
            zarizeniInstance.Location = new Point(10, 15);
            oblastiInstance.Location = new Point(180, 20);
            shlukyInstance.Location = new Point(180, 90);
            tabPageHier.Controls.Add(zarizeniInstance);
            tabPageHier.Controls.Add(oblastiInstance);
            comboBoxMetoda.SelectedIndex = 0;
            comboBoxVzdalenost.SelectedIndex = 0;
        }
        //====================//
        //                    //
        //      NAČÍTÁNÍ      //
        //                    //
        //====================//
        private void btnNacist_Click(object sender, EventArgs e)
        {
            openFileDialog.Filter = "Text Files (.txt)|*.txt|All Files (*.*)|*.*";
            openFileDialog.FilterIndex = 1;
            if (openFileDialog.ShowDialog() == DialogResult.OK)
            {
                fileName = openFileDialog.FileName;
                forma = new Form4();
                Enabled = false;
                forma.Show();
                forma.UpdateProgressBar();
                forma.PostupString("Načítám soubor");
                forma.nacitani();
                backgroundWorkerNacitani.RunWorkerAsync();
            }
        }
        private void backgroundWorkerNacitani_DoWork(object sender, DoWorkEventArgs e)
        {
            zpracovanyTxt = new ZpracovaniTxt(fileName);           
        }
        private void backgroundWorkerNacitani_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            adresaLbl.Text = fileName;
            forma.Hotovo();
            Enabled = true;
        }
        //====================//
        //                    //
        //       K-MEANS      //
        //                    //
        //====================//
        private void btnShlukovatKMeans_Click(object sender, EventArgs e)
        {
            if (zpracovanyTxt != null)
            {
                min = shlukyInstance.MinShluku;
                max = shlukyInstance.MaxShluku;
                zarizeni = zarizeniInstance.BoolTyp;
                oblasti = oblastiInstance.Oblasti;
                typOblasti = oblastiInstance.TypOblasti;
                iter = shlukyInstance.Iteraci;
                progr = reportujUcelFceKMeans;
                nacitaniForm();
                backgroundWorkerKMeans.RunWorkerAsync(); 
            }
            else if (nactenaData != null)
            {
                min = shlukyInstance.MinShluku;
                max = shlukyInstance.MaxShluku;
                iter = shlukyInstance.Iteraci;
                progr = reportujUcelFceKMeans;
                nacitaniForm();
                backgroundWorkerKMeans.RunWorkerAsync();
            }
            else 
            {
                MessageBox.Show("Není načtený žádný soubor!");
            }
        }
        private void backgroundWorkerKMeans_DoWork(object sender, DoWorkEventArgs e)
        {
            string cas = "";
            List<SAKMeans> kMeansList = new List<SAKMeans>();
            promenne = dejPromenne();
            backgroundWorkerKMeans.ReportProgress(0,"Provádím shlukování");
            for (int i = 0; i < max - min + 1; i++)
            {
                backgroundWorkerKMeans.ReportProgress(0, "Provádím shlukování");
                sw.Start();
                kMeansList.Add(cyklusKMeans(iter, min + i));
                sw.Stop();
                cas += sw.Elapsed + " \r\n";
                sw.Reset();
                backgroundWorkerKMeans.ReportProgress(min + i, kMeansList[i].siluety.PrumerVsech);
                backgroundWorkerKMeans.ReportProgress(0, "Kopíruji výsledky do Excelu");
                ExcelVypis excelTest = new ExcelVypis(kMeansList[i]);
            }
        }
        private Promenne dejPromenne()
        {
            if (zpracovanyTxt != null)
            {
                if (typOblasti == 0)
                {
                    return promenne = new Promenne(zpracovanyTxt.SeznamScenaru, zarizeni);
                }
                else if (typOblasti == 1)
                {
                    return promenne = new Promenne(zpracovanyTxt.SeznamScenaru, zarizeni, oblasti, true);
                }
                else
                {
                    return promenne = new Promenne(zpracovanyTxt.SeznamScenaru, zarizeni, oblasti, false);
                }
            }
            else
            {
                return promenne = new Promenne(nactenaData);
            }
            
        }
        private void backgroundWorkerKMeans_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            forma.Hotovo();
            Enabled = true;
        }
        private void backgroundWorkerKMeans_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            if (e.ProgressPercentage != 0 && e.UserState is double)
            {
                string str = string.Format("Průměrná hodnota siluety pro {0} shluků: s = {1}", e.ProgressPercentage, e.UserState);
                forma.reportRadek(str);
            }
            else if (e.UserState is int)
            {
                forma.ucelFce("Aktuální hodnota účelové funkce: " + Convert.ToString(e.UserState));
            }
            else if (e.UserState is string)
            {
                forma.PostupString(Convert.ToString(e.UserState));
            }
            else
            {
                forma.iterace(e.ProgressPercentage + "/" + iter);
            }
        }
        private SAKMeans cyklusKMeans(int iter, int k)
        {
            List<SAKMeans> kMeansList = new List<SAKMeans>();
            double[] minHodnoty = new double[iter];
            double minHodnota = 0;
            for (int i = 0; i < iter; i++)
            {
                backgroundWorkerKMeans.ReportProgress(i + 1);
                kMeansList.Add(new SAKMeans(promenne.DatovaMatice, promenne.MaticeVzdalenostiPrvky, k, progr));
                kMeansList[i].shlukuj();
                minHodnoty[i] = kMeansList[i].ucelFce();
            }
            minHodnota = minHodnoty[0];
            int finalni = 0;
            for (int i = 1; i < minHodnoty.Length; i++) // Vybírá nejlepší hodnotu účelové funkce
            {
                if (minHodnoty[i] < minHodnota)
                {
                    finalni = i;
                    minHodnota = minHodnoty[i];
                }
            }
            kMeansList[finalni].postprocess();
            return kMeansList[finalni];
        }
        private void reportujUcelFceKMeans(int x)
        {
            backgroundWorkerKMeans.ReportProgress(0, x);
        }
        //====================//
        //                    //
        //   FUZZY C-MEANS    //
        //                    //
        //====================//
        private SAFuzzy cyklusFuzzy(int k)
        {
            List <SAFuzzy> fuzzylist = new List<SAFuzzy>();
            double[] minHodnoty = new double[iter];
            double minHodnota = 0;
            for (int i = 0; i < iter; i++)
            {
                backgroundWorkerFCM.ReportProgress(i + 1);
                fuzzylist.Add(new SAFuzzy(promenne.DatovaMatice, promenne.MaticeVzdalenostiPrvky, k, konstantaM, progr));
                fuzzylist[i].shlukuj(0.0005);
                minHodnoty[i] = fuzzylist[i].ucelFce();
            }
            minHodnota = minHodnoty[0];
            int finalni = 0;
            for (int i = 1; i < minHodnoty.Length; i++) // Vybírá nejlepší hodnotu účelové funkce
            {
                if (minHodnoty[i] < minHodnota)
                {
                    finalni = i;
                    minHodnota = minHodnoty[i];
                }
            }
            fuzzylist[finalni].postproces();
            return fuzzylist[finalni];
        }
        private void btnShlukovatFCM_Click(object sender, EventArgs e)
        {
            if (zpracovanyTxt != null)
            {
                konstantaM = Convert.ToDouble(textBoxM.Text);
                min = shlukyInstance.MinShluku;
                max = shlukyInstance.MaxShluku;
                zarizeni = zarizeniInstance.BoolTyp;
                oblasti = oblastiInstance.Oblasti;
                typOblasti = oblastiInstance.TypOblasti;
                iter = shlukyInstance.Iteraci;
                progr = reportujUcelFceFCM;
                nacitaniForm();
                backgroundWorkerFCM.RunWorkerAsync(); 
            }
            else
            {
                MessageBox.Show("Není náčtený žádný soubor");
            }
        }
        private void backgroundWorkerFCM_DoWork(object sender, DoWorkEventArgs e)
        {
            List<SAFuzzy> fuzzyList = new List<SAFuzzy>();
            promenne = dejPromenne();
            string cas = "";
            for (int i = 0; i < max - min + 1; i++)
            {
                backgroundWorkerFCM.ReportProgress(0, "Provádím shlukování");
                sw.Start();
                fuzzyList.Add(cyklusFuzzy(min + i));
                sw.Stop();
                cas += sw.Elapsed + "\r\n"; sw.Reset();
                backgroundWorkerFCM.ReportProgress(min + i, fuzzyList[i].siluety.PrumerVsech);
                backgroundWorkerFCM.ReportProgress(0, "Kopíruji výsledky do Excelu");
                ExcelVypis excelTest = new ExcelVypis(fuzzyList[i]);
            }
        }
        private void backgroundWorkerFCM_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            if (e.ProgressPercentage != 0 && e.UserState is double)
            {
                string str = string.Format("Průměrná hodnota siluety pro {0} shluků: s = {1}", e.ProgressPercentage, e.UserState);
                forma.reportRadek(str);
            }
            else if (e.UserState is int)
            {
                forma.ucelFce("Aktuální hodnota účelové funkce: " + Convert.ToString(e.UserState));
            }
            else if (e.UserState is string)
            {
                forma.PostupString(Convert.ToString(e.UserState));
            }
            else
            {
                forma.iterace(e.ProgressPercentage + "/" + iter);
            }
        }
        private void backgroundWorkerFCM_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            forma.Hotovo();
            Enabled = true;
        }
        private void reportujUcelFceFCM(int x)
        {
            backgroundWorkerFCM.ReportProgress(0, x);
        }
        //====================//
        //                    //
        //    HIERARCHICKÉ    //
        //                    //
        //====================//
        private void backgroundWorkerHier_DoWork(object sender, DoWorkEventArgs e)
        {
            backgroundWorkerHier.ReportProgress(0, "Počítám matici vzdáleností");
            promenne = dejPromenne();
            SAHier hier = new SAHier(promenne.DatovaMatice, vzdalenost, metoda, progr, min, max);
            backgroundWorkerHier.ReportProgress(0, "Kopíruji výsledky do Excelu");
            for (int i = 0; i <= max-min; i++)
            {
                ExcelVypis excelTest = new ExcelVypis(hier, i);
            }   
        }
        private void btnShlukovatHier_Click(object sender, EventArgs e)
        {
            // vytvořit progressor
            metoda = comboBoxMetoda.SelectedIndex;
            vzdalenost = comboBoxVzdalenost.SelectedIndex;
            if (zpracovanyTxt != null)
            {
                progr = reportujHier;
                zpracujNastaveni();
                nacitaniForm();
                forma.hier();
                backgroundWorkerHier.RunWorkerAsync();
            }
            else if (nactenaData != null)
            {
                MessageBox.Show("Nech mě!");
            }
            else
            {
                MessageBox.Show("Není načtený žádný soubor!");
            }
        }
        private void backgroundWorkerHier_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            if (e.UserState is string)
            {
                forma.PostupString((string)e.UserState);
                /*if ((string)e.UserState == "Provádím shlukování")
                {
                    forma.hier();
                }*/
                if ((string)e.UserState == "Kopíruji výsledky do Excelu")
                {
                    forma.UpdateProgressBar();
                }
            }
            else
            {
                forma.reportProcenta(e.ProgressPercentage);
                if (e.ProgressPercentage == 100)
                {
                    forma.PostupString("Provádím shlukování");
                }
            }
        }
        private void backgroundWorkerHier_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            forma.Hotovo();
            Enabled = true;
        }
        private void reportujHier(int x)
        {
            backgroundWorkerHier.ReportProgress(x,0);
        }
        //====================//
        //                    //
        //        MENU        //
        //                    //
        //====================//
        private void tabControl1_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (tabControl1.SelectedIndex == 0)
            {
                tabPageHier.Controls.Add(zarizeniInstance);
                tabPageHier.Controls.Add(oblastiInstance);
            }
            if (tabControl1.SelectedIndex == 1)
            {
                tabPageKMeans.Controls.Add(zarizeniInstance);
                tabPageKMeans.Controls.Add(oblastiInstance);
                tabPageKMeans.Controls.Add(shlukyInstance);
            }
            if (tabControl1.SelectedIndex == 2)
            {
                tabPageFCM.Controls.Add(zarizeniInstance);
                tabPageFCM.Controls.Add(oblastiInstance);
                tabPageFCM.Controls.Add(shlukyInstance);
            }
        }
        private void numericMin_ValueChanged(object sender, EventArgs e)
        {
            if (numericMin.Value > numericMax.Value)
            {
                numericMax.Value = numericMin.Value;
            }
        }
        private void numericMax_ValueChanged(object sender, EventArgs e)
        {
            if (numericMin.Value > numericMax.Value)
            {
                numericMin.Value = numericMax.Value;
            }
        }
        private void nacitaniForm()
        {
            forma = new Form4();
            Enabled = false;
            forma.PostupString("Počítám matici vzdálenosti");
            forma.Show();
            forma.UpdateProgressBar();
        }
        //====================//
        //                    //
        //   RUČNÍ NAČÍTÁNÍ   //
        //                    //
        //====================//
        private void button1_Click(object sender, EventArgs e)
        {
            datovaForma = new Form1(this);
            datovaForma.Show();
        }
        public double[][] NactenaData
        {
            set
            {
                nactenaData = value;
            }
        }
        private void zpracujNastaveni()
        {
            if (tabControl1.SelectedIndex == 0)
            {
                min = (int)numericMin.Value;
                max = (int)numericMax.Value;
            }
            else
            {
                min = shlukyInstance.MinShluku;
                max = shlukyInstance.MaxShluku;
            }
            zarizeni = zarizeniInstance.BoolTyp;
            oblasti = oblastiInstance.Oblasti;
            typOblasti = oblastiInstance.TypOblasti;
        }
    }
}
