using System;
using System.ComponentModel;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Threading.Tasks;
using System.Runtime.CompilerServices;
using System.Runtime.Serialization;
using System.IO;
using Windows.Storage;
using FooEditEngine;

namespace FooEditor
{
    public class AppSettings
    {
        static ObservableCollection<FileType> _FileTypeCollection;
        static AppSettings _thisInstance = new AppSettings();
        public static AppSettings Current
        {
            get
            {
                if (ApplicationData.Current.LocalSettings.Values["FontFamily"] == null)
                    ApplicationData.Current.LocalSettings.Values["FontFamily"] = "Calibri";
                if (ApplicationData.Current.LocalSettings.Values["FontSize"] == null)
                    ApplicationData.Current.LocalSettings.Values["FontSize"] = 12.0;
                if (ApplicationData.Current.LocalSettings.Values["TabChar"] == null)
                    ApplicationData.Current.LocalSettings.Values["TabChar"] = 4;
                if (ApplicationData.Current.LocalSettings.Values["IsRTL"] == null)
                    ApplicationData.Current.LocalSettings.Values["IsRTL"] = false;
                if (ApplicationData.Current.LocalSettings.Values["ShowLineBreak"] == null)
                    ApplicationData.Current.LocalSettings.Values["ShowLineBreak"] = true;
                if (ApplicationData.Current.LocalSettings.Values["ShowTab"] == null)
                    ApplicationData.Current.LocalSettings.Values["ShowTab"] = true;
                if (ApplicationData.Current.LocalSettings.Values["ShowFullSpace"] == null)
                    ApplicationData.Current.LocalSettings.Values["ShowFullSpace"] = true;
                if (ApplicationData.Current.LocalSettings.Values["ShowRuler"] == null)
                    ApplicationData.Current.LocalSettings.Values["ShowRuler"] = false;
                if (ApplicationData.Current.LocalSettings.Values["ShowLineNumber"] == null)
                    ApplicationData.Current.LocalSettings.Values["ShowLineNumber"] = false;
                if (ApplicationData.Current.LocalSettings.Values["ShowLineMarker"] == null)
                    ApplicationData.Current.LocalSettings.Values["ShowLineMarker"] = true;
                if (ApplicationData.Current.LocalSettings.Values["LineBreakMethod"] == null)
                    ApplicationData.Current.LocalSettings.Values["LineBreakMethod"] = (int)FooEditEngine.LineBreakMethod.None;
                if (ApplicationData.Current.LocalSettings.Values["LineBreakCount"] == null)
                    ApplicationData.Current.LocalSettings.Values["LineBreakCount"] = 80;
                if (ApplicationData.Current.LocalSettings.Values["ShowFoundPattern"] == null)
                    ApplicationData.Current.LocalSettings.Values["ShowFoundPattern"] = false;
                if (ApplicationData.Current.LocalSettings.Values["IndentBySpace"] == null)
                    ApplicationData.Current.LocalSettings.Values["IndentBySpace"] = false;
                if (ApplicationData.Current.LocalSettings.Values["TopMargin"] == null)
                    ApplicationData.Current.LocalSettings.Values["TopMargin"] = 0;
                if (ApplicationData.Current.LocalSettings.Values["RightMargin"] == null)
                    ApplicationData.Current.LocalSettings.Values["RightMargin"] = 0;
                if (ApplicationData.Current.LocalSettings.Values["BottomMargin"] == null)
                    ApplicationData.Current.LocalSettings.Values["BottomMargin"] = 0;
                if (ApplicationData.Current.LocalSettings.Values["LeftMargin"] == null)
                    ApplicationData.Current.LocalSettings.Values["LeftMargin"] = 0;
                if (ApplicationData.Current.LocalSettings.Values["Header"] == null)
                    ApplicationData.Current.LocalSettings.Values["Header"] = "%f";
                if (ApplicationData.Current.LocalSettings.Values["Footer"] == null)
                    ApplicationData.Current.LocalSettings.Values["Footer"] = "-%p-";
                if (_FileTypeCollection == null)
                    LoadFileTypeCollection();
                return _thisInstance;
            }
        }

