// AdditionalPlotTypes.cs created with MonoDevelop
// User: klose at 13:19 15.07.2010
// CVS release: $Id: AdditionalPlotTypes.cs,v 1.5 2011-04-19 13:13:02 klose Exp $
//

using System;
using System.Collections.Generic;
using Mono.Unix;

using Hiperscan.Spectroscopy;
using Hiperscan.SGS;
using Hiperscan.Extensions;


namespace Hiperscan.Extensions.AdditionalPlotTypes
{

	public class CorrectionPlotTypeInfo : PlotTypeInfo
	{
		public CorrectionPlotTypeInfo() : base(Catalog.GetString("Wavelength correction"))
		{
			this.XLabel = Catalog.GetString("Wavelength / nm");
			this.YLabel = Catalog.GetString("Wavelength correction / nm");
			this.LowerLimit = -10f;
			this.UpperLimit = 10f;
			this.StandardMin = -5f;
			this.StandardMax = 5f;
			this.NeedAbsorbance = false;
		}
		
		public override DataSet ComputeDataSet (Spectrum spectrum, DataSet.XConstraints x_constraints)
		{
			if (spectrum.WavelengthCorrection == null)
				return null;
			DataSet ds = spectrum.WavelengthCorrection.FitFunction(1000.0, 1900.0, 10.0);
			return ds;
		}
	}
	
	public class RawIntensityFFTAbsPlotTypeInfo : PlotTypeInfo
	{
		public RawIntensityFFTAbsPlotTypeInfo() : base(Catalog.GetString("FFT(RawIntensity) Abs"))
		{
			this.XLabel = Catalog.GetString("Spatial frequency / 1/nm");
			this.YLabel = Catalog.GetString("Abs(FFT(RawIntensity))");
			this.LowerLimit = -10f;
			this.UpperLimit = 10f;
			this.StandardMin = -5f;
			this.StandardMax = 5f;
			this.NeedAbsorbance = false;
		}
		
		public override DataSet ComputeDataSet(Spectrum spectrum, DataSet.XConstraints x_constraints)
		{
			DataSet ds = spectrum.RawIntensity.FFTShift().Amplitude;
			return ds;
		}
	}
	
	public class RawIntensityFFTArgPlotTypeInfo : PlotTypeInfo
	{
		public RawIntensityFFTArgPlotTypeInfo() : base(Catalog.GetString("FFT(RawIntensity) Arg"))
		{
			this.XLabel = Catalog.GetString("Spatial frequency / 1/nm");
			this.YLabel = Catalog.GetString("Arg(FFT(RawIntensity))");
			this.LowerLimit = -4f;
			this.UpperLimit = 4f;
			this.StandardMin = -4f;
			this.StandardMax = 4f;
			this.NeedAbsorbance = false;
		}
		
		public override DataSet ComputeDataSet(Spectrum spectrum, DataSet.XConstraints x_constraints)
		{
			DataSet ds = spectrum.RawIntensity.FFTShift().Phase;
			return ds;
		}
	}
	
	public class LinearRegressionPlotTypeInfo : PlotTypeInfo
	{
		public LinearRegressionPlotTypeInfo() : base(Catalog.GetString("Linear Regression"))
		{
			this.XLabel = Catalog.GetString("Wavelength / nm");
			this.YLabel = Catalog.GetString("Linear Regression (Absorbance)");
			this.LowerLimit = -5f;
			this.UpperLimit = 8f;
			this.StandardMin = -0.5f;
			this.StandardMax = 4.1f;
			this.NeedAbsorbance = true;
		}
		
		public override DataSet ComputeDataSet(Spectrum spectrum, DataSet.XConstraints x_constraints)
		{
			if (!spectrum.HasAbsorbance)
				return null;
			
			DataSet.LinearRegressionResult regression = spectrum.Absorbance.LinearRegression();
			DataSet ds = spectrum.Absorbance.LinearRegressionCurve(regression);
			return ds;
		}
	}
	
