// UI.Properties.Spectrum.cs created with MonoDevelop
// User: klose at 15:43 04.02.2010
// CVS release: $Id: UI.Properties.Spectrum.cs,v 1.5 2011-04-19 12:36:59 klose Exp $
//
//    QuickStep: Acquire, view and identify spectra 
//    Copyright (C) 2009-2010  Thomas Klose, 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 System.Drawing;

using Glade;

using Gtk;

using Hiperscan.NPlotEngine.Overlay.Selection;
using Hiperscan.QuickStep.Dialog;
using Hiperscan.QuickStep.Figure;
using Hiperscan.Spectroscopy;
using Hiperscan.Unix;


namespace Hiperscan.QuickStep
{

    public partial class UserInterface
    {
        [Widget] Gtk.Fixed property_spectrum_fixed = null;

        [Widget] Gtk.Label spectrum_time_label           = null;
        [Widget] Gtk.Label spectrum_file_path_label      = null;
        [Widget] Gtk.Label spectrum_serial_label         = null;
        [Widget] Gtk.Label spectrum_dark_intensity_label = null;
        [Widget] Gtk.Label spectrum_average_label        = null;
        
        [Widget] Gtk.CheckButton spectrum_absorbance_checkbutton            = null;
        [Widget] Gtk.CheckButton spectrum_wavelength_correction_checkbutton = null;
        [Widget] Gtk.CheckButton spectrum_resolution_limit_checkbutton      = null;

        [Widget] Gtk.Button spectrum_properties_button = null;
        [Widget] Gtk.Button spectrum_edit_button = null;

        [Widget] Gtk.TextView spectrum_comment_text2 = null;
        
        [Widget] Gtk.ColorButton plot_colorbutton = null;
        [Widget] Gtk.SpinButton  plot_width_spin  = null;
        [Widget] Gtk.ComboBox    plot_style_combo = null;
        
        private List<Spectrum> current_spectra_config;

        private volatile bool updating_properties_spectrum = false;


        private void InitializePropertiesSpectrum()
        {
            this.spectrum_comment_text2.Buffer.Changed += (sender, e) =>
            {
                if (this.updating_properties_spectrum == false)
                    this.current_spectra_config[0].Comment = this.spectrum_comment_text2.Buffer.Text;
            };
            
            this.UpdatePropertiesSpectrum(null);
        }

