// Created with MonoDevelop
//
//    Copyright (C) 2019 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.IO;
using System.Xml.Serialization;

using Hiperscan.Unix;


namespace Hiperscan.SGS.Common
{

    [Serializable()]
    public class HardwareProperties
    {
        public string Type { set; get; }
        public double GridConstant { set; get; }
        public double IncidenceAngle { set; get; }
        public double DiffractionAngle { set; get; }
        public double MaxTemperature { set; get; }
        public double MinTemperature { set; get; }
        public double SpectralResolution { set; get; }
        public double WavelengthDrift { set; get; }
        public double Sensitivity { set; get; }
        public double SignalNoiseRatio { set; get; }
        public double DynamicRange { set; get; }
        public double MinWavelength { set; get; }
        public double MaxWavelength { set; get; }
        public double WavelengthIncrement { set; get; }
        public double WavelengthExtension { set; get; }
        public uint MinAverage { set; get; }
        public uint MaxAverage { set; get; }
        public ushort MEMSInfo { set; get; }
        public ushort AdcConfigurationId { set; get; }

        private bool is_invalid = false;


        public HardwareProperties()
        {
            // default properties
            this.Type = Catalog.GetString("n/a");
            this.GridConstant = 1600;
            this.IncidenceAngle = 10.0;
            this.DiffractionAngle = 15.0;
            this.MinTemperature = 15.0;
            this.MaxTemperature = 60.0;
            this.WavelengthDrift = 0.1;
            this.SpectralResolution = 10.0;
            this.Sensitivity = 0.0;
            this.SignalNoiseRatio = 200.0;
            this.DynamicRange = 0.0;
            this.MinWavelength = 1000.0;
            this.MaxWavelength = 1900.0;
            this.WavelengthIncrement = 1.0;
            this.WavelengthExtension = 0.0;
            this.MinAverage = 1;
            this.MaxAverage = 2000;
            this.MEMSInfo = 0;
            this.AdcConfigurationId = 0;
        }

        public HardwareProperties(string type, double grid_constant, double incident_angle, 
                                  double min_temp, double max_temp, double spectral_resolution, 
                                  double wavelength_drift, double sensitivity, double signal_noise_ratio,
                                  double dynamic_range, double refraction_angle, uint min_average, uint max_average)
        {
            this.Type = type;
            this.GridConstant = grid_constant;
            this.IncidenceAngle = incident_angle;
            this.DiffractionAngle = refraction_angle;
            this.MaxTemperature = max_temp;
            this.MinTemperature = min_temp;
            this.SpectralResolution = spectral_resolution;
            this.Sensitivity = sensitivity;
            this.SignalNoiseRatio = signal_noise_ratio;
            this.DynamicRange = dynamic_range;
            this.MinAverage = min_average;
            this.MaxAverage = max_average;
        }

        public void SetInvalid()
        {
            this.is_invalid = true;
            this.Type = Catalog.GetString("n/a");
            this.GridConstant = 0;
            this.IncidenceAngle = 0;
            this.DiffractionAngle = 0;
            this.MinTemperature = 0;
            this.MaxTemperature = 0;
            this.WavelengthDrift = 0;
            this.SpectralResolution = 0;
            this.Sensitivity = 0.0;
            this.SignalNoiseRatio = 0.0;
            this.DynamicRange = 0.0;
            this.MinWavelength = 0.0;
            this.MaxWavelength = 0.0;
            this.WavelengthIncrement = 0.0;
            this.WavelengthExtension = 0.0;
            this.MinAverage = 0;
            this.MaxAverage = 0;
        }

        public static HardwareProperties Read(string fname)
        {
            using (Stream stream = new FileStream(fname, FileMode.Open, FileAccess.Read))
            {
                XmlSerializer serializer = new XmlSerializer(typeof(HardwareProperties));
                HardwareProperties properties = (HardwareProperties)serializer.Deserialize(stream);

                if (properties == null)
                    throw new Exception(Catalog.GetString("Error while deserialization."));

                return properties;
            }
        }