	public class LinearRegressionCorrectionPlotTypeInfo : PlotTypeInfo
	{
		public LinearRegressionCorrectionPlotTypeInfo() : base(Catalog.GetString("Baseline Correction"))
		{
			this.XLabel = Catalog.GetString("Wavelength / nm");
			this.YLabel = Catalog.GetString("(Baseline Correction) Absorbance");
			this.LowerLimit = -5f;
			this.UpperLimit = 8f;
			this.StandardMin = -0.5f;
			this.StandardMax = 4.1f;
			this.NeedAbsorbance = true;
		}
		
		public override DataSet ComputeDataSet(Spectrum spectrum, DataSet.XConstraints x_constraints)
		{
			if (!spectrum.HasAbsorbance)
				return null;

			DataSet absorbance = spectrum.Absorbance.SNV();
			DataSet.LinearRegressionResult regression = absorbance.LinearRegression();
			DataSet ds = absorbance - absorbance.LinearRegressionCurve(regression);
			return ds;
		}
	}

	public class LinearRegressionCorrectionSnvPlotTypeInfo : PlotTypeInfo
	{
		public LinearRegressionCorrectionSnvPlotTypeInfo() : base(Catalog.GetString("Baseline Correction SNV"))
		{
			this.XLabel = Catalog.GetString("Wavelength / nm");
			this.YLabel = Catalog.GetString("(Baseline Correction) SNV(Absorbance)");
			this.LowerLimit = -5f;
			this.UpperLimit = 8f;
			this.StandardMin = -0.5f;
			this.StandardMax = 4.1f;
			this.NeedAbsorbance = true;
		}
		
		public override DataSet ComputeDataSet(Spectrum spectrum, DataSet.XConstraints x_constraints)
		{
			if (!spectrum.HasAbsorbance)
				return null;

//			List<double> wavelengths = new List<double>();
//			for (double lambda = Plugin.host.SnvLowerBoundary; lambda <= Plugin.host.SnvUpperBoundary; lambda += 1.0)
//			{
//				wavelengths.Add(lambda);
//			}
//			DataSet absorbance = spectrum.Absorbance.Interpolate(wavelengths);
			DataSet absorbance = x_constraints.Apply(spectrum.Absorbance);
			DataSet.LinearRegressionResult regression = absorbance.LinearRegression();
			DataSet ds = absorbance - absorbance.LinearRegressionCurve(regression);
			ds = ds.SNV();
			return ds;
		}
	}

	public class RawIntensityPlotTypeInfo : PlotTypeInfo
	{
		public RawIntensityPlotTypeInfo() : base(Catalog.GetString("RawIntensity"))
		{
			this.XLabel = Catalog.GetString("Wavelength / nm");
			this.YLabel = Catalog.GetString("RawIntensity / a.u.");
			this.LowerLimit = -2f;
			this.UpperLimit = 5f;
			this.StandardMin = -0.1f;
			this.StandardMax = 2.6f;
			this.NeedAbsorbance = false;
		}
		
		public override DataSet ComputeDataSet(Spectrum spectrum, DataSet.XConstraints x_constraints)
		{
			DataSet ds = new DataSet(spectrum.RawIntensity);
			return ds;
		}
	}
	
	public class ProbeError : PlotTypeInfo
	{
		public ProbeError() : base(Catalog.GetString("Probe Error"))
		{
			this.XLabel = Catalog.GetString("Wavelength / nm");
			this.YLabel = Catalog.GetString("Probe Error");
			this.LowerLimit = -5f;
			this.UpperLimit = 8f;
			this.StandardMin = -0.5f;
			this.StandardMax = 4.1f;
			this.NeedAbsorbance = true;
		}
		
		public override DataSet ComputeDataSet(Spectrum spectrum, DataSet.XConstraints x_constraints)
		{
			if (!spectrum.HasAbsorbance)
				return null;

			DataSet ds = x_constraints.Apply(spectrum.Absorbance);
			return ProbeErrorCharacteristic.GetCorrection(ds);
		}
	}
	
	public class ProbeErrorCorrection : PlotTypeInfo
	{
		public ProbeErrorCorrection() : base(Catalog.GetString("Probe Error Correction (PEC)"))
		{
			this.XLabel = Catalog.GetString("Wavelength / nm");
			this.YLabel = Catalog.GetString("PEC(Absorbance)");
			this.LowerLimit = -5f;
			this.UpperLimit = 8f;
			this.StandardMin = -0.5f;
			this.StandardMax = 4.1f;
			this.NeedAbsorbance = true;
		}
		