        private void UpdatePropertiesSpectrum(List<Spectrum> spectra)
        {
            if (this.property_notebook.Page != 2)
                return;
            
            if (spectra == null || spectra.Count == 0)
            {
                this.current_object_label.Text = string.Empty;
                this.property_spectrum_fixed.Sensitive = false;
                this.spectrum_properties_button.Sensitive = false;
                this.spectrum_edit_button.Sensitive = false;
                return;
            }

            this.updating_properties_spectrum = true;
            
            if (spectra.Count == 1)
            {
                this.current_object_label.Text = $"({spectra[0].Label})";
                
                this.spectrum_time_label.Text = spectra[0].Timestamp.ToString();
                this.spectrum_time_label.Sensitive = true;
                this.spectrum_properties_button.Sensitive = true;
                this.spectrum_edit_button.Sensitive = true;
                
                if (spectra[0].FileInfo != null)
                {
                    this.spectrum_file_path_label.Text = spectra[0].FileInfo.FullName;
                    this.spectrum_file_path_label.TooltipText = spectra[0].FileInfo.FullName;
                    this.spectrum_file_path_label.HasTooltip = true;
                }
                else
                {
                    this.spectrum_file_path_label.Text = Catalog.GetString("n/a");
                    this.spectrum_file_path_label.HasTooltip = false;
                }
                this.spectrum_file_path_label.Sensitive = true;

                this.spectrum_absorbance_checkbutton.Active = spectra[0].HasAbsorbance;
                this.spectrum_absorbance_checkbutton.Inconsistent = false;
                
                this.spectrum_wavelength_correction_checkbutton.Active = spectra[0].HasWavelengthCorrection;
                this.spectrum_wavelength_correction_checkbutton.Inconsistent = false;

                this.spectrum_resolution_limit_checkbutton.Active = spectra[0].LimitBandwidth;
                this.spectrum_resolution_limit_checkbutton.Inconsistent = false;
                this.spectrum_resolution_limit_checkbutton.Sensitive = !spectra[0].IsPreview;

                if (spectra[0].HasDarkIntensity)
                    this.spectrum_dark_intensity_label.Text = spectra[0].DarkIntensity.Intensity.ToString("f4");
                else
                    this.spectrum_dark_intensity_label.Text = Catalog.GetString("n/a");
                this.spectrum_dark_intensity_label.Sensitive = true;

                if (string.IsNullOrEmpty(spectra[0].Serial))
                    this.spectrum_serial_label.Text = Catalog.GetString("n/a");
                else
                    this.spectrum_serial_label.Text = spectra[0].Serial;
                this.spectrum_serial_label.Sensitive = true;
                
                if (spectra[0].AverageCount > 0)
                    this.spectrum_average_label.Text = spectra[0].AverageCount.ToString();
                else
                    this.spectrum_average_label.Text = Catalog.GetString("n/a");
                this.spectrum_average_label.Sensitive = !spectra[0].IsPreview;

                this.spectrum_comment_text2.Buffer.Text = spectra[0].Comment;
                this.spectrum_comment_text2.Sensitive = !spectra[0].IsPreview;
            
                this.plot_colorbutton.Color = UserInterface.GdkColor(spectra[0].Color);
                this.plot_colorbutton.Sensitive = !spectra[0].IsPreview;
                
                this.plot_style_combo.Active = (int)spectra[0].LineStyle;
                this.plot_style_combo.Sensitive = true;
                
                this.plot_width_spin.Value = spectra[0].LineWidth;
                this.plot_width_spin.Sensitive = true;
            }
            else
            {
                this.current_object_label.Text = string.Empty;
                
                this.spectrum_time_label.Text = string.Empty;
                this.spectrum_time_label.Sensitive = false;
                this.spectrum_properties_button.Sensitive = false;
                this.spectrum_edit_button.Sensitive = false;
                
                bool active = spectra[0].HasAbsorbance;
                bool inconsistent = false;
                foreach (Spectrum spectrum in spectra)
                {
                    if (spectrum.HasAbsorbance != active)
                        inconsistent = true;
                }
                this.spectrum_absorbance_checkbutton.Active = active;
                this.spectrum_absorbance_checkbutton.Inconsistent = inconsistent;
                
                active = spectra[0].HasWavelengthCorrection;
                inconsistent = false;
                foreach (Spectrum spectrum in spectra)
                {
                    if (spectrum.HasWavelengthCorrection != active)
                        inconsistent = spectrum.HasWavelengthCorrection;
                }
                this.spectrum_wavelength_correction_checkbutton.Active = active;
                this.spectrum_wavelength_correction_checkbutton.Inconsistent = inconsistent;
                
                active = spectra[0].LimitBandwidth;
                inconsistent = false;
                foreach (Spectrum spectrum in spectra)
                {
                    if (spectrum.LimitBandwidth != active)
                        inconsistent = true;
                }
                this.spectrum_resolution_limit_checkbutton.Active = active;
                this.spectrum_resolution_limit_checkbutton.Inconsistent = inconsistent;
                
                
                string serial = spectra[0].Serial;
                inconsistent = false;
                foreach (Spectrum spectrum in spectra)
                {
                    if (spectrum.Serial != serial)
                        inconsistent = true;
                }

                if (inconsistent)
                {
                    this.spectrum_serial_label.Text = string.Empty;
                    this.spectrum_serial_label.Sensitive = false;
                }
                else
                {
                    this.spectrum_serial_label.Text = serial;
                    this.spectrum_serial_label.Sensitive = true;
                }

                int average = spectra[0].AverageCount;
                inconsistent = false;
                foreach (Spectrum spectrum in spectra)
                {
                    if (spectrum.AverageCount != average)
                        inconsistent = true;
                }
                if (inconsistent)
                {
                    this.spectrum_average_label.Text = string.Empty;
                    this.spectrum_average_label.Sensitive = false;
                }
                else
                {
                    if (average > 0)
                        this.spectrum_average_label.Text = average.ToString();
                    else
                        this.spectrum_average_label.Text = Catalog.GetString("n/a");
                    this.spectrum_average_label.Sensitive = true;
                }

                this.spectrum_comment_text2.Buffer.Text = spectra[0].Comment;
                this.spectrum_comment_text2.Sensitive = false;
            
                inconsistent = false;
                Color color = spectra[0].Color;
                foreach (Spectrum spectrum in spectra)
                {
                    if (spectrum.Color != color)
                        inconsistent = true;
                }
                this.plot_colorbutton.Color = inconsistent ? Gdk.Color.Zero : UserInterface.GdkColor(color);
                this.plot_colorbutton.Sensitive = true;
                
                LineStyle style = spectra[0].LineStyle;
                this.plot_style_combo.Active = (int)style;
                this.plot_style_combo.Sensitive = true;

                float width = spectra[0].LineWidth;
                this.plot_width_spin.Value = width;
                this.plot_width_spin.Sensitive = true;
            }
            this.updating_properties_spectrum = false;
            this.property_spectrum_fixed.Sensitive = true;

            this.current_spectra_config = spectra;
        }
        
