using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using CommonAI.Zone;
using CommonFroms.Utils;
using CommonLang.Concurrent;
using System.IO;
using CommonLang.Property.Modeling;
using CommonAI.Zone.ZoneEditor;
using CommonLang;
using CommonFroms.G2D;
using CommonFroms.G2D.DataGrid;

namespace CommonAIEditor
{
    public interface IDataManager
    {
        object SelectedData { get; }
        TreeNode TreeRoot { get; }
        object GetNodeData(string id);
        object ShowSelectTemplateDialog(object obj);
        bool ShowSelectTemplateIDDialog(object obj, out int id);
        void SaveEditorStatus();
    }
    public partial class DataManagerPanel<T> : UserControl, IDataManager
        where T : class, ITemplateData, new()
    {
        private Random random = new Random();
        private string categoryText;
        private Type dataType;
        private G2DTreeNodeRoot<T> rootNode;
        public G2DTreeNodeRoot<T> TreeRoot { get { return rootNode; } }
        public string SaveDir { get { return rootNode.Dir; } }

        public DataManagerPanel(
            string category,
            string dir,
            string set_dir,
            ImageList imageList,
            string groupImageKey,
            string childImageKey)
        {
            InitializeComponent();

            if (!Directory.Exists(dir))
            {
                Directory.CreateDirectory(dir);
            }
            if (!Directory.Exists(set_dir))
            {
                Directory.CreateDirectory(set_dir);
            }

            this.dataType = typeof(T);
            this.categoryText = category;

            this.groupBtn_AddNode.Text = ("添加 " + category);

            this.rootNode = new G2DTreeNodeRoot<T>(category, dir, set_dir);
            this.rootNode.ImageKey = groupImageKey;
            this.rootNode.ChildsImageKey = childImageKey;
            this.rootNode.ContextMenuStrip = groupMenu;
            this.rootNode.ChildsContextMenuStrip = childMenu;

            this.treeView.SelectedImageKey = groupImageKey;
            this.treeView.ImageKey = groupImageKey;
            this.treeView.ImageList = imageList;
            this.treeView.TreeViewNodeSorter = new G2DTreeNodeComparer();
            this.treeView.Nodes.Add(rootNode);

            this.Dock = System.Windows.Forms.DockStyle.Fill;
            
        }

        public int GetTryLoadCount()
        {
            return rootNode.GetTryLoadCount();
        }
        public void LoadAll(AtomicInteger progress)
        {
            this.rootNode.LoadAll(Editor.Instance.MessageFactory, progress);
            this.rootNode.Invoke(() =>
            {
                this.rootNode.Expand();
            });
        }

        public void SetEnableDataGrid(bool e)
        {
            groupBtn_Balance.Visible = e;
            groupBtn_EditAll.Visible = e;
            groupBtn_Balance.Enabled = e;
            groupBtn_EditAll.Enabled = e;
        }

        public TreeView GetTreeView()
        {
            return treeView;
        }

        public void AddChildMenuItem(int index, ToolStripItem append)
        {
            childMenu.Items.Insert(index, append);
        }


        public void SaveEditorStatus()
        {
            rootNode.SaveState();
        }


        public T GetNodeData(string id)
        {
            G2DTreeNode<T> cn = rootNode.FindNode(id);
            if (cn != null)
            {
                return cn.Data;
            }
            return default(T);
        }

        public List<T> GetAllNodeData()
        {
            List<T> ret = new List<T>();
            foreach (G2DTreeNode<T> cn in rootNode.GetG2DList())
            {
                ret.Add(cn.Data);
            }
            return ret;
        }

        public List<G2DTreeNode<T>> GetAllNode()
        {
            List<G2DTreeNode<T>> ret = new List<G2DTreeNode<T>>();
            foreach (G2DTreeNode<T> cn in rootNode.GetG2DList())
            {
                ret.Add(cn);
            }
            return ret;
        }

        virtual public G2DTreeNode<T> CreateNodeData(string id)
        {
            G2DTreeNode<T> ret = new G2DTreeNode<T>(new T());
            ret.SetDataID(id);
            return ret;
        }


        public void SaveAll(AtomicInteger progress, bool check)
        {
            foreach (var node in GetAllNode())
            {
                node.Data.EditorPath = node.FullPath;
            }
            rootNode.SaveAll(Editor.Instance.MessageFactory, progress);
            if (check)
            {
                foreach (var data in GetAllNodeData())
                {
                    string srcxml;
                    string retxml;
                    if (!EditorTemplates.ValidateBin<T>(data, Editor.Instance.MessageFactory, out srcxml, out retxml))
                    {
                        string sfile = SaveDir + "_conflict_" + data.TemplateID + ".src.txt";
                        string dfile = SaveDir + "_conflict_" + data.TemplateID + ".bin.txt";
                        File.WriteAllText(sfile, srcxml, CUtils.UTF8);
                        File.WriteAllText(dfile, retxml, CUtils.UTF8);
                        throw new Exception(SaveDir + "/" + data.TemplateID + ".xml" + " : Save Load 二进制序列化不匹配 !" + data.GetType() +
                            "\n比较文件已存储到: " + dfile);
                    }
                }
            }
        }

        public void SaveNode(G2DTreeNode<T> node)
        {
            var data = node.Data;
            data.EditorPath = node.FullPath;
            rootNode.SaveOne(data, Editor.Instance.MessageFactory);
        }

        public void RefreshData()
        {
            rootNode.Refresh();
            treeView.Refresh();
        }

        public List<FileInfo> GetSavedFiles()
        {
            return rootNode.ListSavedFiles();
        }
        public FileInfo GetListFile()
        {
            return rootNode.GetListFile();
        }
        public FileInfo GetMd5File()
        {
            return rootNode.GetMd5File();
        }

        public T GetSelectedData()
        {
            G2DTreeNode<T> cn = GetChildMenuNode();
            if (cn != null)
            {
                return cn.Data;
            }
            return default(T);
        }
        public G2DTreeNode<T> GetSelectedNode()
        {
            return GetChildMenuNode();
        }

        private G2DTreeNode<T> GetChildMenuNode()
        {
            TreeNode nd = treeView.SelectedNode;
            if (nd is G2DTreeNode<T>)
            {
                return nd as G2DTreeNode<T>;
            }
            return null;
        }

        private G2DTreeNodeGroup GetGroupMenuNode()
        {
            TreeNode nd = treeView.SelectedNode;
            if (nd is G2DTreeNodeGroup)
            {
                return nd as G2DTreeNodeGroup;
            }
            return null;
        }


        public T ShowSelectTemplateDialog(object obj)
        {
            G2DListSelectEditor<T> dialog = new G2DListSelectEditor<T>(
                   this.TreeRoot, treeView.ImageList, obj);
            if (dialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                return dialog.SelectedObject;
            }
            return null;
        }
        public bool ShowSelectTemplateIDDialog(object obj, out int id)
        {
            G2DListSelectEditor<T> dialog = new G2DListSelectEditor<T>(
                this.TreeRoot, treeView.ImageList, obj);
            if (dialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                if (dialog.SelectedObject != null)
                {
                    id = dialog.SelectedObject.TemplateID;
                    return true;
                }
            }
            id = 0;
            return false;
        }

        // ---------------------------------------------------------------------------------------
        #region EventHandlers

        private void groupBtn_AddNode_Click(object sender, EventArgs e)
        {
            G2DTreeNodeGroup parent = GetGroupMenuNode();
            if (parent != null)
            {
                string id = G2DTextDialog.Show(random.Next() + "", "添加" + categoryText);
                if (id != null)
                {
                    try
                    {
                        G2DTreeNode<T> tn = CreateNodeData(id);
                        if (rootNode.AddG2DNode(tn, parent))
                        {
                            parent.Expand();
                            treeView.SelectedNode = tn;
                            treeView.Refresh();
                        }
                        else
                        {
                            MessageBox.Show("无法添加");
                        }
                    }
                    catch (Exception err)
                    {
                        MessageBox.Show(err.Message);
                    }
                }
            }
        }

        private void groupBtn_AddGroup_Click(object sender, EventArgs e)
        {
            G2DTreeNodeGroup parent = GetGroupMenuNode();
            if (parent != null)
            {
                string gname = G2DTextDialog.Show("分组");
                if (gname != null)
                {
                    G2DTreeNodeGroup group = parent.AddG2DGroup(gname);
                    parent.Expand();
                    treeView.SelectedNode = group;
                }
            }
        }

        private void groupBtn_Rename_Click(object sender, EventArgs e)
        {
            G2DTreeNodeGroup parent = GetGroupMenuNode();
            if (parent != null)
            {
                string gname = G2DTextDialog.Show(parent.Text, "重命名");
                if (gname != null)
                {
                    parent.Text = gname;
                    treeView.Refresh();
                }
            }
        }
        private void groupBtn_EditAll_Click(object sender, EventArgs e)
        {
            G2DTreeNodeGroup parent = GetGroupMenuNode();
            if (parent != null)
            {
                List<object> datas = new List<object>();
                foreach (TreeNode tn in parent.Nodes)
                {
                    if (tn is G2DTreeNode<T>)
                    {
                        datas.Add((tn as G2DTreeNode<T>).Data);
                    }
                }
                try
                {
                    G2DDataGridEditor grid_editor = new G2DDataGridEditor(datas);
                    grid_editor.ShowDialog();
                    if (grid_editor.IsDataChanged)
                    {
                        RefreshData();
                    }
                }
                catch (Exception err)
                {
                    MessageBox.Show(err.Message);
                }

            }
        }
        private void groupBtn_Balance_Click(object sender, EventArgs e)
        {

            G2DTreeNodeGroup parent = GetGroupMenuNode();
            if (parent != null)
            {
                StringBuilder sb = new StringBuilder();
                List<object> datas = new List<object>();
                foreach (TreeNode tn in parent.Nodes)
                {
                    if (tn is G2DTreeNode<T>)
                    {
                        T data = (tn as G2DTreeNode<T>).Data;
                        datas.Add(data);
                        sb.AppendLine("[" + data.ToString() + "]");
                    }
                }
                if (MessageBox.Show("确定要配平数据?\n" + sb.ToString(), "集合内所有数据结构将会一致!") == DialogResult.OK)
                {
                    sb.Clear();

                    int count = 0;
                    foreach (object src in datas)
                    {
                        foreach (object dst in datas)
                        {
                            try
                            {
                                if (UmlUtils.StructEquationBalancer(src, dst))
                                {
                                    sb.AppendLine(src + " -> " + dst);
                                    count++;
                                }
                            }
                            catch (Exception err)
                            {
                                MessageBox.Show(err.Message);
                            }
                        }
                    }
                    if (count > 0)
                    {
                        MessageBox.Show(string.Format("{0}个数据已配平!\n{1}", count, sb.ToString()));
                    }
                }
            }
        }


        private void childBtn_SetID_Click(object sender, EventArgs e)
        {
            G2DTreeNode<T> node = GetChildMenuNode();
            if (node != null)
            {
                string id = G2DTextDialog.Show(node.DataID, node.Text);
                if (id != null)
                {
                    try
                    {
                        if (rootNode.SetG2DNodeID(node, id))
                        {
							//rootNode.Refresh();
							node.Refresh();
                        }
                        else
                        {
                            MessageBox.Show("无法重设ID,有冲突!");
                        }
                    }
                    catch (Exception err)
                    {
                        MessageBox.Show(err.Message);
                    }
                }
            }
        }

        private void childBtn_Duplicate_Click(object sender, EventArgs e)
        {
            G2DTreeNode<T> node = GetChildMenuNode();
            if (node != null)
            {
                string newname = random.Next() + "";
                while (newname != null)
                {
                    newname = G2DTextDialog.Show(newname, "复制");
                    if (newname != null)
                    {
                        if (rootNode.ContainsG2DNodeID(newname))
                        {
                            MessageBox.Show(newname + " 已存在!");
                        }
                        else
                        {
                            try
                            {
                                G2DTreeNode<T> newnode = node.Clone(newname);
                                rootNode.AddG2DNode(newnode, node.Parent);
                                return;
                            }
                            catch (Exception err)
                            {
                                MessageBox.Show(err.Message);
                            }
                        }
                    }
                }
            }
        }

        private void childBtn_Delete_Click(object sender, EventArgs e)
        {
            G2DTreeNode<T> node = GetChildMenuNode();
            if (node != null)
            {
                DialogResult res = MessageBox.Show(
                    "确认删除: " + node.Text,
                    "确认",
                    MessageBoxButtons.OKCancel);
                if (res == DialogResult.OK)
                {
                    node.RemoveFromParent();
                }
            }
        }

        private void childBtn_EditSingle_Click(object sender, EventArgs e)
        {
            G2DTreeNode<T> node = GetChildMenuNode();
            if (node != null)
            {
                List<object> datas = new List<object>();
                datas.Add(node.Data);
                try
                {
                    G2DDataGridEditor grid_editor = new G2DDataGridEditor(datas);
                    grid_editor.ShowDialog();
                    if (grid_editor.IsDataChanged)
                    {
                        RefreshData();
                    }
                }
                catch (Exception err)
                {
                    MessageBox.Show(err.Message);
                }
            }
        }

        private void treeView_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e)
        {
            treeView.SelectedNode = e.Node;
            if (e.Node is G2DTreeNode<T>)
            {
                G2DTreeNode<T> dnode = e.Node as G2DTreeNode<T>;
                propertyGrid.SelectedObject = new G2DPropertyDescriptor(dnode.Data);
            }
            else
            {
                propertyGrid.SelectedObject = null;
            }
        }

