// Created with MonoDevelop
//
//    Copyright (C) 2023 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.Linq;
using Hiperscan.Spectroscopy;

namespace Hiperscan.SGS.Benchtop.TemperatureControl
{
    public class Temperature
    {
        public Temperature(int history_count = 10, int time_interval_sec = 300)
        {
            this.MaxHistoryCount = history_count;
            this.TimeIntervallSec = time_interval_sec;
        }

        public void Add(double temperature)
        {
            DateTime date = DateTime.Now;
            if (this.Temperatures.Count == this.MaxHistoryCount)
            {
                DateTime tmp = this.Temperatures.OrderBy(x => x.Key).Select(t => t.Key).First();
                this.Temperatures.Remove(tmp);
            }

            this.Temperatures.Add(date, temperature);
        }

        public Temperature Clone()
        {
            return new Temperature()
            {
                MaxHistoryCount = this.MaxHistoryCount,
                TimeIntervallSec = this.TimeIntervallSec,
                Temperatures = new Dictionary<DateTime, double>(this.Temperatures)
            };
        }

        public double GradientDegreePerHour
        {
            get
            {
                if (this.Temperatures.Count < 2)
                    return double.NaN;

                DateTime past = this.Temperatures.Keys.Last().AddSeconds(-this.TimeIntervallSec);

                double[] temperatures = this.Temperatures.Where(t => t.Key >= past).
                                            Select(t => t.Value).
                                            ToArray();

                if (temperatures.Count() < 2)
                    return double.NaN;

                double[] measure_numbers = Enumerable.Range(1, temperatures.Count()).
                                                     Select(i => (double)i).
                                                     ToArray();

                DataSet ds = new DataSet(measure_numbers, temperatures);
                double slope = ds.LinearRegression().Slope;
                TimeSpan diff = this.Temperatures.Keys.Last() - this.Temperatures.Keys.First(d => d > past);
                return slope / diff.TotalHours;
            }
        }

        public double LastTemperature
        {
            get
            {
                return this.Temperatures.Count > 0 ? this.Temperatures.Values.Last() : Double.NaN;
            }
        }

        public override string ToString()
        {
            double gradient = this.GradientDegreePerHour;

            string gradient_text = String.Empty;
            if (Double.IsNaN(gradient))
                gradient_text = "n/a";
            else
                gradient_text = String.Format("{0:F5}°C/h", gradient);

            return String.Format("Temperature = {0}°C; Gradient = {1}",
                                 this.LastTemperature,
                                 gradient_text);
        }

        public int TimeIntervallSec { get; protected set; }
        public int MaxHistoryCount { get; protected set; }
        public Dictionary<DateTime, double> Temperatures { get; set; } = new Dictionary<DateTime, double>();
    }
}
