using System;
using System.Collections.Generic;
using System.IO;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using Microsoft.Win32;
using FooEditEngine;
using FooEditEngine.WPF;
using FooEditor.Properties;

namespace FooEditor
{
    public class Config : DependencyObject
    {
        static private Config _instance;

        public const string RegAppPath = "Software\\FooProject\\FooEditor";
        const string SyntaxDefinitionPath = RegAppPath + "\\SytaxDefinition";

        public string FontName
        {
            get { return (string)GetValue(FontNameProperty); }
            set { SetValue(FontNameProperty, value); }
        }
        public static readonly DependencyProperty FontNameProperty =
            DependencyProperty.Register("FontName", typeof(string), typeof(Config), new PropertyMetadata(""));

        public string GrepPath
        {
            get { return (string)GetValue(GrepPathProperty); }
            set { SetValue(GrepPathProperty, value); }
        }
        public static readonly DependencyProperty GrepPathProperty =
            DependencyProperty.Register("GrepPath", typeof(string), typeof(Config), new PropertyMetadata(""));

        public TextAntialiasMode TextAntialiasMode
        {
            get { return (TextAntialiasMode)GetValue(TextAntialiasModeProperty); }
            set { SetValue(TextAntialiasModeProperty, value); }
        }

        // Using a DependencyProperty as the backing store for TextAntialiasMode.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty TextAntialiasModeProperty =
            DependencyProperty.Register("TextAntialiasMode", typeof(TextAntialiasMode), typeof(Config), new PropertyMetadata(TextAntialiasMode.Default));
        
        public string Header
        {
            get { return (string)GetValue(HeaderProperty); }
            set { SetValue(HeaderProperty, value); }
        }
        public static readonly DependencyProperty HeaderProperty =
            DependencyProperty.Register("Header", typeof(string), typeof(Config), new PropertyMetadata(""));

        public string Footer
        {
            get { return (string)GetValue(FooterProperty); }
            set { SetValue(FooterProperty, value); }
        }
        public static readonly DependencyProperty FooterProperty =
            DependencyProperty.Register("Footer", typeof(string), typeof(Config), new PropertyMetadata(""));

        public double FontSize
        {
            get { return (double)GetValue(FontSizeProperty); }
            set { SetValue(FontSizeProperty, value); }
        }
        public static readonly DependencyProperty FontSizeProperty =
            DependencyProperty.Register("FontSize", typeof(double), typeof(Config), new PropertyMetadata(0.0));

        public double Height
        {
            get { return (double)GetValue(HeightProperty); }
            set { SetValue(HeightProperty, value); }
        }
        public static readonly DependencyProperty HeightProperty =
            DependencyProperty.Register("Height", typeof(double), typeof(Config), new PropertyMetadata(0.0));

        public double Width
        {
            get { return (double)GetValue(WidthProperty); }
            set { SetValue(WidthProperty, value); }
        }
        public static readonly DependencyProperty WidthProperty =
            DependencyProperty.Register("Width", typeof(double), typeof(Config), new PropertyMetadata(0.0));

        public double TopSpace
        {
            get { return (double)GetValue(TopSpaceProperty); }
            set { SetValue(TopSpaceProperty, value); }
        }
        public static readonly DependencyProperty TopSpaceProperty =
            DependencyProperty.Register("TopSpace", typeof(double), typeof(Config), new PropertyMetadata(0.0));

        public double RightSpace
        {
            get { return (double)GetValue(RightSpaceProperty); }
            set { SetValue(RightSpaceProperty, value); }
        }
        public static readonly DependencyProperty RightSpaceProperty =
            DependencyProperty.Register("RightSpace", typeof(double), typeof(Config), new PropertyMetadata(0.0));

        public double BottomSpace
        {
            get { return (double)GetValue(BottomSpaceProperty); }
            set { SetValue(BottomSpaceProperty, value); }
        }
        public static readonly DependencyProperty BottomSpaceProperty =
            DependencyProperty.Register("BottomSpace", typeof(double), typeof(Config), new PropertyMetadata(0.0));

        public double LeftSpace
        {
            get { return (double)GetValue(LeftSpaceProperty); }
            set { SetValue(LeftSpaceProperty, value); }
        }
        public static readonly DependencyProperty LeftSpaceProperty =
            DependencyProperty.Register("LeftSpace", typeof(double), typeof(Config), new PropertyMetadata(0.0));