        private void treeView_ItemDrag(object sender, ItemDragEventArgs e)
        {
            treeView.DoDragDrop(e.Item, DragDropEffects.Move);
        }

        private void treeView_DragEnter(object sender, DragEventArgs e)
        {
            if (e.Data.GetDataPresent(typeof(G2DTreeNode<T>)))
            {
                e.Effect = DragDropEffects.Move;
            }
            else if (e.Data.GetDataPresent(typeof(G2DTreeNodeGroup)))
            {
                e.Effect = DragDropEffects.Move;
            }
            else
            {
                e.Effect = DragDropEffects.None;
            }
        }

        private void treeView_DragOver(object sender, DragEventArgs e)
        {
            Point pos = treeView.PointToClient(new Point(e.X, e.Y));
            TreeNode dropNode = this.treeView.GetNodeAt(pos);
            if (dropNode is G2DTreeNodeGroup)
            {
                e.Effect = DragDropEffects.Move;
            }
            else
            {
                e.Effect = DragDropEffects.None;
            }
        }

        private void treeView_DragDrop(object sender, DragEventArgs e)
        {
            Point pos = treeView.PointToClient(new Point(e.X, e.Y));
            TreeNode dropNode = this.treeView.GetNodeAt(pos);
            if (dropNode is G2DTreeNodeGroup)
            {
                G2DTreeNodeBase child_node = (G2DTreeNodeBase)e.Data.GetData(typeof(G2DTreeNode<T>));
                G2DTreeNodeBase group_node = (G2DTreeNodeBase)e.Data.GetData(typeof(G2DTreeNodeGroup));
                if (child_node == null && group_node == null)
                {
                    MessageBox.Show("error");
                }
                else if (child_node != null)
                {
                    child_node.RemoveFromParent();
                    dropNode.Nodes.Add(child_node);
                    treeView.SelectedNode = child_node;
                }
                else if (group_node != dropNode)
                {
                    if (!G2DTreeNodeBase.ContainsChild(group_node, dropNode, true))
                    {
                        group_node.RemoveFromParent();
                        dropNode.Nodes.Add(group_node);
                    }
                }
            }
        }

        private void propertyGrid_PropertyValueChanged(object s, PropertyValueChangedEventArgs e)
        {
            G2DTreeNode<T> tn = treeView.SelectedNode as G2DTreeNode<T>;
            if (tn != null)
            {
                tn.Refresh();
            }
        }

        #endregion


        object IDataManager.SelectedData
        {
            get { return this.GetSelectedData(); }
        }

        TreeNode IDataManager.TreeRoot
        {
            get { return this.TreeRoot; }
        }

        object IDataManager.GetNodeData(string id)
        {
            return this.GetNodeData(id);
        }


        object IDataManager.ShowSelectTemplateDialog(object obj)
        {
            return this.ShowSelectTemplateDialog(obj);
        }

        bool IDataManager.ShowSelectTemplateIDDialog(object obj, out int id)
        {
            return this.ShowSelectTemplateIDDialog(obj, out id);
        }
    }
}