        public void WriteToFile(string fname)
        {
            using (Stream stream = new FileStream(fname, FileMode.Create))
            {
                XmlSerializer serializer = new XmlSerializer(typeof(HardwareProperties));
                serializer.Serialize(stream, this);
            }
        }

        public static void CreateTemplate(string fname)
        {
            HardwareProperties properies = new HardwareProperties();
            properies.WriteToFile(fname);
        }

        private string _na(double val, string fmt, string unit)
        {
            if (val <= 0.0)
                return Catalog.GetString("n/a");
            return val.ToString(fmt) + unit;
        }

        public override string ToString()
        {
            System.Text.StringBuilder sb = new System.Text.StringBuilder();
            sb.AppendFormat(Catalog.GetString("Type:                      {0}"), this.Type);
            sb.AppendLine();
            sb.AppendFormat(Catalog.GetString("Grid constant:             {0}"), _na(this.GridConstant, "f0", "nm"));
            sb.AppendLine();
            sb.AppendFormat(Catalog.GetString("Incidence angle:           {0}"), _na(this.IncidenceAngle, "f1", "°"));
            sb.AppendLine();
            sb.AppendFormat(Catalog.GetString("Diffraction angle:         {0}"), _na(this.DiffractionAngle, "f1", "°"));
            sb.AppendLine();
            sb.AppendFormat(Catalog.GetString("Min. temperature:          {0}"), _na(this.MinTemperature, "f1", "°C"));
            sb.AppendLine();
            sb.AppendFormat(Catalog.GetString("Max. temperature:          {0}"), _na(this.MaxTemperature, "f1", "°C"));
            sb.AppendLine();
            sb.AppendFormat(Catalog.GetString("Spectral resolution:       {0}"), _na(this.SpectralResolution, "f1", "nm"));
            sb.AppendLine();
            sb.AppendFormat(Catalog.GetString("Wavelength drift:          {0}"), _na(this.WavelengthDrift, "f1", "nm/K"));
            sb.AppendLine();
            sb.AppendFormat(Catalog.GetString("Sensitivity:               {0}"), _na(this.Sensitivity, "f1", ""));
            sb.AppendLine();
            sb.AppendFormat(Catalog.GetString("Signal-to-noise ratio:     {0}"), _na(this.SignalNoiseRatio, "f0", ""));
            sb.AppendLine();
            sb.AppendFormat(Catalog.GetString("Dynamic range:             {0}"), _na(this.DynamicRange, "f1", ""));
            sb.AppendLine();
            sb.AppendFormat(Catalog.GetString("Min. wavelength:           {0}"), _na(this.MinWavelength, "f1", "nm"));
            sb.AppendLine();
            sb.AppendFormat(Catalog.GetString("Max. wavelength:           {0}"), _na(this.MaxWavelength, "f1", "nm"));
            sb.AppendLine();
            sb.AppendFormat(Catalog.GetString("Wavelength increment:      {0}"), _na(this.WavelengthIncrement, "f1", "nm"));
            sb.AppendLine();
            sb.AppendFormat(Catalog.GetString("Wavelength extension:      {0}"), _na(this.WavelengthExtension, "f1", "nm"));
            sb.AppendLine();
            sb.AppendFormat(Catalog.GetString("Min. average:              {0}"), _na(this.MinAverage, "f0", ""));
            sb.AppendLine();
            sb.AppendFormat(Catalog.GetString("Max. average:              {0}"), _na(this.MaxAverage, "f0", ""));
            sb.AppendLine();
            sb.AppendFormat(Catalog.GetString("MEMS info:                 {0}"), _na(this.MEMSInfo, "f0", ""));
            sb.AppendLine();
            sb.AppendFormat(Catalog.GetString("ADC configuration ID:      {0}"), this.AdcConfigurationId);

            return sb.ToString();
        }

        public bool IsInvalid
        {
            get { return this.is_invalid; }
        }
    }
}