        public int MaxBackupCount
        {
            get { return (int)GetValue(MaxBackupCountProperty); }
            set { SetValue(MaxBackupCountProperty, value); }
        }
        public static readonly DependencyProperty MaxBackupCountProperty =
            DependencyProperty.Register("MaxBackupCount", typeof(int), typeof(Config), new PropertyMetadata(0));

        public int TabStops
        {
            get { return (int)GetValue(TabStopsProperty); }
            set { SetValue(TabStopsProperty, value); }
        }
        public static readonly DependencyProperty TabStopsProperty =
            DependencyProperty.Register("TabStops", typeof(int), typeof(Config), new PropertyMetadata(0));

        public int AutoSaveCount
        {
            get { return (int)GetValue(AutoSaveCountProperty); }
            set { SetValue(AutoSaveCountProperty, value); }
        }
        public static readonly DependencyProperty AutoSaveCountProperty =
            DependencyProperty.Register("AutoSaveCount", typeof(int), typeof(Config), new PropertyMetadata(0));

        public bool WordRap
        {
            get { return (bool)GetValue(WordRapProperty); }
            set { SetValue(WordRapProperty, value); }
        }
        public static readonly DependencyProperty WordRapProperty =
            DependencyProperty.Register("WordRap", typeof(bool), typeof(Config), new PropertyMetadata(false));

        public bool DrawLine
        {
            get { return (bool)GetValue(DrawLineProperty); }
            set { SetValue(DrawLineProperty, value); }
        }
        public static readonly DependencyProperty DrawLineProperty =
            DependencyProperty.Register("DrawLine", typeof(bool), typeof(Config), new PropertyMetadata(false));

        public bool DrawRuler
        {
            get { return (bool)GetValue(DrawRulerProperty); }
            set { SetValue(DrawRulerProperty, value); }
        }

        // Using a DependencyProperty as the backing store for DrawRuler.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty DrawRulerProperty =
            DependencyProperty.Register("DrawRuler", typeof(bool), typeof(Config), new PropertyMetadata(false));        

        public bool UrlMark
        {
            get { return (bool)GetValue(UrlMarkProperty); }
            set { SetValue(UrlMarkProperty, value); }
        }
        public static readonly DependencyProperty UrlMarkProperty =
            DependencyProperty.Register("UrlMark", typeof(bool), typeof(Config), new PropertyMetadata(false));

        public bool AutoIndent
        {
            get { return (bool)GetValue(AutoIndentProperty); }
            set { SetValue(AutoIndentProperty, value); }
        }
        public static readonly DependencyProperty AutoIndentProperty =
            DependencyProperty.Register("AutoIndent", typeof(bool), typeof(Config), new PropertyMetadata(false));

        public bool DrawLineNumber
        {
            get { return (bool)GetValue(DrawLineNumberProperty); }
            set { SetValue(DrawLineNumberProperty, value); }
        }

        // Using a DependencyProperty as the backing store for DrawLineNumber.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty DrawLineNumberProperty =
            DependencyProperty.Register("DrawLineNumber", typeof(bool), typeof(Config), new PropertyMetadata(false));
        
        public Color Fore
        {
            get { return (Color)GetValue(ForeProperty); }
            set { SetValue(ForeProperty, value); }
        }
        public static readonly DependencyProperty ForeProperty =
            DependencyProperty.Register("Fore", typeof(Color), typeof(Config), new PropertyMetadata(Colors.Black));

        public Color Back
        {
            get { return (Color)GetValue(BackProperty); }
            set { SetValue(BackProperty, value); }
        }
        public static readonly DependencyProperty BackProperty =
            DependencyProperty.Register("Back", typeof(Color), typeof(Config), new PropertyMetadata(Colors.White));

        public Color Hilight
        {
            get { return (Color)GetValue(HilightProperty); }
            set { SetValue(HilightProperty, value); }
        }
        public static readonly DependencyProperty HilightProperty =
            DependencyProperty.Register("Hilight", typeof(Color), typeof(Config), new PropertyMetadata(Colors.Blue));

        public Color URL
        {
            get { return (Color)GetValue(URLProperty); }
            set { SetValue(URLProperty, value); }
        }
        public static readonly DependencyProperty URLProperty =
            DependencyProperty.Register("URL", typeof(Color), typeof(Config), new PropertyMetadata(Colors.Blue));

