using System;
using System.Linq;
using System.Net;
using System.Windows;
using System.Collections.Generic;
using System.Xml.Linq;
using System.Xml;
using System.Reflection;
using System.IO;
using System.ComponentModel;
using System.Threading.Tasks;

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

        private static MainViewModel _instance = null;

        #endregion

        #region ** object model

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

        public IEnumerable<ControlDescription> Controls { get; private set; }

        public ControlDescription GetControl(string name)
        {
            return _instance.Controls.Where(c => c.Name == name).First<ControlDescription>();
        }

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

        public IEnumerable<NewFeatureDescription> NewFeatures { get; private set; }

        #endregion

        #region private stuff
        private async Task LoadControls()
        {
            var doc = await LoadXmlResource("Resources/ControlList.xml");
            Controls = (from c in doc.Root.Elements("Control")
                         select new ControlDescription(c)).ToList();
        }

        private async Task LoadNewFeatures()
        {
            var doc = await LoadXmlResource("Resources/NewFeatures.xml");
            NewFeatures = (from c in doc.Root.Elements("Feature")
                            select new NewFeatureDescription(c)).ToList();
        }
        private async Task LoadPaths()
        {
            var xamlPaths = (await ReadResource("Resources/XamlPaths.txt")).Where(path => !path.Contains("\\VB"));
            var slnPaths = (await ReadResource("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 async Task<XDocument> LoadXmlResource(string resourceName)
        {
            var uri = new Uri("ms-appx:///" + resourceName);
            var file = await Windows.Storage.StorageFile.GetFileFromApplicationUriAsync(uri);
            return XDocument.Load(await file.OpenStreamForReadAsync());
        }

        private static async Task<List<string>> ReadResource(string resourceName)
        {
            var xamlPaths = new List<string>();
            var uri = new Uri("ms-appx:///" + resourceName);
            var file = await Windows.Storage.StorageFile.GetFileFromApplicationUriAsync(uri);
            using (var reader = new StreamReader(await file.OpenStreamForReadAsync()))
            {
                while (true)
                {
                    var line = reader.ReadLine();
                    if (line == null) break;
                    var common = "\\Controls\\SL\\";
                    var relativePath = line.Substring(line.IndexOf(common) + common.Length);
                    xamlPaths.Add(relativePath);
                }
            }
            return xamlPaths;
        }
        #endregion

        public async Task Load()
        {
            await LoadControls();
            await LoadNewFeatures();
        }
    }
}
