// Created with MonoDevelop
//
//    QuickStep: Acquire, view and identify spectra 
//    Copyright (C) 2018 Thomas Klose & Torsten Schache, Hiperscan GmbH Dresden, Germany
//
//    This program is free software: you can redistribute it and/or modify
//    it under the terms of the GNU General Public License as published by
//    the Free Software Foundation, either version 3 of the License, or
//    (at your option) any later version.
//
//    This program is distributed in the hope that it will be useful,
//    but WITHOUT ANY WARRANTY; without even the implied warranty of
//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//    GNU General Public License for more details.
//
//    You should have received a copy of the GNU General Public License
//    along with this program.  If not, see <http://www.gnu.org/licenses/>.


using System;
using System.Collections.Generic;
using Gtk;
using System.IO;


using Hiperscan.Unix;
using Hiperscan.I18n;
using Glade;
using Hiperscan.Spectroscopy;
using Gdk;
using Hiperscan.Spectroscopy.IdentModule;

namespace Hiperscan.Extensions.ApoIdent
{
    public enum BLindClassificationState
    {
        Init,
        DevicePollFinderButton,
        SampleTypeChanged,
        StartTranslectance,
        EndTransflectance,
        FailedTransflectance,
        StartMeasurement,
        EndMeasurement,
        FailedMeasurement,
        DeviceAfterExternalCalibration,
        DeviceAfterInternalCalibration,
    }

    public partial class BlindClassificationDialog
    {
        [Widget] Gtk.Label transflectance_label = null;
        [Widget] Gtk.Label measurement_label = null;
        [Widget] Gtk.Label result_label = null;

        [Widget] Gtk.Alignment transflectance_align = null;
        [Widget] Gtk.Alignment measurement_align = null;
        [Widget] Gtk.TreeView result_treeview = null;

        [Widget] Gtk.Label transflectance_advice_label = null;
        [Widget] Gtk.Label measurement_advice_label = null;

        [Widget] Gtk.Button measurement_button = null;

        public void UpdateGui(BLindClassificationState state)
        {
            this.IsUpdating = true;

            switch(state)
            {
                case BLindClassificationState.Init:
                    this.UpdateMeasurementSection();
                    this.UpdateResultSection();
                    this.Busy = false;
                    break;

                case BLindClassificationState.SampleTypeChanged:
                    this.UpdateMeasurementSection();
                    this.UpdateResultSection();
                    break;

                case BLindClassificationState.DevicePollFinderButton:
                    this.UpdateMeasurementSection();
                    break;

                case BLindClassificationState.StartTranslectance:
                    this.UpdateResultSection();
                    this.Busy = true;
                    break;

                case BLindClassificationState.EndTransflectance:
                    this.UpdateMeasurementSection();
                    this.Busy = false;
                    break;

                case BLindClassificationState.FailedTransflectance:
                    this.UpdateMeasurementSection();
                    this.Busy = false;
                    break;

                case BLindClassificationState.StartMeasurement:
                    this.UpdateResultSection();
                    this.Busy = true;
                    break;

                case BLindClassificationState.EndMeasurement:
                    this.UpdateMeasurementSection();
                    this.UpdateResultSection();
                    this.Busy = false;
                    break;

                case BLindClassificationState.FailedMeasurement:
                    this.UpdateMeasurementSection();
                    this.Busy = false;
                    break;

                case BLindClassificationState.DeviceAfterExternalCalibration:
                    this.UpdateMeasurementSection();
                    break;

                case BLindClassificationState.DeviceAfterInternalCalibration:
                    this.UpdateMeasurementSection();
                    break;

                default:
                    break;
            }

            this.IsUpdating = false;

            if (this.Busy == true)
                this.FinderWindow.host.ProcessEvents();
        }

