using BoFilTest.Domain;
using BoFilTest.Utils;
using Optional;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace BoFilTest.UI
{
    class EndModel : INotifyPropertyChanged
    {
        private readonly DataModel dataModel;
        private const string NOT_MEASURED_MARKER = "NOT_MEASURED_MARKER";

        public EndModel(DataModel dataModel)
        {
            this.dataModel = dataModel;
        }

        public void RefreshAll()
        {
            SendPropertyChanged("");
        }

        private string TimingOr(Func<TestTimings, Option<string>> mapper)
        {
            return this.dataModel.Timings.FlatMap(mapper).ValueOr(Translated.FromKey(NOT_MEASURED_MARKER));
        }

        private string WithTimings(Func<TestTimings, string> mapper)
        {
            return TimingOr(timings => Option.Some(mapper(timings)));
        }

        private string WithTimings(Func<TestTimings, TimeSpan> mapper)
        {
            return WithTimings(timings => Format.MeasuredSeconds(mapper(timings)));
        }

        private string WithTimings(Func<TestTimings, Option<TimeSpan>> mapper)
        {
            return TimingOr(timings => mapper(timings).Map(s => Format.MeasuredSeconds(s)));
        }

        private static Option<TimeSpan> NthTiming(List<TimeSpan> list, int index)
        {
            return list.Count > index ? Option.Some(list[index]) : Option.None<TimeSpan>();
        }

        public string CakeFormationTime => WithTimings(timings => timings.CakeFormationTime);

        public string IntermediateDemoisturizingTime1 => WithTimings(timings => NthTiming(timings.IntermediateDemoisturizing, 0));
        public string IntermediateDemoisturizingTime2 => WithTimings(timings => NthTiming(timings.IntermediateDemoisturizing, 1));
        public string IntermediateDemoisturizingTime3 => WithTimings(timings => NthTiming(timings.IntermediateDemoisturizing, 2));
        public string IntermediateDemoisturizingTime4 => WithTimings(timings => NthTiming(timings.IntermediateDemoisturizing, 3));

        public string WashingTime1 => WithTimings(timings => NthTiming(timings.CakeWash, 0));
        public string WashingTime2 => WithTimings(timings => NthTiming(timings.CakeWash, 1));
        public string WashingTime3 => WithTimings(timings => NthTiming(timings.CakeWash, 2));

        public string PressingTime => WithTimings(timings => timings.Press);
        public string VaporizationTime => WithTimings(timings => timings.Vaporization);
        public string GasBreakthroughTime => WithTimings(timings => timings.GasBreakthrough);
        public string DemoisturizingTime => WithTimings(timings => timings.Demoisturizing);

        public string GasIntegralForArea => dataModel.GasIntegralForArea
            .Map(x => Format.GasIntegralForArea(x)).ValueOr(Translated.FromKey("NOT_MEASURED_MARKER"));

        private AfterTestForm AfterTestForm => dataModel.AfterTestForm;

        public FilterCakeConsistency CakeConsistency
        {
            get { return AfterTestForm.CakeConsistency; }
            set { AfterTestForm.CakeConsistency = value; }
        }

        public FilterCakeCracking CakeCracking
        {
            get { return AfterTestForm.CakeCracking; }
            set { AfterTestForm.CakeCracking = value;  }
        }

        public EdgeDissolution EdgeDissolution
        {
            get { return AfterTestForm.EdgeDissolution; }
            set { AfterTestForm.EdgeDissolution = value;  }
        }
        public double? CakeHeight
        {
            get { return AfterTestForm.CakeHeight; }
            set { AfterTestForm.CakeHeight = value;  }
        }

        public double? CakeWeight
        {
            get { return AfterTestForm.CakeWeight; }
            set { AfterTestForm.CakeWeight = value; }
        }

        public double? Tare
        {
            get { return AfterTestForm.Tare;  }
            set  { AfterTestForm.Tare = value; }
        }

        public double? InitialSuspensionWeight
        {
            get { return AfterTestForm.InitialSuspensionWeight; }
            set { AfterTestForm.InitialSuspensionWeight = value; }
        }

        public bool EvaluateThis
        {
            get { return AfterTestForm.ValidForAnalysis; }
            set { AfterTestForm.ValidForAnalysis = value; }
        }

        public string Notes
        {
            get { return AfterTestForm.Notes; }
            set { AfterTestForm.Notes = value; }
        }

        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;

        private void SendPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
        #endregion
    }
}
