// Created with MonoDevelop
//
//    QuickStep: Acquire, view and identify spectra 
//    Copyright (C) 2017 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 Hiperscan.Spectroscopy;
using Hiperscan.NPlotEngine;
using System.Drawing;
using Hiperscan.Unix;
using Hiperscan.ApoIdentCore.Enums;
using Hiperscan.ApoIdentCore.Reporting.ReportData;
using Hiperscan.ApoIdentCore.Legacy;
using Gtk;
using Hiperscan.ApoIdentCommon.ApoConfig.Enums;

namespace Hiperscan.Extensions.ApoIdent
{
    public class DetailsPlot : IDetailPlot
    {
        public DetailsPlot(int main_thread_id)
        {
            this.MainThreadId = main_thread_id;
        }

        public void Init(ReportInfo report_info)
        {
            this.ReportInfo = report_info;

            if (this.MainThreadId == System.Threading.Thread.CurrentThread.ManagedThreadId)
            {
                this.Init(this, EventArgs.Empty);
            }
            else
            {
                this.Wait = true;
                Application.Invoke(this.Init);
                for (; ; )
                {
                    if (this.Wait == false)
                        break;

                    System.Threading.Thread.Sleep(20);
                }
            }
        }

        private void Init(object sender, EventArgs e)
        {
            this.Original = this.ReportInfo.Spectrum.Absorbance;
            this.Backprojection = this.ReportInfo.Backprojection;

            if (this.Backprojection != null && this.ReportInfo.IsMatch == true)
            {
                this.MatchBackProjection = this.ReportInfo.MatchBackProjection;
                this.Difference = this.Backprojection - this.MatchBackProjection;
            }

            this.SetCommonPlot();
            this.Wait = false;
        }

        private void SetCommonPlot()
        {
            this.Original.Label = Catalog.GetString("Sample spectrum");
            this.Original.Color = Color.Blue;

            if (this.Backprojection != null)
            {
                this.Backprojection.Label = Catalog.GetString("Back-projection of sample spectrum");
                this.Backprojection.Color = Color.Blue;
                this.Backprojection.Id = "0_backprojection";

                if (this.ReportInfo.IsMatch == true)
                {
                    this.MatchBackProjection.Label = Catalog.GetString("Back-projection of reference spectrum");
                    this.MatchBackProjection.Color = Color.Red;
                    this.MatchBackProjection.Id = "1_match";
                    this.Difference.Label = Catalog.GetString("Difference of back-projections*");
                    this.Difference.Color = Color.Green;
                    this.Difference.LineStyle = LineStyle.Dash;
                    this.Difference.Id = "2_difference";
                }
            }


            this.Plot1 = new NPlotEngine.NPlotEngine(PlotEngineType.Synchronous)
            {
                Title = Catalog.GetString("Rawdata of the spectrum"),
                XLabel = Catalog.GetString("Wavelength / nm"),
                YLabel = Catalog.GetString("Absorbance")
            };
            /*
            {
                Title = "Rohdaten des Probenspektrums"
                this.Plot1.XLabel = "Wellenlänge / nm";
            this.Plot1.YLabel = "Absorbanz";               
            };*/
            this.Plot1.AddDataSet(this.Original);
            this.Plot1.FitView();
            this.Plot1.ProcessChanges();

            if (this.Backprojection != null)
            {
                this.Plot2 = new NPlotEngine.NPlotEngine(PlotEngineType.Synchronous)
                {
                    Title = Catalog.GetString("Comparison of processed spectrum and database entry"),
                    XLabel = Catalog.GetString("Wavelength / nm"),
                    YLabel = Catalog.GetString("f(Absorbance)")
                };
                /*
                {
                    Title = "Vergleich von verarbeitetem Probenspektrum und Datenbankeintrag"
                    this.Plot2.XLabel = "Wellenlänge / nm";
                this.Plot2.YLabel = "f(Absorbanz)";                   
                };*/

                this.Plot2.AddDataSet(this.Backprojection);
                if (this.ReportInfo.IsMatch == true)
                    this.Plot2.AddDataSet(this.MatchBackProjection);
                this.Plot2.FitView();
                this.Plot2.ProcessChanges();

                if (this.ReportInfo.ShowDifferencePlot == true && this.ReportInfo.IsMatch == true)
                {
                    this.Plot2.UseSecondAxes = true;
                    this.Plot2.AddDataSet(this.Difference);
                    double min = this.Difference.YMin();
                    double max = this.Difference.YMax();
                    this.Plot2.YMin = min - 2 * (max - min);
                    this.Plot2.YMax = max + 2 * (max - min);
                    this.Plot2.ProcessChanges();
                    this.Plot2.YLabel = Catalog.GetString("Difference*");// "Differenz*";
                    this.Plot2.ProcessChanges();
                }
            }
        }

        public void Dispose()
        {
            ((IDisposable)this.Plot1).Dispose();
            ((IDisposable)this.Plot2).Dispose();
        }

        public Bitmap GetAbsorbancePlot(int width, int height)
        {
            return this.Plot1.GetBitmap(width, height);
        }

        public Bitmap GetBackProjectionPlot(int width, int height)
        {
            return this.Plot2.GetBitmap(width, height);
        }

        public IPlotEngine Plot1 { get; private set; }
        public IPlotEngine Plot2 { get; private set; }

        private DataSet MatchBackProjection { get; set; }
        private DataSet Difference { get; set; }
        private DataSet Backprojection { get; set; }
        private DataSet Original { get; set; }

        private ReportInfo ReportInfo { get; set; }
        private int MainThreadId { get; set; }
        private bool Wait { get; set; }
    }
}