        private void UpdateMeasurementSection()
        {
            bool active =
                this.FinderWindow.InitState == ServerDeviceState.Success &&
                    this.FinderWindow.Finder.IsDeviceReady;

            bool active_transflexion = active &&
                this.FinderWindow.Finder.Current.RecalibrationIsPending &&
                    this.IsFluid;

            this.transflectance_label.Sensitive = active_transflexion;
            this.transflectance_align.Sensitive = active_transflexion;
            this.transflectance_advice_label.Visible = active_transflexion;

            bool active_start_button = active &&
                this.FinderWindow.PollFinderButton;

            this.measurement_label.Sensitive = active_start_button;
            this.measurement_align.Sensitive = active_start_button;

            this.measurement_advice_label.Visible = active_start_button;

            if (active == true)
            {
                if (this.IsFluid == true)
                {
                    this.measurement_advice_label.Text = Catalog.GetString("Please use the same transflectance insert and sample container for the " +
                                                              "transflectance reference measurement and your substance measurement.");
                    this.measurement_advice_label.Visible = this.FinderWindow.Finder.Current.RecalibrationIsPending == false;
                }
                else
                {       
                    this.measurement_advice_label.Text = Catalog.GetString("Place the sample container with your substance on the device.");
                    this.measurement_advice_label.Visible = true;
                }
            }
        }
         
        private void UpdateResultSection()
        {
            if (this.CurrentProcessedSpectrum == null)
            {
                this.ResultStore.Clear();
                foreach (TreeViewColumn column in this.result_treeview.Columns)
                    column.Visible = false;
                this.result_label.Sensitive = false;
                    this.result_treeview.Sensitive = false;
            }
            else
            {
                foreach (TreeViewColumn column in this.result_treeview.Columns)
                    column.Visible = true;

                this.result_label.Sensitive = true;
                this.result_treeview.Sensitive = true;

                this.FillResult();
            }
        }

        public void FillResult()
        {
            Dictionary<string, ModelClassInfo> current = this.IsFluid ? this.Liquids : this.Solids;
            bool has_info = false;

            foreach (string class_name in this.Results.Keys)
            {
                ResultSet result = this.Results[class_name];
                if (result == null || result.PcaMatches.Count == 0)
                {                    
                    this.ResultStore.AppendValues(class_name, Catalog.GetString("Error"), false, null);
                    continue;
                }

                NormalizedPCAMatch match = result.PcaMatches[0];
                string classification_id = result.ClassificationId;

                string classification_name = Catalog.GetString("Not identified");
                if (result.ClassificationId != ResultSet.NO_ID && result.PositiveIdentified == true)
                    classification_name = match.ClassificationName;

                List<string> substance_names = null;

                if (result.PositiveIdentified == true)
                {
                    ModelClassInfo class_info = current[class_name];

                    foreach (ClassificationInfo classification_info in class_info.Classifications)
                    {

                        if (classification_info.Id == classification_id)
                        {
                            if (classification_info.Substances.Count > 1)
                            {
                                substance_names = new List<string>();
                                foreach (SubstanceInfo substance_info in classification_info.Substances)
                                    substance_names.Add(substance_info.PrimaryDefaultName);

                                has_info = true;
                            }

                            break;
                        }
                    }
                }

                this.ResultStore.AppendValues(class_name, classification_name, substance_names != null, substance_names);
                this.result_treeview.Columns[(int) Columns.Info].Visible = has_info;
            }
        }


        private void SetBusyState()
        {
            if (this.Busy == true)
            {
                this.SetWatchCursor();
            }
            else
            {
                this.FinderWindow.PollFinderButton = false;
                this.SetArrowCursor();
            }

            this.blind_classfication_dialog.Sensitive = this.Busy == false;
        }

        private void SetWatchCursor()
        {
            if (this.blind_classfication_dialog.IsRealized == false)
                return;

            this.blind_classfication_dialog.Sensitive = false;

            this.blind_classfication_dialog.GdkWindow.Cursor = new Gdk.Cursor(Gdk.CursorType.Watch);
        }

        private void SetArrowCursor()
        {
            if (this.blind_classfication_dialog.IsRealized == false)
                return;

            this.blind_classfication_dialog.Sensitive = true;
            this.blind_classfication_dialog.GdkWindow.Cursor = new Gdk.Cursor(Gdk.CursorType.Arrow);
        }

        public bool IsUpdating { get; set; } = false;
    }
}
