using System;
using System.ComponentModel;
using System.Linq;
using System.Text.RegularExpressions;
using System.Windows.Forms;

using LabelerCore.Data;
using LabelerCore.Model.Classifiers;

namespace Labeler
{
    public partial class KMeansSetupForm : Form
    {
        private KMeans _kmeans;
        private double[][] _X;
        private VehicleInfo[] _samples;

      
        public KMeansSetupForm(double[][] X, VehicleInfo[] samples)
        {
            InitializeComponent();
            _X = X;
            _samples = samples;
        }

        private void runButton_Click(object sender, EventArgs e)
        {
            if (!backgroundWorker.IsBusy) {
                okButton.Enabled = false;
                backgroundWorker.RunWorkerAsync();
            }
            else
                MessageBox.Show("Already running!");
        }

        private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            
            Match match = Regex.Match(nClustersTextBox.Text, @"^\d+-\d+$");
            int nClustersFrom = -1;
            int nClustersTo = -1;
            if(match.Success)
            {
                string s = nClustersTextBox.Text;
                nClustersFrom = int.Parse(string.Join("", s.Take(s.IndexOf("-"))));
                nClustersTo = int.Parse(string.Join("", s.Skip(s.IndexOf("-") + 1)));

                inertiaChart.Invoke(new Action(() => { inertiaChart.Series[0].Points.Clear(); }));
                for (int nClusters = nClustersFrom; nClusters < nClustersTo; nClusters++)
                {
                    _kmeans = new KMeans(nClusters: nClusters,
                                         nInit: int.Parse(nInitTextBox.Text),
                                         maxIter: int.Parse(iterationsTextBox.Text),
                                         tolerance: double.Parse(toleranceTextBox.Text));
                    _kmeans.ProgressChanged += KMeansProgressChangedHandler_ProgressChanged;
                    _kmeans.Fit(_X, null);
                    inertiaChart.Invoke(new Action(() => { inertiaChart.Series[0].Points.AddXY(nClusters, _kmeans.Inertia); }));
                }
                //_kmeans = null;
            }
            else
            {
                int nClusters = int.Parse(nClustersTextBox.Text);
                _kmeans =new KMeans(nClusters: nClusters,
                                nInit: int.Parse(nInitTextBox.Text),
                                maxIter: int.Parse(iterationsTextBox.Text));
                _kmeans.ProgressChanged += KMeansProgressChangedHandler_ProgressChanged;
                _kmeans.Fit(_X, null);
            }

        }

        private void backgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            progressBar1.Value = e.ProgressPercentage;
        }

        private void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            inertiaLabel.Text = "Finished, inertia: " + _kmeans.Inertia.ToString("F3");
            okButton.Enabled = true;
        }

        private void KMeansProgressChangedHandler_ProgressChanged(double progress)
        {
            backgroundWorker.ReportProgress((int)progress);
        }

        private void okButton_Click(object sender, EventArgs e)
        {
            if (_kmeans == null)
                MessageBox.Show("To apply clustering enter single number of clusters");
            else
            {
                int[] y = _kmeans.Predict(_X);
                for (int i = 0; i < y.Length; i++)
                    _samples[i].cluster = y[i];
                this.DialogResult = DialogResult.OK;
                Close();
            }
        }

        private void KMeansSetupForm_FormClosed(object sender, FormClosedEventArgs e)
        {
            if(_kmeans != null)
                this.DialogResult = System.Windows.Forms.DialogResult.OK;

        }

        private void nClustersTextBox_Validating(object sender, CancelEventArgs e)
        {
            int dummy;
            if (!int.TryParse(nClustersTextBox.Text, out dummy) &&
                !Regex.Match(nClustersTextBox.Text, @"^\d+-\d+$").Success)
            {
                MessageBox.Show("Number of clusters should be positive integer or range in format(d-d)");
                e.Cancel = true;
            }
            if (dummy < 1 && !Regex.Match(nClustersTextBox.Text, @"^\d+-\d+$").Success)
            {
                MessageBox.Show("Number of clusters should be positive integer or range in format(d-d)");
                e.Cancel = true;
            }

        }

        private void iterationsTextBox_Validating(object sender, CancelEventArgs e)
        {
            int dummy;
            if (!int.TryParse(iterationsTextBox.Text, out dummy))
            {
                MessageBox.Show("Number of iterations should be positive integer");
                e.Cancel = true;
            }
            if (dummy < 1)
            {
                MessageBox.Show("Number of iterations should be positive integer");
                e.Cancel = true;
            }
        }

        private void nInitTextBox_Validating(object sender, CancelEventArgs e)
        {
            int dummy;
            if (!int.TryParse(nInitTextBox.Text, out dummy))
            {
                MessageBox.Show("Number of initializations should be positive integer");
                e.Cancel = true;
            }
            if (dummy < 1)
            {
                MessageBox.Show("Number of initializations should be positive integer");
                e.Cancel = true;
            }
        }

        private void toleranceTextBox_Validating(object sender, CancelEventArgs e)
        {
            double dummy;
            if (!double.TryParse(toleranceTextBox.Text, out dummy))
            {
                MessageBox.Show("Tolerance should be positive float");
                e.Cancel = true;
            }
        }





    }
}