		public override DataSet ComputeDataSet(Spectrum spectrum, DataSet.XConstraints x_constraints)
		{
			if (!spectrum.HasAbsorbance)
				return null;

			DataSet ds = x_constraints.Apply(spectrum.Absorbance);
			return ProbeErrorCharacteristic.CorrectDataSet(ds);
		}
	}

	public class ConvertZenithToTiO2Intensity : PlotTypeInfo
	{
		public ConvertZenithToTiO2Intensity() : base(Catalog.GetString("Convert Zenith to TiO2 (Intensity)"))
		{
			this.XLabel = Catalog.GetString("Wavelength / nm");
			this.YLabel = Catalog.GetString("Intensity / a.u.");
			this.LowerLimit = -5.0;
			this.UpperLimit = 8.0;
			this.StandardMin = -0.5;
			this.StandardMax = 4.1;
			this.NeedAbsorbance = false;
		}
		
		public override DataSet ComputeDataSet(Spectrum spectrum, DataSet.XConstraints x_constraints)
		{
			DataSet ds = x_constraints.Apply(spectrum.Intensity);
			return Finder.ConvertWhiteReference(WhiteReferenceConversionMode.ZenithToTitaniumdioxide, ds);
		}
	}
	
	public class ConvertZenithToTiO2Background : PlotTypeInfo
	{
		public ConvertZenithToTiO2Background() : base(Catalog.GetString("Convert Zenith to TiO2 (Background)"))
		{
			this.XLabel = Catalog.GetString("Wavelength / nm");
			this.YLabel = Catalog.GetString("Intensity (Background) / a.u.");
			this.LowerLimit = -5.0;
			this.UpperLimit = 8.0;
			this.StandardMin = -0.5;
			this.StandardMax = 4.1;
			this.NeedAbsorbance = true;
		}
		
		public override DataSet ComputeDataSet(Spectrum spectrum, DataSet.XConstraints x_constraints)
		{
			if (spectrum.Background == null)
				return null;

			DataSet ds = x_constraints.Apply(spectrum.Background.Intensity);
			return Finder.ConvertWhiteReference(WhiteReferenceConversionMode.ZenithToTitaniumdioxide, ds);
		}
	}

	public class ConvertZenithToTiO2Reflectivity : PlotTypeInfo
	{
		public ConvertZenithToTiO2Reflectivity() : base(Catalog.GetString("Convert Zenith to TiO2 (Reflectivity)"))
		{
			this.XLabel = Catalog.GetString("Wavelength / nm");
			this.YLabel = Catalog.GetString("Reflectivity");
			this.LowerLimit = 0.0;
			this.UpperLimit = 1.5;
			this.StandardMin = 0.5;
			this.StandardMax = 1.1;
			this.NeedAbsorbance = true;
		}
		
		public override DataSet ComputeDataSet(Spectrum spectrum, DataSet.XConstraints x_constraints)
		{
			if (spectrum.Background == null)
				return null;

			DataSet ds = x_constraints.Apply(spectrum.Background.Intensity);
			return spectrum.Intensity / Finder.ConvertWhiteReference(WhiteReferenceConversionMode.ZenithToTitaniumdioxide, ds);
		}
	}

	public class ZenithApoIdent2FitQuadratic : PlotTypeInfo
	{
		public ZenithApoIdent2FitQuadratic() : base(Catalog.GetString("Global Fit (Quadratic, ZenithApoIdent)"))
		{
			this.XLabel = Catalog.GetString("Wavelength / nm");
			this.YLabel = Catalog.GetString("Normalized Absorbance / a.u.");
			this.LowerLimit = 0.0;
			this.UpperLimit = 1.5;
			this.StandardMin = 0.5;
			this.StandardMax = 1.1;
			this.NeedAbsorbance = true;
		}