        private static void LoadFileTypeCollection()
        {
            DataContractSerializer serializer = new DataContractSerializer(typeof(ObservableCollection<FileType>));
            Stream fs = null;
            try
            {
                Task<Stream> task = ApplicationData.Current.LocalFolder.OpenStreamForReadAsync("FileTypes.xml");
                fs = task.Result;
                _FileTypeCollection = (ObservableCollection<FileType>)serializer.ReadObject(fs);
            }
            catch (Exception)
            {
                _FileTypeCollection = new ObservableCollection<FileType>();
                FileType fileType = new FileType("Text", "");
                fileType.ExtensionCollection.Add(".txt");
                _FileTypeCollection.Add(fileType);
                fileType = new FileType("C", "clang.xml");
                fileType.ExtensionCollection.Add(".c");
                fileType.ExtensionCollection.Add(".cs");
                fileType.ExtensionCollection.Add(".cpp");
                fileType.ExtensionCollection.Add(".h");
                _FileTypeCollection.Add(fileType);
                fileType = new FileType("CSS", "css.xml");
                fileType.ExtensionCollection.Add(".css");
                _FileTypeCollection.Add(fileType);
                fileType = new FileType("HTML", "html.xml");
                fileType.ExtensionCollection.Add(".htm");
                fileType.ExtensionCollection.Add(".html");
                fileType.ExtensionCollection.Add(".xhtml");
                _FileTypeCollection.Add(fileType);
                fileType = new FileType("Java", "java.xml");
                fileType.ExtensionCollection.Add(".java");
                _FileTypeCollection.Add(fileType);
                fileType = new FileType("JavaScript", "javascript.xml");
                fileType.ExtensionCollection.Add(".js");
                _FileTypeCollection.Add(fileType);
                fileType = new FileType("Perl", "perl.xml");
                fileType.ExtensionCollection.Add(".pl");
                _FileTypeCollection.Add(fileType);
                fileType = new FileType("PHP", "php.xml");
                fileType.ExtensionCollection.Add(".php");
                _FileTypeCollection.Add(fileType);
                fileType = new FileType("Python", "python.xml");
                fileType.ExtensionCollection.Add(".py");
                _FileTypeCollection.Add(fileType);
                fileType = new FileType("Ruby", "ruby.xml");
                fileType.ExtensionCollection.Add(".rb");
                _FileTypeCollection.Add(fileType);
                fileType = new FileType("VisualBasic", "vb.xml");
                fileType.ExtensionCollection.Add(".vb");
                fileType.ExtensionCollection.Add(".vbs");
                _FileTypeCollection.Add(fileType);
                fileType = new FileType("XML", "xml.xml");
                fileType.ExtensionCollection.Add(".xml");
                _FileTypeCollection.Add(fileType);
            }
            finally
            {
                if (fs != null)
                    fs.Dispose();
            }
        }

        public async Task Save()
        {
            DataContractSerializer serializer = new DataContractSerializer(typeof(ObservableCollection<FileType>));
            StorageFile file = await ApplicationData.Current.LocalFolder.CreateFileAsync("FileTypes.xml",CreationCollisionOption.ReplaceExisting);
            using (Stream fs = await file.OpenStreamForWriteAsync())
            {
                serializer.WriteObject(fs, _FileTypeCollection);
            }
        }

        public bool IndentBySpace
        {
            get
            {
                return (bool)ApplicationData.Current.LocalSettings.Values["IndentBySpace"];
            }
            set
            {
                ApplicationData.Current.LocalSettings.Values["IndentBySpace"] = value;
                this.OnChangedSetting();
            }
        }

        public bool ShowFoundPattern
        {
            get
            {
                return (bool)ApplicationData.Current.LocalSettings.Values["ShowFoundPattern"];
            }
            set
            {
                ApplicationData.Current.LocalSettings.Values["ShowFoundPattern"] = value;
                this.OnChangedSetting();
            }
        }

        public LineBreakMethod LineBreakMethod
        {
            get
            {
                return (LineBreakMethod)(int)ApplicationData.Current.LocalSettings.Values["LineBreakMethod"];
            }
            set
            {
                ApplicationData.Current.LocalSettings.Values["LineBreakMethod"] = (int)value;
                this.OnChangedSetting();
            }
        }

        public int TopMargin
        {
            get
            {
                return (int)ApplicationData.Current.LocalSettings.Values["TopMargin"];
            }
            set
            {
                ApplicationData.Current.LocalSettings.Values["TopMargin"] = value;
                this.OnChangedSetting();
            }
        }