        public static Gdk.Color GdkColor(Color c)
        {
            return new Gdk.Color(c.R, c.G, c.B); 
        }
        
        public static Color DrawingColor(Gdk.Color c)
        {
            return Color.FromArgb(c.Red >> 8, c.Green >> 8, c.Blue >> 8);
        }
        
        internal void OnSpectrumPropertiesButtonClicked(object o, EventArgs e)
        {
            Spectrum spectrum = this.plot_tv.GetSelectedSpectra()[0];

            string msg = Catalog.GetString("<b>Spectrum Properties</b>\n\n") +
                         $"<span font_family=\"monospace\">{spectrum.ToString()}</span>";

            var dialog = new Dialog.MessageDialog(Instance.MainWindow,
                                                  DialogFlags.Modal,
                                                  MessageType.Info,
                                                  ButtonsType.Ok,
                                                  msg);

            HBox hbox = dialog.VBox.Children[0] as HBox;
            VBox vbox = hbox.Children[1] as VBox;
            Label label = vbox.Children[0] as Label;
            label.Wrap = false;
            Console.WriteLine(msg);
            dialog.Run();
            dialog.Destroy();
        }

        internal void OnSpectrumEditButtonClicked(object o, EventArgs e)
        {
            Spectrum spectrum = this.plot_tv.GetSelectedSpectra()[0];

            if (!spectrum.IsFromFile ||
                spectrum.FileInfo == null ||
                string.IsNullOrEmpty(spectrum.FileInfo.FullName))
            {
                this.ShowInfoMessage(Instance.MainWindow,
                                     Catalog.GetString("Cannot open text editor: The spectrum must be " +
                                                       "available (saved) at a local hard drive."));
                return;
            }

            UserInterface.OpenTextEditor(Instance.MainWindow, spectrum.FileInfo.FullName);
        }

        internal void OnSpectrumResolutionLimitToggled(object o, EventArgs e)
        {
            this.spectrum_resolution_limit_checkbutton.Inconsistent = false;
            this.ApplyResolutionLimit();
        }
        
        internal void OnPlotColorbuttonSet(object o, EventArgs e)
        {
            this.ApplyColor();
        }
        
        internal void OnPlotStyleComboChanged(object o, EventArgs e)
        {
            this.ApplyLineStyle();
        }
        
        internal void OnPlotWidthSpinValueChanged(object o, EventArgs e)
        {
            this.ApplyLineWidth();
        }

        internal void OnSpectrumPropertyChanged(object o, System.EventArgs e)
        {
        }
        