		public override DataSet ComputeDataSet(Spectrum spectrum, DataSet.XConstraints x_constraints)
		{
			if (!spectrum.HasAbsorbance)
				return null;

			DataSet ds = x_constraints.Apply(spectrum.Absorbance);
			DataSet ref_ds = Finder.GetWavelengthReference(ReferenceWheelVersion.ZenithApoIdent2).Absorbance;
			DataSet fit_ds = ds.Interpolate(ref_ds.X, InterpolationType.NaturalCubic);

            double[] p = LevenbergMarquardt.Fit(new Match2DQuadraticQuadraticSlopeLMFit(fit_ds, ref_ds, 1.0)).Coefficients;

			double[] pwl = new double[3];
			Array.Copy(p, 0, pwl, 0, 3);
			WavelengthCorrection wlc = new WavelengthCorrection(pwl);
			DataSet fit = wlc.CorrectedSpectrum(fit_ds).Interpolate(ref_ds.X);

			List<double> Y = new List<double>();
			for (int ix=0; ix < fit.Count; ++ix)
			{
				Y.Add(p[3] + p[4]*fit.Y[ix] + p[5]*fit.Y[ix]*fit.Y[ix] + p[6]*fit.X[ix]);
			}

			return new DataSet(fit.X, Y);
		}
	}

	public class ZenithApoIdent2FitLinear : PlotTypeInfo
	{
		public ZenithApoIdent2FitLinear() : base(Catalog.GetString("Global Fit (Linear, ZenithApoIdent)"))
		{
			this.XLabel = Catalog.GetString("Wavelength / nm");
			this.YLabel = Catalog.GetString("Normalized Absorbance / a.u.");
			this.LowerLimit = 0.0;
			this.UpperLimit = 1.5;
			this.StandardMin = 0.5;
			this.StandardMax = 1.1;
			this.NeedAbsorbance = true;
		}

		public override DataSet ComputeDataSet(Spectrum spectrum, DataSet.XConstraints x_constraints)
		{
			if (!spectrum.HasAbsorbance)
				return null;

			DataSet ds = x_constraints.Apply(spectrum.Absorbance);
			DataSet ref_ds = Finder.GetWavelengthReference(ReferenceWheelVersion.ZenithApoIdent2).Absorbance;
			DataSet fit_ds = ds.Interpolate(ref_ds.X, InterpolationType.NaturalCubic);

            double[] p = LevenbergMarquardt.Fit(new Match2DQuadraticLinearSlopeLMFit(fit_ds, ref_ds, 1.0)).Coefficients;

			double[] pwl = new double[3];
			Array.Copy(p, 0, pwl, 0, 3);
			WavelengthCorrection wlc = new WavelengthCorrection(pwl);
			DataSet fit = wlc.CorrectedSpectrum(fit_ds).Interpolate(ref_ds.X);

			List<double> Y = new List<double>();
			for (int ix=0; ix < fit.Count; ++ix)
			{
				Y.Add(p[3] + p[4]*fit.Y[ix] + p[5]*fit.X[ix]);
			}

			return new DataSet(fit.X, Y);
		}
	}

	public class NistDeviation : PlotTypeInfo
	{
		public NistDeviation() : base(Catalog.GetString("NIST Deviation"))
		{
			this.XLabel = Catalog.GetString("Wavelength / nm");
			this.YLabel = Catalog.GetString("NIST Deviation / nm");
			this.LowerLimit = -10.0;
			this.UpperLimit = 10.0;
			this.StandardMin = -2.0;
			this.StandardMax = 2.0;
			this.NeedAbsorbance = true;
		}

		public override DataSet ComputeDataSet(Spectrum _spectrum, DataSet.XConstraints x_constraints)
		{
			if (!_spectrum.HasAbsorbance)
				return null;

			Spectrum spectrum = _spectrum.Clone();

			spectrum.ApplyCorrectionsToRawData(CorrectionMask.All);
			WavelengthCorrection wlc;

			if (spectrum.LimitBandwidth || spectrum.SpectralResolution == 15.0)
				wlc = WavelengthCorrection.CreateFromExtremumDeviation(spectrum, WavelengthCorrection.ReferenceType.NIST15nm, false);
			else
				wlc = WavelengthCorrection.CreateFromExtremumDeviation(spectrum, WavelengthCorrection.ReferenceType.NIST10nm, true);

			DataSet ds = new DataSet(wlc.Wavelengths, wlc.Corrections);
//			ds.IsDropPoint = true;
			ds.IsContinuous = false;

			return ds;
		}
	}