        public string Header
        {
            get
            {
                return (string)ApplicationData.Current.LocalSettings.Values["Header"];
            }
            set
            {
                ApplicationData.Current.LocalSettings.Values["Header"] = value;
                this.OnChangedSetting();
            }
        }

        public string Footer
        {
            get
            {
                return (string)ApplicationData.Current.LocalSettings.Values["Footer"];
            }
            set
            {
                ApplicationData.Current.LocalSettings.Values["Footer"] = value;
                this.OnChangedSetting();
            }
        }

        public int RightMargin
        {
            get
            {
                return (int)ApplicationData.Current.LocalSettings.Values["RightMargin"];
            }
            set
            {
                ApplicationData.Current.LocalSettings.Values["RightMargin"] = value;
                this.OnChangedSetting();
            }
        }

        public int BottomMargin
        {
            get
            {
                return (int)ApplicationData.Current.LocalSettings.Values["BottomMargin"];
            }
            set
            {
                ApplicationData.Current.LocalSettings.Values["BottomMargin"] = value;
                this.OnChangedSetting();
            }
        }

        public int LeftMargin
        {
            get
            {
                return (int)ApplicationData.Current.LocalSettings.Values["LeftMargin"];
            }
            set
            {
                ApplicationData.Current.LocalSettings.Values["LeftMargin"] = value;
                this.OnChangedSetting();
            }
        }

        public int LineBreakCount
        {
            get
            {
                return (int)ApplicationData.Current.LocalSettings.Values["LineBreakCount"];
            }
            set
            {
                ApplicationData.Current.LocalSettings.Values["LineBreakCount"] = value;
                this.OnChangedSetting();
            }
        }

        public ObservableCollection<FileType> FileTypeCollection
        {
            get
            {
                return _FileTypeCollection;
            }
        }

        public string FontFamily
        {
            get
            {
                return (string)ApplicationData.Current.LocalSettings.Values["FontFamily"];
            }
            set
            {
                ApplicationData.Current.LocalSettings.Values["FontFamily"] = value;
                this.OnChangedSetting();
            }
        }

        public double FontSize
        {
            get
            {
                return (double)ApplicationData.Current.LocalSettings.Values["FontSize"];
            }
            set
            {
                ApplicationData.Current.LocalSettings.Values["FontSize"] = value;
                this.OnChangedSetting();
            }
        }

        public int TabChar
        {
            get
            {
                return (int)ApplicationData.Current.LocalSettings.Values["TabChar"];
            }
            set
            {
                ApplicationData.Current.LocalSettings.Values["TabChar"] = value;
                this.OnChangedSetting();
            }
        }

        public bool IsRTL
        {
            get
            {
                return (bool)ApplicationData.Current.LocalSettings.Values["IsRTL"];
            }
            set
            {
                ApplicationData.Current.LocalSettings.Values["IsRTL"] = value;
                this.OnChangedSetting();
            }
        }

        public bool ShowTab
        {
            get
            {
                return (bool)ApplicationData.Current.LocalSettings.Values["ShowTab"];
            }
            set
            {
                ApplicationData.Current.LocalSettings.Values["ShowTab"] = value;
                this.OnChangedSetting();
            }
        }

        public bool ShowFullSpace
        {
            get
            {
                return (bool)ApplicationData.Current.LocalSettings.Values["ShowFullSpace"];
            }
            set
            {
                ApplicationData.Current.LocalSettings.Values["ShowFullSpace"] = value;
                this.OnChangedSetting();
            }
        }

        public bool ShowLineBreak
        {
            get
            {
                return (bool)ApplicationData.Current.LocalSettings.Values["ShowLineBreak"];
            }
            set
            {
                ApplicationData.Current.LocalSettings.Values["ShowLineBreak"] = value;
                this.OnChangedSetting();
            }
        }

        public bool ShowRuler
        {
            get
            {
                return (bool)ApplicationData.Current.LocalSettings.Values["ShowRuler"];
            }
            set
            {
                ApplicationData.Current.LocalSettings.Values["ShowRuler"] = value;
                this.OnChangedSetting();
            }
        }

        public bool ShowLineNumber
        {
            get
            {
                return (bool)ApplicationData.Current.LocalSettings.Values["ShowLineNumber"];
            }
            set
            {
                ApplicationData.Current.LocalSettings.Values["ShowLineNumber"] = value;
                this.OnChangedSetting();
            }
        }