        public Color Keyword1
        {
            get { return (Color)GetValue(Keyword1Property); }
            set { SetValue(Keyword1Property, value); }
        }
        public static readonly DependencyProperty Keyword1Property =
            DependencyProperty.Register("Keyword1", typeof(Color), typeof(Config), new PropertyMetadata(Colors.Blue));

        public Color Keyword2
        {
            get { return (Color)GetValue(Keyword2Property); }
            set { SetValue(Keyword2Property, value); }
        }
        public static readonly DependencyProperty Keyword2Property =
            DependencyProperty.Register("Keyword2", typeof(Color), typeof(Config), new PropertyMetadata(Colors.Aqua));

        public Color Control
        {
            get { return (Color)GetValue(ControlProperty); }
            set { SetValue(ControlProperty, value); }
        }
        public static readonly DependencyProperty ControlProperty =
            DependencyProperty.Register("Control", typeof(Color), typeof(Config), new PropertyMetadata(Colors.Gray));

        public Color Literal
        {
            get { return (Color)GetValue(LiteralProperty); }
            set { SetValue(LiteralProperty, value); }
        }
        public static readonly DependencyProperty LiteralProperty =
            DependencyProperty.Register("Literal", typeof(Color), typeof(Config), new PropertyMetadata(Colors.Brown));

        public Color Comment
        {
            get { return (Color)GetValue(CommentProperty); }
            set { SetValue(CommentProperty, value); }
        }
        public static readonly DependencyProperty CommentProperty =
            DependencyProperty.Register("Comment", typeof(Color), typeof(Config), new PropertyMetadata(Colors.Green));

        public Color InsetCaret
        {
            get { return (Color)GetValue(InsetCaretProperty); }
            set { SetValue(InsetCaretProperty, value); }
        }
        public static readonly DependencyProperty InsetCaretProperty =
            DependencyProperty.Register("InsetCaret", typeof(Color), typeof(Config), new PropertyMetadata(Colors.Gray));

        public Color OverwriteCaret
        {
            get { return (Color)GetValue(OverwriteCaretProperty); }
            set { SetValue(OverwriteCaretProperty, value); }
        }
        public static readonly DependencyProperty OverwriteCaretProperty =
            DependencyProperty.Register("OverwriteCaret", typeof(Color), typeof(Config), new PropertyMetadata(Colors.Gray));


        public Color LineMarker
        {
            get { return (Color)GetValue(LineMarkerProperty); }
            set { SetValue(LineMarkerProperty, value); }
        }
        public static readonly DependencyProperty LineMarkerProperty =
            DependencyProperty.Register("LineMarker", typeof(Color), typeof(Config), new PropertyMetadata(Colors.Gray));

        private Config()
        {
            this.RecentFile = new RecentFileCollection();
            this.DontLoadPlugins = new List<string>();
            this.SyntaxDefinitions = new DocumentTypeCollection();
        }

        static public Config GetInstance()
        {
            if (_instance == null)
            {
                _instance = new Config();
                _instance.Load();
            }
            return _instance;
        }

