using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Windows.Forms;
using System.Xml.Serialization;

namespace Azyobuzi.Twirunrun
{
    public abstract class SettingsBase<T>
        : INotifyPropertyChanged
        where T : SettingsBase<T>, new()
    {
        protected static string GetFileName()
        {
            return string.Format("{0}\\settings\\{1}.xml", Application.StartupPath, typeof(T).Name);
        }

        private static T instance;
        public static T Instance
        {
            get
            {
                if (instance == null)
                {
                    try
                    {
                        using (var sr = new StreamReader(GetFileName()))
                        {
                            var xs = new XmlSerializer(typeof(T));
                            instance = (T)xs.Deserialize(sr);
                        }
                    }
                    catch
                    {
                        instance = new T();
                    }
                }

                return instance;
            }
        }

        public void Save()
        {
            Save(GetFileName());
        }

        private void Save(string filename)
        {
            Directory.CreateDirectory(Path.GetDirectoryName(filename));
            using (var sw = new StreamWriter(filename))
            {
                var xs = new XmlSerializer(typeof(T));
                xs.Serialize(sw, this);
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        protected void OnPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }

        /// <summary>
        /// このクラスのすべてのプロパティ名を使用してPropertyChangedイベントを発生させる
        /// </summary>
        public void RaiseAllEvents()
        {
            this.GetType().GetProperties()
                .Select(property => property.Name)
                .ForEach(OnPropertyChanged);
        }
    }
}
