// Created with MonoDevelop
//
//    Copyright (C) 2010 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 Hiperscan.Unix;


namespace Hiperscan.SGS.Common
{

    public static partial class Spectrometer
    {
        
        public class LUT
        {

            public LUT(float[] data, uint lut_offset, int acquisition_offset, double msa_factor, DateTime timestamp, Version firmware, Version scan_engine)
            {
                this.Length                 = data.Length;
                this.Data                   = data;
                this.Offset                 = lut_offset;
                this.AcquisitionOffset      = acquisition_offset;
                this.MsaFactor              = msa_factor;
                this.Timestamp              = timestamp;
                this.FirmwareVersion        = firmware;
                this.ScanEngineVersion      = scan_engine;
                this.MinWavelength          = 1000f;
                this.MaxWavelength          = 1900f;
                this.Increment              = 1f;
                this.ExtensionRange         = 10f;
                this.AcquisitionChannelMask = 1;
                this.SkipCount              = 0;
                this.DarkIntensityEndpoint  = 0;
            }

            public LUT(LUT lut, float[] data, uint lut_offset, int acquisition_offset, double msa_factor, DateTime timestamp, Version firmware, Version scan_engine)
                : this(data, lut_offset, acquisition_offset, msa_factor, timestamp, firmware, scan_engine) 
            {
                this.IsExtended = lut.IsExtended;
                this.AcquisitionChannelMask = lut.AcquisitionChannelMask;
                this.SkipCount = lut.SkipCount;
                this.MinWavelength = lut.MinWavelength;
                this.MaxWavelength = lut.MaxWavelength;
                this.Increment = lut.Increment;
                this.ExtensionRange = lut.ExtensionRange;
                this.DarkIntensityEndpoint = lut.DarkIntensityEndpoint;
            }

            public LUT(float[] data, double msa_factor, DateTime timestamp, Version firmware, Version scan_engine, byte channel, uint skip_count, 
                       float min_wavelength, float max_wavelength, float increment, float extension_range, uint dark_intensity_endpoint) 
                : this(data, 0, 0, msa_factor, timestamp, firmware, scan_engine)
            {
                this.IsExtended = true;
                this.MinWavelength = min_wavelength;
                this.MaxWavelength = max_wavelength;
                this.Increment = increment;
                this.ExtensionRange = extension_range;
                this.AcquisitionChannelMask = channel;
                this.SkipCount = skip_count;
                this.DarkIntensityEndpoint = dark_intensity_endpoint;
            }

            public LUT(double msa, double g, double theta01, double theta2, int acquisition_offset, double msa_factor, int lut_length)
            {
                this.IsExtended = false;
                this.Length = lut_length;
                this.Offset = 250000;
                this.AcquisitionOffset = acquisition_offset;
                this.MsaFactor = msa_factor;
                this.FirmwareVersion = new Version(0);
                this.ScanEngineVersion = new Version(0);
                this.Timestamp = DateTime.MinValue;

                this.MinWavelength = 1000f;
                this.MaxWavelength = 1900f;
                this.Increment = 1f;
                this.ExtensionRange = 10f;
                this.AcquisitionChannelMask = 1;
                this.SkipCount = 0;
                this.DarkIntensityEndpoint = 0;

                msa *= Math.PI / 180.0;
                theta01 *= Math.PI / 180.0;
                theta2  *= Math.PI / 180.0;
                
                this.Data = new float[this.Length];

                for (int ix = 0; ix < this.Data.Length; ++ix)
                {
                    double tau = (double)ix / (double)this.Length * Math.PI;
                    this.Data[ix] = (float)(g * Math.Sin(theta01 - msa * Math.Cos(tau)) +
                                            g * Math.Cos(Math.PI/2.0 - theta01 + msa * Math.Cos(tau) - theta2));
                }
            }
            
            public LUT(double msa, int lut_length) : this(msa, 1600.0, 20.0, 15.0, 0, 1.35, lut_length)
            {
            }
            
            public LUT(double msa, int acquisition_offset, double msa_factor, int lut_length) 
                : this(msa, 1600.0, 20.0, 15.0, acquisition_offset, msa_factor, lut_length)
            {
                this.AcquisitionOffset = acquisition_offset;
            }

            public bool IsExtended             { get; private set; }
            public int Length                  { get; }
            public float[] Data                { get; }
            public uint Offset                 { get; }
            public int AcquisitionOffset       { get; }
            public double MsaFactor            { get; set; }
            public Version FirmwareVersion     { get; }
            public Version ScanEngineVersion   { get; }
            public DateTime Timestamp          { get; }
            public float MinWavelength         { get; }
            public float MaxWavelength         { get; }
            public float Increment             { get; }
            public float ExtensionRange        { get; }
            public byte AcquisitionChannelMask { get; set; }
            public uint SkipCount              { get; }
            public uint DarkIntensityEndpoint  { get; }
        }
    }
}