using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Xml;
using Aitex.Core.UI.View.Common;
using Caliburn.Micro.Core;
using DocumentFormat.OpenXml.Spreadsheet;
using DocumentFormat.OpenXml.Wordprocessing;
using MECF.Framework.UI.Client.CenterViews.Configs.SystemConfig;

namespace MECF.Framework.UI.Client.CenterViews.Editors.Sequence
{
    public class FileNode : PropertyChangedBase
    {
        #region Variables

        private string _name = string.Empty;

        #endregion

        #region Constructors
        public FileNode()
        {
            this.Files = new ObservableCollection<FileNode>();
            this.IsFile = false;
        }

        #endregion

        #region Properties

        public string Name
        {
            get { return _name; }
            set { _name = value; NotifyOfPropertyChange("Name"); }
        }
        public string FullPath { get; set; }

        public FileNode Parent { get; set; }

        public ObservableCollection<FileNode> Files { get; set; }

        public bool IsFile { get; set; }

        public string PrefixPath { get; set; }

        public bool IsSelected { get; set; }

        private bool _isExpanded;
        public bool IsExpanded
        {
            get { return _isExpanded; }
            set { _isExpanded = value; NotifyOfPropertyChange("IsExpanded"); }
        }

        private Visibility _isMatch;
        public Visibility IsMatch
        {
            get { return _isMatch; }
            set { _isMatch = value; NotifyOfPropertyChange("IsMatch"); }
        }

        #endregion

        #region Methods

        /// <summary>
        /// 将数中的节点转换为节点数组。
        /// </summary>
        /// <param name="terminalOnly">是否仅枚举最末端节点。</param>
        /// <para>更新子节点的Selected属性时，需要同时更新中间节点的属性；更新父节点时，只评估终端节点的Selected属性。</para>
        /// <returns></returns>
        private List<FileNode> Flatten(bool terminalOnly)
        {
            if (Files == null || Files.Count <= 0)
                return new List<FileNode>(new[] { this });

            var lst = Files.SelectMany(x => x.Flatten(terminalOnly)).ToList();
            if (!terminalOnly)
                lst.Add(this);

            return lst;
        }

        /// <summary>
        /// 选择指定的节点。
        /// </summary>
        /// <param name="fullPath"></param>
        public void Select(string fullPath)
        {
            var flattenList = Flatten(true);
            flattenList.ForEach(x => { x.IsSelected = x.FullPath == fullPath; });
            Refresh();
        }
        private bool IsCriteriaMatched(string criteria)
        {
            bool matched = string.IsNullOrEmpty(criteria) || _name.ToLower().Contains(criteria.ToLower());

            if (matched)
                return true;

            return false;
        }

        public void ApplyCriteria(string criteria, Stack<FileNode> ancestors)
        {
            if (IsCriteriaMatched(criteria))
            {
                IsMatch = Visibility.Visible;
                foreach (var ancestor in ancestors)
                {
                    ancestor.IsMatch = Visibility.Visible;
                    ancestor.IsExpanded = !string.IsNullOrEmpty(criteria);
                }
                IsExpanded = true;
            }
            else
                IsMatch = Visibility.Collapsed;

            ancestors.Push(this);
            foreach (var child in Files)
                child.ApplyCriteria(criteria, ancestors);

            ancestors.Pop();
        }

        #endregion
    }

    public class RecipeSequenceTreeBuilder
    {
        public static List<FileNode> GetFiles(string prefixPath, List<string> filenames)
        {
            List<FileNode> folders = new List<FileNode>();
            FileNode root = new FileNode() { Name = "Files", IsFile = false, FullPath = "", PrefixPath = prefixPath };
            folders.Add(root);

            foreach (string filename in filenames)
            {
                string[] filesplits = filename.Split('\\');

                FileNode parent = root;
                if (filesplits.Length > 1)
                {
                    for (var index = 0; index < filesplits.Length - 1; index++)
                    {
                        bool found = false;
                        for (var j = 0; j < parent.Files.Count; j++)
                        {
                            if (parent.Files[j].Name == filesplits[index] && !parent.Files[j].IsFile)
                            {
                                found = true;
                                parent = parent.Files[j];
                                break;
                            }
                        }
                        if (!found)
                        {
                            FileNode folder = new FileNode() { Name = filesplits[index], IsFile = false, PrefixPath = prefixPath };
                            folder.FullPath = (parent.FullPath == string.Empty ? filesplits[index] : parent.FullPath + "\\" + filesplits[index]);
                            folder.Parent = parent;
                            parent.Files.Add(folder);
                            parent = folder;
                        }
                    }
                }
                FileNode file = new FileNode() { Name = filesplits[filesplits.Length - 1], IsFile = true, PrefixPath = prefixPath };
                file.FullPath = (parent.FullPath == string.Empty ? filesplits[filesplits.Length - 1] : parent.FullPath + "\\" + filesplits[filesplits.Length - 1]);
                file.Parent = parent;
                parent.Files.Add(file);
            }
            return folders;
        }

