using System.Collections.ObjectModel;
using System.ComponentModel;
using Windows.Storage;

namespace PCUT.ViewModels
{
    public class SvgNestSettings : INotifyPropertyChanged
    {
        private SvgNestSettings() { }
        private static readonly object _instanceLock = new object();
        private static SvgNestSettings _instance;
        public static SvgNestSettings Instance
        {
            get
            {
                if (_instance == null)
                {
                    lock (_instanceLock)
                    {
                        if (_instance == null)
                        {
                            _instance = new SvgNestSettings();
                            _instance.LoadSettings();
                            _instance.ApplySettings();
                        }
                    }
                }
                return _instance;
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        private int _maxNumberOfRun = 10;
        public int MaxNumberOfRun
        {
            get => _maxNumberOfRun;
            set
            {
                _maxNumberOfRun = value;
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(MaxNumberOfRun)));
            }
        }

        private int _maxRuntimeInMinutes = 5;
        public int MaxRuntimeInMinute
        {
            get => _maxRuntimeInMinutes;
            set
            {
                _maxRuntimeInMinutes = value;
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(MaxRuntimeInMinute)));
            }
        }

        private double _curveTolerance = 0.3;
        public double CurveTolerance
        {
            get => _curveTolerance;
            set
            {
                _curveTolerance = value;
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(CurveTolerance)));
            }
        }

        private double _spacing = 0;
        public double Spacing
        {
            get => _spacing;
            set
            {
                _spacing = value;
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Spacing)));
            }
        }

        public ObservableCollection<int> ValidRotations = new ObservableCollection<int> { 2, 4, 8 };
        private int _rotations = 4;
        public int Rotations
        {
            get => _rotations;
            set
            {
                if (_rotations != value)
                {
                    _rotations = value;
                    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Rotations)));
                }
            }
        }

        private int _populationSize = 10;
        public int PopulationSize
        {
            get => _populationSize;
            set
            {
                _populationSize = value;
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(PopulationSize)));
            }
        }

        private int _mutationRate = 10;
        public int MutationRate
        {
            get => _mutationRate;
            set
            {
                _mutationRate = value;
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(MutationRate)));
            }
        }


        private bool _useHoles = true;
        public bool UseHoles
        {
            get => _useHoles;
            set
            {
                _useHoles = value;
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(UseHoles)));
            }
        }

        private bool _exploreConcave = true;
        public bool ExploreConcave
        {
            get => _exploreConcave;
            set
            {
                _exploreConcave = value;
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(ExploreConcave)));
            }
        }

        private object this[string key]
        {
            get
            {
                return GetType().GetProperty(key).GetValue(this);
            }
            set
            {
                GetType().GetProperty(key).SetValue(this, value);
            }
        }

        private static readonly string[] Keys = new string[]
        {
            nameof(MaxNumberOfRun),
            nameof(MaxRuntimeInMinute),
            nameof(CurveTolerance),
            nameof(Spacing),
            nameof(Rotations),
            nameof(PopulationSize),
            nameof(MutationRate),
            nameof(UseHoles),
            nameof(ExploreConcave)
        };

        public void SaveSettings()
        {
            foreach (var key in Keys)
            {
                SaveSetting($"Nest{key}", this[key]);
            }
        }

        public void LoadSettings()
        {
            foreach (var key in Keys)
            {
                var value = LoadSetting($"Nest{key}");
                if (value != null)
                    this[key] = value;
            }
        }

        public void ApplySettings()
        {
            var config = DeepNestApi.SvgNest.Config;
            config.curveTolerance = CurveTolerance;
            config.spacing = Spacing;
            config.rotations = Rotations;
            config.populationSize = PopulationSize;
            config.mutationRate = MutationRate;
            config.useHoles = UseHoles;
            config.exploreConcave = ExploreConcave;
        }

        private static object LoadSetting(string key)
        {
            return ApplicationData.Current.LocalSettings.Values[key];
        }

        private static void SaveSetting(string key, object value)
        {
            ApplicationData.Current.LocalSettings.Values[key] = value;
        }
    }
}