        public bool ShowLineMarker
        {
            get
            {
                return (bool)ApplicationData.Current.LocalSettings.Values["ShowLineMarker"];
            }
            set
            {
                ApplicationData.Current.LocalSettings.Values["ShowLineMarker"] = value;
                this.OnChangedSetting();
            }
        }

        public void OnChangedSetting()
        {
            if (ChangedSetting != null)
                ChangedSetting(this, null);
        }

        public event EventHandler ChangedSetting;
        public event EventHandler OccueredShare;
    }

    [DataContract]
    public class FileType : INotifyPropertyChanged
    {
        [DataMember]
        ObservableCollection<string> _ExtensionCollection;
        [DataMember]
        string _DocumentTypeName,_DocumentType;
        [DataMember]
        bool _ShowTab;
        [DataMember]
        bool _ShowFullSpace;
        [DataMember]
        bool _ShowRuler;
        [DataMember]
        bool _ShowLineNumber;
        [DataMember]
        bool _ShowLineBreak;
        [DataMember]
        bool _NoInherit;
        [DataMember]
        LineBreakMethod _LineBreakMethod;
        [DataMember]
        int _LineBreakCount;
        [DataMember]
        bool _IndentBySpace;
        [DataMember]
        int _TabCharCount;

        public ObservableCollection<string> ExtensionCollection
        {
            get
            {
                return this._ExtensionCollection;
            }
        }

        public string DocumentTypeName
        {
            get
            {
                return _DocumentTypeName;
            }
            set
            {
                _DocumentTypeName = value;
            }
        }
        
        public string DocumentType
        {
            get
            {
                return this._DocumentType;
            }
            set
            {
                this._DocumentType = value;
            }
        }

        public bool NoInherit
        {
            get
            {
                return this._NoInherit;
            }
            set
            {
                this._NoInherit = value;
                this.OnPropertyChanged();
            }
        }

        public bool IndentBySpace
        {
            get
            {
                return _IndentBySpace;
            }
            set
            {
                _IndentBySpace = value;
                this.OnPropertyChanged();
            }
        }

        public bool ShowTab
        {
            get
            {
                return this._ShowTab;
            }
            set
            {
                this._ShowTab = value;
                this.OnPropertyChanged();
            }
        }

        public bool ShowFullSpace
        {
            get
            {
                return this._ShowFullSpace;
            }
            set
            {
                this._ShowFullSpace = value;
                this.OnPropertyChanged();
            }
        }

        public bool ShowLineBreak
        {
            get
            {
                return this._ShowLineBreak;
            }
            set
            {
                this._ShowLineBreak = value;
                this.OnPropertyChanged();
            }
        }

        public bool ShowRuler
        {
            get
            {
                return this._ShowRuler;
            }
            set
            {
                this._ShowRuler = value;
                this.OnPropertyChanged();
            }
        }

        public bool ShowLineNumber
        {
            get
            {
                return this._ShowLineNumber;
            }
            set
            {
                this._ShowLineNumber = value;
                this.OnPropertyChanged();
            }
        }

        public LineBreakMethod LineBreakMethod
        {
            get
            {
                return this._LineBreakMethod;
            }
            set
            {
                this._LineBreakMethod = value;
                this.OnPropertyChanged();
            }
        }

        public int LineBreakCount
        {
            get
            {
                return this._LineBreakCount;
            }
            set
            {
                this._LineBreakCount = value;
                this.OnPropertyChanged();
            }
        }

        public int TabCharCount
        {
            get
            {
                return this._TabCharCount;
            }
            set
            {
                this._TabCharCount = value;
                this.OnPropertyChanged();
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        public FileType()
            : this(string.Empty,string.Empty)
        {
        }

        public FileType(string name, string doctype)
        {
            this._ExtensionCollection = new ObservableCollection<string>();
            this._DocumentTypeName = name;
            this._DocumentType = doctype;
            this._NoInherit = false;
            this._ShowFullSpace = false;
            this._ShowLineNumber = false;
            this._ShowRuler = false;
            this._ShowTab = false;
            this._IndentBySpace = false;
            this._LineBreakMethod = FooEditEngine.LineBreakMethod.None;
            this._LineBreakCount = 80;
            this._TabCharCount = 4;
        }

        public void OnPropertyChanged([CallerMemberName] string caller = "")
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(caller));
        }
    }
}