	public class RawNistDeviation : PlotTypeInfo
	{
		public RawNistDeviation() : base(Catalog.GetString("NIST Deviation (uncorrected)"))
		{
			this.XLabel = Catalog.GetString("Wavelength / nm");
			this.YLabel = Catalog.GetString("NIST Deviation / nm");
			this.LowerLimit = -10.0;
			this.UpperLimit = 10.0;
			this.StandardMin = -2.0;
			this.StandardMax = 2.0;
			this.NeedAbsorbance = true;
		}

		public override DataSet ComputeDataSet(Spectrum spectrum, DataSet.XConstraints x_constraints)
		{
			if (!spectrum.HasAbsorbance)
				return null;

			spectrum = spectrum.Clone();

			spectrum.WavelengthCorrection = null;
			spectrum.ApplyCorrectionsToRawData(CorrectionMask.All);
			WavelengthCorrection wlc;

			if (spectrum.SpectralResolution == 15.0)
                wlc = WavelengthCorrection.CreateFromExtremumDeviation(spectrum, WavelengthCorrection.ReferenceType.NIST15nm, false);
			else
				wlc = WavelengthCorrection.CreateFromExtremumDeviation(spectrum, WavelengthCorrection.ReferenceType.NIST10nm, true);

			DataSet ds = new DataSet(wlc.Wavelengths, wlc.Corrections);
//			ds.IsDropPoint = true;
			ds.IsContinuous = false;

			return ds;
		}

	}

	public class MeanNistDeviation : PlotTypeInfo
	{
		public MeanNistDeviation() : base(Catalog.GetString("Mean NIST Deviation"))
		{
			this.XLabel = Catalog.GetString("Wavelength / nm");
			this.YLabel = Catalog.GetString("Mean NIST Deviation / nm");
			this.LowerLimit = -10.0;
			this.UpperLimit = 10.0;
			this.StandardMin = -2.0;
			this.StandardMax = 2.0;
			this.NeedAbsorbance = true;
		}

		private static Dictionary<int,DataSet> cache = new Dictionary<int,DataSet>();

		public override DataSet ComputeDataSet(Spectrum _spectrum, DataSet.XConstraints x_constraints)
		{
			if (!_spectrum.HasAbsorbance)
				return null;

			int hash = Plugin.host.CurrentSpectra.GetHashCode();

			if (MeanNistDeviation.cache.ContainsKey(hash))
				return MeanNistDeviation.cache[hash];

			DataSet ds = null;

			foreach (Spectrum __spectrum in Plugin.host.CurrentSpectra.Values)
			{
				Spectrum spectrum = __spectrum.Clone();
				spectrum.ApplyCorrectionsToRawData(CorrectionMask.All);
				WavelengthCorrection wlc;

				if (spectrum.LimitBandwidth || spectrum.SpectralResolution == 15.0)
					wlc = WavelengthCorrection.CreateFromExtremumDeviation(spectrum, WavelengthCorrection.ReferenceType.NIST15nm, false);
				else
					wlc = WavelengthCorrection.CreateFromExtremumDeviation(spectrum, WavelengthCorrection.ReferenceType.NIST10nm, true);

				if (ds == null)
					ds = new DataSet(wlc.Wavelengths, wlc.Corrections);
				else
					ds += new DataSet(wlc.Wavelengths, wlc.Corrections);
			}

			ds /= (double)Plugin.host.CurrentSpectra.Count;

			ds.IsContinuous = false;

			MeanNistDeviation.cache.Add(hash, ds);

			return ds;
		}
	}

