// Dialogs.cs created with MonoDevelop
// User: klose at 18:10 12.03.2009
// CVS release: $Id: Dialogs.cs,v 1.25 2011-04-19 12:36:58 klose Exp $
//
//    QuickStep: Acquire, view and identify spectra 
//    Copyright (C) 2009  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.IO;
using System.Threading;

using Gtk;

using Hiperscan.QuickStep.Figure;
using Hiperscan.Spectroscopy;
using Hiperscan.Spectroscopy.IO;
using Hiperscan.Unix;


namespace Hiperscan.QuickStep.Dialog
{

    internal class ExtractedDataDialog : Gtk.Dialog 
    {
        private readonly int extraction_id;
        private bool run_dialog = false;
        private readonly DirectoryInfo directory;
        
        private readonly DataSet ds;       
        private readonly Window parent;
        
        private readonly UserInterface ui;
        private readonly ScrolledPlot plot;

        
        internal ExtractedDataDialog(Window parent, UserInterface ui, DirectoryInfo dir)
            : base($"{Catalog.GetString("Extracted data characteristic")} ({dir.Name})",
                   parent,
                   DialogFlags.Modal)
        {
            this.parent = parent;
            this.TransientFor = parent;
            this.ui = ui;
            this.directory = dir;
            this.IconList = MainClass.QuickStepIcons;
            
            var dialog = new Gtk.Dialog(Catalog.GetString("Extract data"),
                                        this.parent,
                                        DialogFlags.Modal);

            Alignment align1 = new Alignment(0f, 0.5f, 0f, 0f);
            Alignment align2 = new Alignment(0f, 0.5f, 1f, 0f);
            align1.LeftPadding   = 8;
            align1.RightPadding  = 8;
            align1.TopPadding    = 0;
            align1.Add(new Label(Catalog.GetString("Choose data to extract:")));
            align2.RightPadding = 5;

            ComboBox combo = new ComboBox(new string[]
            {
                "AddData 1",
                "AddData 2",
                "AddData 3",
                "AddData 4",
                "AddData 5",
                "AddData 6",
                "AddData 7",
                "AddData 8",
                "AddData 9",
                "AddData 10",
                "AddData 11",
                "AddData 12",
                "AddData 13",
                "AddData 14",
                Catalog.GetString("Intensity FWHM")
            })
            {
                Active = 0
            };
            align2.Add(combo);
            
            Alignment align3 = new Alignment(0f, 0.5f, 0f, 0f);
            Alignment align4 = new Alignment(0f, 0.5f, 1f, 0f);
            align3.LeftPadding   = 8;
            align3.RightPadding  = 8;
            align3.BottomPadding = 0;
            align3.Add(new Label(Catalog.GetString("Choose time format:")));
            align4.RightPadding = 5;

            ComboBox combo2 = new ComboBox(new string[]
            {
                Catalog.GetString("Minutes (relative)"),
                Catalog.GetString("Unix time (absolute)")
            })
            {
                Active = 0
            };
            align4.Add(combo2);

            Table table = new Table(2, 2, false);
            table.Attach(align1, 0, 1, 0, 1, AttachOptions.Fill, AttachOptions.Fill, 0, 0);
            table.Attach(align2, 1, 2, 0, 1, AttachOptions.Fill, AttachOptions.Fill, 0, 0);
            table.Attach(align3, 0, 1, 1, 2, AttachOptions.Fill, AttachOptions.Fill, 0, 0);
            table.Attach(align4, 1, 2, 1, 2, AttachOptions.Fill, AttachOptions.Fill, 0, 0);
            table.ShowAll();
            
            dialog.VBox.PackStart(table);
            dialog.AddButton(Stock.Cancel, ResponseType.Cancel);
            dialog.AddButton(Stock.Ok, ResponseType.Ok);            
            
            ResponseType choice = (ResponseType)dialog.Run();
            this.extraction_id = combo.Active;
            dialog.Destroy();
            
            if (choice != ResponseType.Ok)
                return;

            if (this.extraction_id < 14)
            {
                MessageDialog mdialog = new MessageDialog(parent,
                                                          DialogFlags.Modal,
                                                          MessageType.Info, 
                                                          ButtonsType.None,
                                                          Catalog.GetString("Reading data..."));
                mdialog.ShowAll();
                List<CSV.AddData> list = new List<CSV.AddData>();
                try
                {
                    Exception ex = null;
                    Thread t = new Thread(new ThreadStart(() =>
                    {
                        try
                        {
                            list = CSV.ReadAdditionalData(dir);
                        }
                        catch (Exception _ex)
                        {
                            ex = _ex;
                        }
                    }));
                    t.Start();

                    while (t.Join(50) == false)
                    {
                        UserInterface.Instance.ProcessEvents();
                    }
                    mdialog.Destroy();

                    if (ex != null)
                        throw new Exception(ex.Message, ex);
                }
                catch (Exception ex)
                {
                    InfoMessageDialog.Show(this.parent, 
                                     Catalog.GetString("Cannot extract additional data from directory:") +
                                     " " +
                                     ex.Message);
                    return;
                }
            
                // extract relevant data
                List<CSV.AddData> new_list = new List<CSV.AddData>();
                foreach (CSV.AddData add_data in list)
                {
                    if (add_data.Data.Count > extraction_id)
                        new_list.Add(add_data);
                }
                
                if (new_list.Count < 2)
                {
                    InfoMessageDialog.Show(this.parent, 
                                     Catalog.GetString("No or not enough additional data available."));
                    return;
                }
                
                // create data set
                new_list.Sort();
                List<double> time = new List<double>();
                List<double> data = new List<double>();
                DateTime unix_epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
                foreach (CSV.AddData add_data in new_list)
                {
                    if (combo2.Active == 1)
                    {
                        time.Add((add_data.DateTime.ToUniversalTime() - unix_epoch).TotalSeconds);
                    }
                    else
                    {
                        TimeSpan span = add_data.DateTime - new_list[0].DateTime;
                        time.Add(span.TotalSeconds);
                    }
                    data.Add((double)((int)add_data.Data[extraction_id]));
                }
                this.ds = new DataSet(time, data);
                this.ds.Label = Catalog.GetString("Additional Data") + " " + (this.extraction_id+1);
            }
            else
            {
                try
                {
                    switch (this.extraction_id)
                    {
                        
                    case 5:
                        this.ds = this.ExtractFwhmData(dir);
                        this.ds.Label = Catalog.GetString("Intensity FWHM");
                        break;
                        
                    default:
                        throw new Exception("Unknown data type.");
                        
                    }
                }
                catch (Exception ex)
                {
                    InfoMessageDialog.Show(this.parent, 
                                     Catalog.GetString("Cannot extract data from directory:") +
                                     " " + ex.Message);
                    return;
                }
            }
            
            this.AddButton(Stock.Save,  0);
            this.AddButton(Stock.Print, 1);
            this.AddButton(Stock.Close, ResponseType.Close);
            
            this.Response += new ResponseHandler(this.OnDialogResponse);
            
            this.HasSeparator  = true;
            this.WidthRequest  = 780;
            this.HeightRequest = 400;
            
            this.plot = new ScrolledPlot(null);
            this.plot.Plot.BackgroundColor = MainWindow.UI.BackgroundColor;
            DataSet ds = this.ds / new DataSet.Operand(60.0, 1.0);
            ds.Label = this.ds.Label;
            this.plot.Plot.AddDataSet(ds);

            if (combo2.Active == 1)
                this.plot.Plot.XLabel = Catalog.GetString("Unix time / s");
            else
                this.plot.Plot.XLabel = Catalog.GetString("Relative time / min");

            this.plot.Plot.YLabel = Catalog.GetString("Extracted Data / a.u.");
            this.plot.Plot.Title = Catalog.GetString("Directory:") + " " + dir.FullName;
            this.VBox.PackStart(this.plot);
            this.plot.ShowAll();
            
            do
            {
                this.Run();
            }
            while (this.run_dialog);
            
            this.Destroy();
        }
        
