using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Threading;
using C1.Silverlight.Docking;
using System.Diagnostics;
using C1.Silverlight;
using C1.Silverlight.RichTextBox;
using System.Xml.Linq;
using System.Reflection;
using VSDev9.Controls;

namespace VSDev9
{
    public partial class MainPage : UserControl
    {
        public MainPage()
        {
            InitializeComponent();

            InitializeDockElements();
        }

        #region VS Look & feel

        private void dockControl_PickerLoading(object sender, PickerLoadingEventArgs e)
        {
            if (docs.Items.Contains(e.Source))
            {
                e.ShowLeftInnerPart = false;
                e.ShowLeftOuterPart = false;
                e.ShowTopInnerPart = false;
                e.ShowTopOuterPart = false;
                e.ShowRightInnerPart = false;
                e.ShowRightOuterPart = false;
                e.ShowBottomInnerPart = false;
                e.ShowBottomOuterPart = false;
                e.ShowOverInnerPart = false;
            }
        }

        private void dockControl_ViewChanged(object sender, EventArgs e)
        {
            var list = new List<C1MenuItem>();
            foreach (var nestedTabControl in dockControl.NestedItems)
            {
                var tabControl = nestedTabControl; // must be fresh each loop iteration because of the delegate
                if (tabControl == docs)
                    continue;

                foreach (var item in tabControl.Items)
                {
                    var tabItem = (C1DockTabItem)item; // must be fresh each loop iteration because of the delegate
                    var menuItem = new C1MenuItem();
                    menuItem.Header = tabItem.Header;
                    menuItem.Click += delegate
                    {
                        switch (tabControl.DockMode)
                        {
                            case DockMode.Hidden:
                                tabControl.DockMode = DockMode.Docked;
                                break;
                            case DockMode.Sliding:
                                tabControl.SlideOpen();
                                break;
                        }
                        tabItem.IsSelected = true;
                    };
                    list.Add(menuItem);
                }
            }

            ViewMenuItem.Items.Clear();
            foreach (var menuItem in list.OrderBy(mi => mi.Header))
            {
                ViewMenuItem.Items.Add(menuItem);
            }
        }

        #endregion

        #region Add dock elements

        int item_count;

        void AddDocking_Click(object sender, SourcedEventArgs e)
        {
            Add(DockMode.Docked);
        }
        void AddSliding_Click(object sender, SourcedEventArgs e)
        {
            Add(DockMode.Sliding);
        }

        void Add(DockMode dockMode)
        {
            dockControl.Items.Insert(0, new C1DockTabControl
            {
                DockMode = dockMode,
                Items =
                {
                    new C1DockTabItem
                    {
                        Header = "tab " + item_count,
                        Content = "tab " + item_count,                        
                    },
                },
            });
            item_count++;
        }

        #endregion

        #region Toggle DockMode programatically

        private void ToggleWindowMode_Click(object sender, SourcedEventArgs e)
        {
            var sliding = FindSlidingTabControl();

            var value = (DockMode)(sliding.DockMode + 1);
            if (!Enum.IsDefined(typeof(DockMode), value))
            {
                value = 0;
            }
            sliding.DockMode = value;
        }

        private void ToggleTabStripPlacement_Click(object sender, SourcedEventArgs e)
        {
            var sliding = FindSlidingTabControl();

            sliding.TabStripPlacement = (Dock)(sliding.TabStripPlacement + 1);
            if (!Enum.IsDefined(typeof(Dock), sliding.TabStripPlacement))
            {
                sliding.TabStripPlacement = 0;
            }
        }

        private C1DockTabControl FindSlidingTabControl()
        {
            var sliding =  dockControl.NestedItems.Where(t => t.DockMode == DockMode.Sliding).FirstOrDefault();
            if (sliding == null) 
            {
                // create sliding panel
                sliding = new C1DockTabControl() { DockMode = DockMode.Sliding, Dock = Dock.Left };
                dockControl.Items.Add(sliding);
            }
            return sliding;
        }

        #endregion

        #region Different Pane interaction

        C1DockTabControl docs = null;
        Output output = null;

        private void InitializeDockElements()
        {
            if ((docs != null) && (output != null))
                return;

            foreach (C1DockTabControl tab in dockControl.NestedItems)
            {
                // find docs container, wire events and save reference
                if ((tab.Tag != null) && (tab.Tag.ToString() == "docs"))
                {
                    tab.ItemsChanged += docs_ItemsChanged;
                    tab.TabItemClosed += docs_TabClosed;
                    docs = tab;
                }

                // get output window
                var res = tab.Items.Cast<C1DockTabItem>().Where(i => i.Content is Output);
                if (res.FirstOrDefault() != null) 
                {
                    output = res.First().Content as Output;
                }

                // wire events of the SolutionExplorer
                res = tab.Items.Cast<C1DockTabItem>().Where(i => i.Content is SolutionExplorer);
                if (res.FirstOrDefault() != null) 
                {
                    var solExplorer = res.First().Content as SolutionExplorer;
                    solExplorer.FileSelected += SolutionExplorer_FileSelected;
                }
            }

            UpdateWindowMenuItem();
        }