	//	public class RawIntensityDifferencePlotTypeInfo : PlotTypeInfo
//	{
//		public RawIntensityDifferencePlotTypeInfo() : base(Catalog.GetString("RawIntensity difference"))
//		{
//			this.XLabel = Catalog.GetString("Wavelength / nm");
//			this.YLabel = Catalog.GetString("RawIntensity difference / a.u.");
//			this.LowerLimit = -2f;
//			this.UpperLimit = 5f;
//			this.StandardMin = -0.1f;
//			this.StandardMax = 2.6f;
//			this.NeedAbsorbance = false;
//		}
//		
//		public override DataSet ComputeDataSet(Spectrum spectrum)
//		{
//			DataSet ref_ds = null;
//			foreach (Spectrum s in Plugin.host.CurrentSpectra.Values)
//			{
//				ref_ds = s.RawIntensity;
//				break;
//			}
//			if (ref_ds == null)
//				return null;
//			
//			DataSet ds = spectrum.RawIntensity - ref_ds.Interpolate(spectrum.RawIntensity.X);
//			return ds;
//		}
//	}
//	
//	public class AbsorbanceDifferencePlotTypeInfo : PlotTypeInfo
//	{
//		public AbsorbanceDifferencePlotTypeInfo() : base(Catalog.GetString("Absorbance difference"))
//		{
//			this.XLabel = Catalog.GetString("Wavelength / nm");
//			this.YLabel = Catalog.GetString("Absorbance difference");
//			this.LowerLimit = -2f;
//			this.UpperLimit = 5f;
//			this.StandardMin = -0.1f;
//			this.StandardMax = 2.6f;
//			this.NeedAbsorbance = true;
//		}
//		
//		public override DataSet ComputeDataSet(Spectrum spectrum)
//		{
//			DataSet ref_ds = null;
//			foreach (Spectrum s in Plugin.host.CurrentSpectra.Values)
//			{
//				ref_ds = s.Absorbance;
//				break;
//			}
//			if (ref_ds == null)
//				return null;
//			
//			DataSet ds = spectrum.Absorbance - ref_ds.Interpolate(spectrum.Absorbance.X);
//			return ds;
//		}
//	}
//	
//	public class IntensityQuotientPlotTypeInfo : PlotTypeInfo
//	{
//		public IntensityQuotientPlotTypeInfo() : base(Catalog.GetString("Intensity quotient"))
//		{
//			this.XLabel = Catalog.GetString("Wavelength / nm");
//			this.YLabel = Catalog.GetString("Intensity quotient");
//			this.LowerLimit = -2f;
//			this.UpperLimit = 5f;
//			this.StandardMin = -0.1f;
//			this.StandardMax = 2.6f;
//			this.NeedAbsorbance = false;
//		}
//		
//		public override DataSet ComputeDataSet(Spectrum spectrum)
//		{
//			DataSet ref_ds = null;
//			foreach (Spectrum s in Plugin.host.CurrentSpectra.Values)
//			{
//				ref_ds = s.Intensity;
//				break;
//			}
//			if (ref_ds == null)
//				return null;
//			
//			DataSet ds = spectrum.Intensity / ref_ds.Interpolate(spectrum.Intensity.X);
//			return ds;
//		}
//	}
	
//	// FIXME: obsolete? works only with poly spectra!
//	public class WLCIntensityQuotientPlotTypeInfo : PlotTypeInfo
//	{
//		public WLCIntensityQuotientPlotTypeInfo() : base(Catalog.GetString("WLC Intensity quotient"))
//		{
//			this.XLabel = Catalog.GetString("Wavelength / nm");
//			this.YLabel = Catalog.GetString("WLC Intensity quotient");
//			this.LowerLimit = -2f;
//			this.UpperLimit = 5f;
//			this.StandardMin = -0.1f;
//			this.StandardMax = 2.6f;
//			this.NeedAbsorbance = false;
//		}
//		
//		public override DataSet ComputeDataSet(Spectrum spectrum)
//		{
//			DataSet ref_ds = null;
//			foreach (Spectrum s in Plugin.host.CurrentSpectra.Values)
//			{
//				ref_ds = s.Intensity;
//				break;
//			}
//			if (ref_ds == null)
//				return null;
//			
//			List<double> wavelengths = new List<double>();
//			for (double lambda = Plugin.host.SnvLowerBoundary; lambda <= Plugin.host.SnvUpperBoundary; lambda += 1f)
//			{
//				wavelengths.Add(lambda);
//			}
//			ref_ds = ref_ds.Interpolate(wavelengths);
//			DataSet ds = spectrum.Intensity.Interpolate(wavelengths);
//			
//			spectrum.WavelengthCorrection = new WavelengthCorrection(ref_ds, ds);
//			
//			ds = spectrum.Intensity.Interpolate(wavelengths) / ref_ds;
//			return ds;
//		}
//	}
}