        private DataSet ExtractFwhmData(DirectoryInfo dir)
        {
            FileInfo[] files = dir.GetFiles("*.csv", SearchOption.AllDirectories);

            var time = new List<double>();
            var data = new List<double>();
            
            foreach (FileInfo file in files)
            {
                Spectrum spectrum = CSV.Read(file.FullName);
                
                TimeSpan span = spectrum.Timestamp - DateTime.MinValue;
                time.Add(span.TotalSeconds);
                
                try
                {
                    DataSet.FwhmResult result = spectrum.Intensity.FWHM();
                    data.Add(result.FWHM);
                }
                catch (Exception ex)
                {
                    string msg = string.Format(Catalog.GetString("Cannot calculate Full Width at Half Maximum (FWHM) for spectrum '{0}': {1}"),
                                               file.FullName,
                                               ex.Message);
                    throw new Exception(msg);
                }
            }
            
            DataSet ds = new DataSet(time, data);
            
            ds -= new DataSet.Operand(ds.XMin(), 0.0);
            ds.Sort();
            
            return ds;
        }
        
        private void OnDialogResponse(object o, ResponseArgs e)
        {
            switch ((int)e.ResponseId)
            {
                
            case 0:
                FileChooserDialog chooser = new FileChooserDialog(Catalog.GetString("Choose file to save additional data characteristic"), 
                                                                  UserInterface.Instance.MainWindow,
                                                                  FileChooserAction.Save,
                                                                  Stock.Save,
                                                                  ResponseType.Ok,
                                                                  Stock.Cancel,
                                                                  ResponseType.Cancel);
                FileFilter filter = new FileFilter
                {
                    Name = Catalog.GetString("CSV files")
                };
                filter.AddPattern("*.csv");
                chooser.AddFilter(filter);
                
                chooser.CurrentName = $"add_data_{this.directory.Name}_{DateTime.Now.ToString("yyyy-MM-dd_HH-mm")}.csv";
                
                if (string.IsNullOrEmpty(UserInterface.Settings.Current.SaveAddDataFilePath) == false)
                    chooser.SetCurrentFolder(UserInterface.Settings.Current.SaveAddDataFilePath);
                else
                    chooser.SetCurrentFolder(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments));
                
                try
                {
                    ResponseType choice = (ResponseType)chooser.Run();
                    
                    if (choice == ResponseType.Ok)
                    {
                        chooser.Hide();
                        
                        CSV.Write(this.ds, chooser.Filename);
                        UserInterface.Settings.Current.SaveAddDataFilePath = chooser.CurrentFolder;
                    }
                }
                catch (Exception ex)
                {
                    InfoMessageDialog.Show(null, 
                                     Catalog.GetString("Error while saving additional data characteristic: {0}"),
                                     ex.Message);
                }
                finally
                {
                    chooser.Destroy();
                }
                this.run_dialog = true;
                break;
                
            case 1:
                var printer = new Integration.Printer(null, this.plot.Plot);
                this.run_dialog = true;
                break;

            default:
                this.run_dialog = false;
                break;
                
            }
        }
    }
}