        private void ApplyColor()
        {
            if (this.updating_properties_spectrum)
                return;

            if (this.current_spectra_config.Count == 1)
            {
                if (this.current_spectra_config[0].Color.ToArgb() != UserInterface.DrawingColor(this.plot_colorbutton.Color).ToArgb())
                    this.current_spectra_config[0].Color = UserInterface.DrawingColor(this.plot_colorbutton.Color);
            }
            else
            {
                foreach (Spectrum spectrum in this.current_spectra_config)
                {
                    if (this.plot_colorbutton.Sensitive &&
                        spectrum.Color.ToArgb() != UserInterface.DrawingColor(this.plot_colorbutton.Color).ToArgb())
                    {
                        spectrum.Color = UserInterface.DrawingColor(this.plot_colorbutton.Color);
                    }
                }
            }
            this.UpdatePlot(this.plot_info_list.Current);
        }
        
        private void ApplyResolutionLimit()
        {
            if (this.updating_properties_spectrum)
                return;
            
            if (this.current_spectra_config.Count == 1)
            {
                this.current_spectra_config[0].LimitBandwidth = this.spectrum_resolution_limit_checkbutton.Active;
            }
            else
            {
                foreach (Spectrum spectrum in this.current_spectra_config)
                {
                    if (this.spectrum_resolution_limit_checkbutton.Inconsistent)
                        continue;

                    spectrum.LimitBandwidth = this.spectrum_resolution_limit_checkbutton.Active;
                }
            }
            this.UpdatePlot(this.plot_info_list.Current);
        }
        
        private void ApplyComment()
        {
            if (this.updating_properties_spectrum)
                return;
            
            if (this.current_spectra_config.Count == 1)
            {
                this.current_spectra_config[0].Comment = this.spectrum_comment_text2.Buffer.Text;
            }
            else
            {
                foreach (Spectrum spectrum in this.current_spectra_config)
                {
                    if (this.plot_colorbutton.Sensitive &&
                        spectrum.Color.ToArgb() != UserInterface.DrawingColor(this.plot_colorbutton.Color).ToArgb())
                    {
                        spectrum.Color = UserInterface.DrawingColor(this.plot_colorbutton.Color);
                    }
                }
            }
            this.UpdatePlot(this.plot_info_list.Current);
        }
        
        private void ApplyLineStyle()
        {
            if (this.updating_properties_spectrum)
                return;

            if (this.current_spectra_config.Count == 1)
            {
                if (this.current_spectra_config[0].LineStyle != (LineStyle)this.plot_style_combo.Active)
                    this.current_spectra_config[0].LineStyle = (LineStyle)this.plot_style_combo.Active;
            }
            else
            {
                foreach (Spectrum spectrum in this.current_spectra_config)
                {
                    if (this.plot_style_combo.Sensitive &&
                        spectrum.LineStyle != (LineStyle)this.plot_style_combo.Active)
                    {
                        spectrum.LineStyle = (LineStyle)this.plot_style_combo.Active;
                    }
                }
            }
            this.UpdatePlot(this.plot_info_list.Current);
        }

        private void ApplyLineWidth()
        {
            if (this.updating_properties_spectrum)
                return;

            if (this.current_spectra_config.Count == 1)
            {
                if (Math.Abs(this.current_spectra_config[0].LineWidth - (float)this.plot_width_spin.Value) > EPSILON)
                    this.current_spectra_config[0].LineWidth = (float)this.plot_width_spin.Value;
            }
            else
            {
                foreach (Spectrum spectrum in this.current_spectra_config)
                {
                    if (this.plot_width_spin.Sensitive &&
                        Math.Abs(spectrum.LineWidth - (float)this.plot_width_spin.Value) > EPSILON)
                    {
                        spectrum.LineWidth = (float)this.plot_width_spin.Value;
                    }
                }
            }
            this.UpdatePlot(this.plot_info_list.Current);
        }

        private void OnPlotTvSpectrumDoubleClicked(Spectrum spectrum)
        {
            this.PropertyType = Config.PropertyType.Spectrum;
            this.PropertyEditorVisible = true;
            
            this.SetCurrentFigure(spectrum.PlotId);
        }
        