        public static string ApplicationFolder
        {
            get
            {
                return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),"FooEditor");
            }
        }

        public static string ExecutablePath
        {
            get
            {
                return Path.GetDirectoryName(Environment.GetCommandLineArgs()[0]);
            }
        }

        public int RecentMaxCount
        {
            get { return this.RecentFile.MaxCount; }
            set { this.RecentFile.MaxCount = value; }
        }

        public RecentFileCollection RecentFile
        {
            get;
            private set;
        }
        
        public DocumentTypeCollection SyntaxDefinitions
        {
            get;
            private set;
        }

        public List<string> DontLoadPlugins
        {
            get;
            private set;
        }

        public void Load()
        {
            RegistryKey regkey = Registry.CurrentUser.CreateSubKey(RegAppPath);
            
            this.FontName = (string)regkey.GetValue("FontName", SystemFonts.MessageFontFamily.Source);
            this.FontSize = double.Parse((string)regkey.GetValue("FontSize", SystemFonts.MessageFontSize.ToString()));
            this.Height = double.Parse((string)regkey.GetValue("Height","480"));
            this.Width = double.Parse((string)regkey.GetValue("Width", "640"));
            this.MaxBackupCount = (int)regkey.GetValue("MaxBackupCount", 4);
            this.RecentMaxCount = (int)regkey.GetValue("RecentCount", 4);
            this.WordRap = bool.Parse((string)regkey.GetValue("WordRap","false"));
            this.DrawLine = bool.Parse((string)regkey.GetValue("DrawLine", "true"));
            this.UrlMark = bool.Parse((string)regkey.GetValue("UrlMark", "false"));
            this.DrawLineNumber = bool.Parse((string)regkey.GetValue("DrawLineNumber", "false"));
            this.DrawRuler = bool.Parse((string)regkey.GetValue("DrawRuler", "false"));
            this.AutoSaveCount = (int)regkey.GetValue("AutoSaveCount", 0);
            string[] temps = (string[])regkey.GetValue("RecentFile", new string[0]);
            foreach (string temp in temps)
                this.RecentFile.Add(temp);
            temps = (string[])regkey.GetValue("DontLoadPlugin", new string[0]);
            this.DontLoadPlugins.AddRange(temps);
            this.TabStops = (int)regkey.GetValue("TabStops", 4);
            this.GrepPath = (string)regkey.GetValue("GrepPath", Config.ExecutablePath + "\\FooGrep.EXE");
            this.Fore = (Color)ColorConverter.ConvertFromString((string)regkey.GetValue("ForeColor", SystemColors.WindowTextColor.ToString()));
            this.Back = (Color)ColorConverter.ConvertFromString((string)regkey.GetValue("BackColor",SystemColors.WindowColor.ToString()));
            this.Comment = (Color)ColorConverter.ConvertFromString((string)regkey.GetValue("CommentColor", Colors.Green.ToString()));
            this.Keyword1 = (Color)ColorConverter.ConvertFromString((string)regkey.GetValue("Keyword1Color", Colors.Blue.ToString()));
            this.Keyword2 = (Color)ColorConverter.ConvertFromString((string)regkey.GetValue("Keyword2Color", Colors.DarkCyan.ToString()));
            this.Literal = (Color)ColorConverter.ConvertFromString((string)regkey.GetValue("LiteralColor", Colors.Brown.ToString()));
            this.Control = (Color)ColorConverter.ConvertFromString((string)regkey.GetValue("ControlColor", Colors.Gray.ToString()));
            this.URL = (Color)ColorConverter.ConvertFromString((string)regkey.GetValue("URLColor", Colors.Blue.ToString()));
            Color DefalutHilight = SystemColors.HighlightColor;
            DefalutHilight.A = 128;
            this.Hilight = (Color)ColorConverter.ConvertFromString((string)regkey.GetValue("HilightColor", DefalutHilight.ToString()));
            this.InsetCaret = (Color)ColorConverter.ConvertFromString((string)regkey.GetValue("InsetCaretColor", SystemColors.WindowTextColor.ToString()));
            Color DefalutOverwriteCaret = SystemColors.WindowTextColor;
            DefalutOverwriteCaret.A = 128;
            this.OverwriteCaret = (Color)ColorConverter.ConvertFromString((string)regkey.GetValue("OverwriteCaretColor", DefalutOverwriteCaret.ToString()));
            Color DefalutLineMarker = SystemColors.WindowTextColor;
            DefalutLineMarker.A = 25;
            this.LineMarker = (Color)ColorConverter.ConvertFromString((string)regkey.GetValue("LineMarkerColor", DefalutLineMarker.ToString()));
            this.TopSpace = double.Parse((string)regkey.GetValue("TopSpace", "0"));
            this.RightSpace = double.Parse((string)regkey.GetValue("RightSpace", "0"));
            this.BottomSpace = double.Parse((string)regkey.GetValue("BottomSpace", "0"));
            this.LeftSpace = double.Parse((string)regkey.GetValue("LeftSpace", "0"));
            this.Header = (string)regkey.GetValue("Header", "%f");
            this.Footer = (string)regkey.GetValue("Fotter", "-%p-");
            this.AutoIndent = bool.Parse((string)regkey.GetValue("AutoIndent", "false"));
            this.TextAntialiasMode = (TextAntialiasMode)regkey.GetValue("TextAntialiasMode", (int)TextAntialiasMode.Default);
            regkey.Close();

            regkey = Registry.CurrentUser.OpenSubKey(SyntaxDefinitionPath);
            if (regkey == null)
                regkey = SetDefalutSytax();
            string[] names = regkey.GetValueNames();
            this.SyntaxDefinitions.Clear();
            this.SyntaxDefinitions.Add(Resources.DocumetTypeNone, null);
            this.SyntaxDefinitions.Select(Resources.DocumetTypeNone);
            foreach (string name in names)
                if (name != "")
                    this.SyntaxDefinitions.Add(name, (string)regkey.GetValue(name));
            regkey.Close();

            return;
        }
        public void Save()
        {
            RegistryKey regkey = Registry.CurrentUser.CreateSubKey(RegAppPath);
            regkey.SetValue("FontName", this.FontName);
            regkey.SetValue("FontSize", this.FontSize);
            regkey.SetValue("Height", this.Height);
            regkey.SetValue("Width", this.Width);
            regkey.SetValue("MaxBackupCount", this.MaxBackupCount);
            regkey.SetValue("RecentCount", this.RecentMaxCount);
            regkey.SetValue("WordRap", this.WordRap);
            regkey.SetValue("DrawLine", this.DrawLine);
            regkey.SetValue("DrawRuler", this.DrawRuler);
            regkey.SetValue("RecentFile", this.RecentFile.ToArray());
            regkey.SetValue("DontLoadPlugin", this.DontLoadPlugins.ToArray());
            regkey.SetValue("TabStops", this.TabStops);
            regkey.SetValue("UrlMark", this.UrlMark);
            regkey.SetValue("GrepPath", this.GrepPath);
            regkey.SetValue("AutoSaveCount", this.AutoSaveCount);
            regkey.SetValue("ForeColor", this.Fore.ToString());
            regkey.SetValue("BackColor", this.Back.ToString());
            regkey.SetValue("CommentColor", this.Comment.ToString());
            regkey.SetValue("Keyword1Color", this.Keyword1.ToString());
            regkey.SetValue("Keyword2Color", this.Keyword2.ToString());
            regkey.SetValue("LiteralColor", this.Literal.ToString());
            regkey.SetValue("ControlColor", this.Control.ToString());
            regkey.SetValue("InsetCaretColor", this.InsetCaret.ToString());
            regkey.SetValue("OverwriteCaretColor", this.OverwriteCaret.ToString());
            regkey.SetValue("LineMarkerColor", this.LineMarker.ToString());
            regkey.SetValue("URLColor", this.URL.ToString());
            regkey.SetValue("HilightColor", this.Hilight.ToString());
            regkey.SetValue("DrawLineNumber", this.DrawLineNumber);
            regkey.SetValue("TopSpace", this.TopSpace);
            regkey.SetValue("RightSpace", this.RightSpace);
            regkey.SetValue("BottomSpace", this.BottomSpace);
            regkey.SetValue("LeftSpace", this.LeftSpace);
            regkey.SetValue("Header", this.Header);
            regkey.SetValue("Fotter", this.Footer);
            regkey.SetValue("AutoIndent",this.AutoIndent);
            regkey.SetValue("TextAntialiasMode", (int)this.TextAntialiasMode);
            regkey.Close();

            regkey =  Registry.CurrentUser.CreateSubKey(SyntaxDefinitionPath);
            foreach (DocumentType item in SyntaxDefinitions)
            {
                if(item.Name != Resources.DocumetTypeNone && item.Extension != null)
                    regkey.SetValue(item.Name, item.Extension);
            }
            regkey.Close();            
        }

        private RegistryKey SetDefalutSytax()
        {
            RegistryKey regkey = Registry.CurrentUser.CreateSubKey(SyntaxDefinitionPath);
            regkey.SetValue("clang.xml", ".+\\.(c|cpp|cs)$");
            regkey.SetValue("css.xml", ".+\\.(css)$");
            regkey.SetValue("html.xml", ".+\\.(htm|html|xhtml)$");
            regkey.SetValue("javascript.xml", ".+\\.(js)$");
            regkey.SetValue("php.xml", ".+\\.(php)$");
            regkey.SetValue("python.xml", ".+\\.(py)$");
            regkey.SetValue("ruby.xml", ".+\\.(rb)$");
            regkey.SetValue("vb.xml", ".+\\.(vb|vbs)$");
            regkey.SetValue("perl.xml", ".+\\.(pl)$");
            regkey.SetValue("java.xml", ".+\\.(java)$");
            regkey.SetValue("xml.xml", ".+\\.(xml)$");
            return regkey;
        }
    }
}