        private void docs_ItemsChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            UpdateWindowMenuItem();
        }

        private void UpdateWindowMenuItem()
        {
            if (WindowMenuItem == null | docs == null)
                return;

            WindowMenuItem.Items.Clear();
            foreach (var item in docs.Items)
            {
                var tabItem = item as C1DockTabItem; // must be fresh each loop iteration because of the delegate
                var menuItem = new C1MenuItem();
                menuItem.Header = tabItem.Header;
                menuItem.Click += delegate
                {
                    tabItem.IsSelected = true;
                };
                WindowMenuItem.Items.Add(menuItem);
            }
        }

        private void docs_TabClosed(object sender, SourcedEventArgs e)
        {
            var tabItem = e.Source as C1TabItem;
            if (output != null)
            {
                output.Text += tabItem.Header.ToString() + " closed...\n";
            }
        }

        private void SolutionExplorer_FileSelected(object sender, EventArgs e)
        {
            var solExplorer = (SolutionExplorer)sender;

            var fileEditor = new FileEditor();
            fileEditor.FileName = solExplorer.SelectedFileName;

            var tabItem = new C1DockTabItem()
            {
                Header = fileEditor.FileName,
                Content = fileEditor
            };

            docs.Items.Add(tabItem);
            (tabItem.Parent as C1TabControl).SelectedItem = tabItem;
        }

        #endregion

        #region Import & Export..

        private void ImportDocking_Click(object sender, SourcedEventArgs e)
        {
            // gets the file to import the settings from
            var dlg = new OpenFileDialog();
            if (dlg.ShowDialog() == true) 
            {
                XDocument doc;
                using (var stream = dlg.File.OpenRead()) 
                {
                    doc = XDocument.Load(stream);
                }
                // Clear and re-configure the dockControl from the settings
                dockControl.Items.Clear();
                C1DockSettings settings = dockControl.Load(doc.Root);
                foreach (var item in settings.Items)
                {
                    // handle the docs container
                    var tabControl = item.Object as C1DockTabControl;
                    if (tabControl != null)
                    {
                        var tagAttrribute = item.Element.Attribute("MyTag");
                        if (tagAttrribute != null)
                        {
                            tabControl.Tag = tagAttrribute.Value;
                        }
                    }

                    // Now, we will handle the C1DockTabItem's content
                    var tabItem = item.Object as C1DockTabItem;
                    if (tabItem != null)
                    {
                        if (item.Element.Value != null)
                        {
                            // Retrieve the information stored in the XElement
                            var innerElem = item.Element.FirstNode as XElement;
                            var headerAtt = item.Element.Attribute("MyHeader");

                            tabItem.Header = headerAtt.Value;
                            tabItem.Content = ControlsFactory.Create(innerElem.Name.LocalName);

                            // file editor needs to save even more stuff
                            var fileEditor = tabItem.Content as FileEditor;
                            if (fileEditor != null)
                            {
                                fileEditor.FileText = innerElem.Value;
                            }
                        }
                    }
                }

                // re initialize local variables
                output = null;
                docs = null;
                InitializeDockElements();
            }
        }

        private void ExportDocking_Click(object sender, SourcedEventArgs e)
        {
            // save settings in a file
            var dlg = new SaveFileDialog();
            dlg.DefaultExt = ".docking.xml";
            if (dlg.ShowDialog() == true)
            {
                // Save the settings into a XElement and put into a XDocument
                var settings = dockControl.Save();
                foreach (var item in settings.Items)
                {
                    // We will inject custom settings for the docs container
                    // because we use a tag there that later reference from the code
                    var tabControl = item.Object as C1DockTabControl;
                    if (tabControl != null)
                    {
                        if (tabControl.Tag != null)
                        {
                            var tagAttribute = new XAttribute("MyTag", tabControl.Tag.ToString());
                            item.Element.Add(tagAttribute);
                        }
                    }


                    // We will inject custom settings for the C1DockTabItem's content
                    var tabItem = item.Object as C1DockTabItem;
                    if (tabItem != null)
                    {
                        // We need a way to save the content we have in each tab item.
                        // In this case, we inspect the element using the ControlsFactory 
                        // class but you can use whatever you want 
                        // (like the x:Name, a custom property, etc).
                        //
                        // You will get this information back once the settings are loaded,
                        // so it's important to store all the information required to recreate
                        // the object instance once reloaded.
                        // 
                        // We save the content as an inner element and the header text as
                        // a custom attribute in the tabItem xml element.
                        var headerAtt = new XAttribute("MyHeader", tabItem.Header);
                        var innerElem = new XElement(ControlsFactory.GetControlKey(tabItem.Content as Control));

                        item.Element.Add(headerAtt);
                        item.Element.Add(innerElem);

                        // file editor needs to save even more stuff
                        var fileEditor = tabItem.Content as FileEditor;
                        if (fileEditor != null)
                        {
                            innerElem.Add(fileEditor.FileText);
                        }
                    }
                }
                var doc = new XDocument();
                doc.Add(settings.Root);

                using (var stream = dlg.OpenFile()) 
                {
                    // save into the stream
                    doc.Save(stream);
                }
            }
            
        }

        #endregion

    }

}