        private void OnPlotTvFigureDoubleClicked(PlotInfo plot_info)
        {
            this.SetCurrentFigure(plot_info.UUID);
        }
        
        private void SetCurrentFigure(string uuid)
        {
            int found = -1;
            for (int ix = 0; ix < this.plot_info_list.Count; ++ix)
            {
                if (uuid == this.plot_info_list[ix].UUID)
                    found = ix;
            }
            
            if (found > -1)
                this.plot_notebook.CurrentPage = found;
        }
        
        private void OnPlotTvSelectionChanged(List<PlotInfo> plot_infos, List<Spectrum> spectra, bool clicked)
        {
            this.ScrolledPlot.Plot.DataSetSelections.Clear();

            if (clicked)
                this.PropertyType = Config.PropertyType.Spectrum;
            
            if (spectra.Count < 1)
                this.UpdatePropertiesSpectrum(null);
            else
                this.UpdatePropertiesSpectrum(spectra);

            bool visible = false;
            bool not_visible = false;
            bool in_current_plot = true;
            foreach (Spectrum spectrum in spectra)
            {
                try
                {
                    if (spectrum.PlotId == this.plot_info_list.Current.UUID)
                        this.ScrolledPlot.Plot.DataSetSelections.Add(new DataSetSelection(this.ScrolledPlot.Plot, spectrum));
                    else
                        in_current_plot = false;
                }
                catch (KeyNotFoundException)
                {
                    // this happens if the selected spectrum cannot be displayed in the current plot type
                    continue;
                }
                
                if (spectrum.IsVisible)
                {
                    if (visible == false && spectrum.IsPreview == false)
                        visible = true;
                }
                else 
                {
                    not_visible = true;
                }
            }
            
            this.ScrolledPlot.Plot.AsyncRefresh(true);

            this.plot_tv_save_button.Sensitive       = visible;
            this.plot_tv_copy_button.Sensitive       = visible && in_current_plot;
            this.plot_tv_delete_button.Sensitive     = visible;
            this.plot_tv_auto_color_button.Sensitive = visible || plot_infos.Count > 0;
            this.plot_tv_remove_button.Sensitive     = visible;
            this.plot_tv_add_button.Sensitive        = not_visible;

            if (this.ScrolledPlot.Plot.DataSetSelections.Count == 0)
                this.plot_tv_auto_color_button.Sensitive = plot_infos.Count > 0;

            this.OnPlotTvSpectrumSelectionPositionChanged(spectra);
        }
        
        private void OnPlotTvSpectrumSelectionPositionChanged(List<Spectrum> spectra)
        {
            bool not_preview = spectra.Count == 1 && !spectra[0].IsPreview;
            this.plot_tv_move_up_button.Sensitive   = not_preview && !this.plot_tv.IsFirst(spectra[0]);
            this.plot_tv_move_down_button.Sensitive = not_preview && !this.plot_tv.IsLast(spectra[0]);
        }

        public static void OpenTextEditor(Window parent, string path)
        {
            System.Diagnostics.Process process = new System.Diagnostics.Process();

            process.StartInfo.CreateNoWindow = true;
            process.StartInfo.UseShellExecute = false;

#pragma warning disable RECS0022
            if (MainClass.OS == MainClass.OSType.Windows)
            {
                // start notepad
                process.StartInfo.Arguments = $"\"{path}\"";
                process.StartInfo.FileName = "notepad.exe";

                try
                {
                    process.Start();
                    return;
                }
                catch { }
            }
            else
            {
                // try to start one of Linux' text editors
                process.StartInfo.Arguments = $"\"{path}\"";
                string[] editors = { "gedit", "kwrite", "kate"};
                
                foreach (string editor in editors)
                {
                    process.StartInfo.FileName = editor;
                    try
                    {
                        process.Start();
                        return;
                    }
                    catch { }
                }
            }
#pragma warning restore RECS0022

            InfoMessageDialog.Show(parent, Catalog.GetString("Cannot start text editor."));
        }
    }
}