using System;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Collections.Generic;
using System.Xml.Linq;
using System.Xml;
using System.Reflection;
using System.IO;
using System.ComponentModel;

namespace ControlExplorer
{
    public class MainViewModel
    {
        #region ** fields

        private static MainViewModel _instance = null;
        private IEnumerable<ControlDescription> _controls;
        private IEnumerable<NewFeatureDescription> _newFeatures;

        #endregion

        #region ** object model

        public static MainViewModel Instance
        {
            get
            {
                if (_instance == null)
                    _instance = new MainViewModel();
                return _instance;
            }
        }

        public IEnumerable<ControlDescription> Controls
        {
            get
            {
                if (_controls == null)
                {
                    LoadControls();
                }
                return _controls;
            }
        }

        public IEnumerable<FeatureDescription> Features
        {
            get
            {
                return Controls.SelectMany(c => c.GetAllFeatures());
            }
        }

        public IEnumerable<NewFeatureDescription> NewFeatures
        {
            get
            {
                if (Controls != null)
                {
                    if (_newFeatures == null)
                    {
                        var doc = LoadXmlResource("ControlExplorer.Resources.NewFeatures.xml");
                        _newFeatures = (from c in doc.Root.Elements("Feature")
                                     select new NewFeatureDescription(c)).ToList();
                    }
                }
                return _newFeatures;
            }
        }
        #endregion

        #region private stuff
        private void LoadControls()
        {
            var doc = LoadXmlResource("ControlExplorer.Resources.ControlList.xml");
            _controls = (from c in doc.Root.Elements("Control")
                         select new ControlDescription(c)).ToList();
             
            BackgroundWorker bw = new BackgroundWorker();
            bw.DoWork += (s, e) =>
                {
                    System.Threading.Thread.Sleep(2000);
                    LoadPaths();
                };
            bw.RunWorkerAsync();
        }

        private void LoadPaths()
        {
            var xamlPaths = ReadResource("ControlExplorer.Resources.XamlPaths.txt").Where(path => !path.Contains("\\VB"));
            var slnPaths = ReadResource("ControlExplorer.Resources.SlnPaths.txt").Where(path => !path.Contains("\\VB"));
            var errors = new List<string>();
            foreach (var feature in Features)
            {
                if (feature.AssemblyName.StartsWith("C1.Silverlight")) continue;
                var folder = "\\" + PlatformUtils.StripPlatformSuffix(feature.AssemblyName, false) + "\\";

                var xaml = PlatformUtils.AdjustPlatformXamlName("\\" + feature.DemoControlTypeName.Substring(feature.DemoControlTypeName.LastIndexOf('.') + 1) + ".xaml", false);
                foreach (var xamlPath in xamlPaths)
                {
                    if (xamlPath.EndsWith(xaml) && xamlPath.Contains(folder))
                    {
                        if (feature.XamlPath != null)
                        {
                            errors.Add(feature.DemoControlTypeName + " also found at " + xamlPath);
                        }
                        else
                        {
                            feature.XamlPath = xamlPath;
                        }
                    }
                }
                if (feature.XamlPath == null)
                {
                    errors.Add(feature.DemoControlTypeName + " not found");
                }
                else
                {
                    foreach (var slnPath in slnPaths)
                    {
                        var slnDir = System.IO.Path.GetDirectoryName(slnPath);
                        if (feature.XamlPath.StartsWith(slnDir))
                        {
                            if (feature.SolutionPath != null && feature.SolutionPath != slnDir)
                            {
                                errors.Add(feature.AssemblyName + " also found at " + slnDir);
                            }
                            else
                            {
                                feature.SolutionPath = slnDir;
                            }
                        }
                    }
                    if (feature.SolutionPath == null)
                    {
                        errors.Add(feature.AssemblyName + " solution not found");
                    }
                }
            }
#if DEBUG
            if (errors.Count > 0)
            {
                System.Text.StringBuilder bld = new System.Text.StringBuilder("File search errors:\r\n");
                foreach (string error in errors)
                {
                    bld.AppendLine("   " + error);
                }
                System.Diagnostics.Debug.WriteLine(bld.ToString());
            }
#endif
        }

        private static XDocument LoadXmlResource(string resourceName)
        {
            var assembly = Assembly.GetExecutingAssembly();
            return XDocument.Load(XmlReader.Create(assembly.GetManifestResourceStream(resourceName)));
        }

        private static List<string> ReadResource(string manifestName)
        {
            var xamlPaths = new List<string>();
            using (var reader = new StreamReader(Assembly.GetExecutingAssembly().GetManifestResourceStream(manifestName)))
            {
                while (true)
                {
                    var line = reader.ReadLine();
                    if (line == null) break;
                    var common = "\\Samples\\SL\\";
                    var relativePath = line.Substring(line.IndexOf(common) + common.Length);
                    xamlPaths.Add(relativePath);
                }
            }
            return xamlPaths;
        }
        #endregion
    }
}