        public static void CreateTreeViewItems(XmlElement curElementNode, FileNode parent, string prefixPath, string selectionName, bool selectionIsFolder, bool isFolderNodeOnly)
        {
            foreach (XmlElement ele in curElementNode.ChildNodes)
            {
                if (ele.Name == "File" && !isFolderNodeOnly)
                {
                    var fileName = ele.Attributes["Name"].Value;
                    fileName = fileName.Substring(fileName.LastIndexOf('\\') + 1);
                    var fullPath = string.IsNullOrEmpty(parent.FullPath)
                        ? fileName
                        : parent.FullPath + "\\" + fileName;
                    var file = new FileNode()
                    {
                        Name = fileName,
                        IsFile = true,
                        PrefixPath = prefixPath,
                        Parent = parent,
                        FullPath = fullPath,
                    };
                    if (!selectionIsFolder && selectionName == file.FullPath)
                    {
                        file.IsSelected = true;
                        var node = file.Parent;
                        while (node.FullPath.Contains("\\"))
                        {
                            node.IsExpanded = true;
                            node = node.Parent;
                        }
                    }
                    parent.Files.Add(file);
                }
                else if (ele.Name == "Folder")
                {
                    var folderName = ele.Attributes["Name"].Value;
                    folderName = folderName.Substring(folderName.LastIndexOf('\\') + 1);
                    var fullPath = string.IsNullOrEmpty(parent.FullPath)
                        ? folderName
                        : parent.FullPath + "\\" + folderName;
                    var folder = new FileNode()
                    {
                        Name = folderName,
                        IsFile = false,
                        PrefixPath = prefixPath,
                        Parent = parent,
                        FullPath = fullPath,
                        IsExpanded = !fullPath.Contains("\\"),
                    };
                    parent.Files.Add(folder);
                    if (selectionIsFolder && selectionName == folder.FullPath)
                    {
                        folder.IsSelected = true;
                        var node = folder;
                        while (node.FullPath.Contains("\\"))
                        {
                            node.IsExpanded = true;
                            node = node.Parent;
                        }
                    }
                    CreateTreeViewItems(ele, folder, prefixPath, selectionName, selectionIsFolder, isFolderNodeOnly);
                }
            }
        }

        /// <summary>
        /// 创建Recipe文件树。
        /// </summary>
        /// <param name="prefixPath"></param>
        /// <param name="selectionName"></param>
        /// <param name="selectionIsFolder"></param>
        /// <param name="fileListInXml"></param>
        /// <param name="isFolderNodeOnly">是否仅显示文件夹</param>
        /// <param name="isShowRoot">是否显示根节点</param>
        /// <returns></returns>
        public static List<FileNode> BuildFileNode(string prefixPath, string selectionName, bool selectionIsFolder, string fileListInXml, bool isFolderNodeOnly = false, bool isShowRoot = false)
        {
            var folders = new List<FileNode>();
            var root = new FileNode() { Name = "Files", IsFile = false, FullPath = "", PrefixPath = prefixPath };
            folders.Add(root);

            // 是否显示根目录节点
            if (isShowRoot)
            {
                root.Files.Add(new FileNode()
                    { Name = "\\", IsExpanded = true, PrefixPath = prefixPath, IsFile = false, FullPath = "", });

                root = root.Files[0];
            }

            var doc = new XmlDocument();
            doc.LoadXml(fileListInXml);
            CreateTreeViewItems(doc.DocumentElement, root, prefixPath, selectionName, selectionIsFolder, isFolderNodeOnly);

            return folders;
        }
    }
}
