using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;

using System.Text;
using System.Windows.Forms;
using CommonAI.Zone.ZoneEditor;
using CommonFroms.Utils;
using System.IO;
using CommonAI.Zone;
using CommonAI.RTS;
using CommonLang.Vector;
using CommonAI.Zone.ZoneEditor.Plugin.EditorToScene;
using CommonAI.Zone.ZoneEditor.Plugin.SceneToEditor;
using CommonLang;
using CommonLang.Xml;
using System.Diagnostics;
using CommonAIEditor.Plugins.Win32;
using CommonFroms;
using CommonAI.ZoneEditor;
using GameEditorPlugin.Win32.Runtime;
using GameEditorPlugin.Win32;
using CommonFroms.G2D;
using CommonFroms.G2D.DataGrid;
using GameEditorPlugin.Tools;
using System.Xml;
using CommonFroms.Drawing;

namespace CommonAIEditor.Scene
{
    public partial class SceneEditor : Form
    {
        public delegate void SaveHandler(SceneEditor editor, G2DTreeNode<SceneData> node);

        public event SaveHandler OnSaved;

        public SceneData Data { get { return mData; } }

        private G2DTreeNode<SceneData> mNode;
        private SceneData mData;
        private ZoneInfo mZoneData;

        private ISceneEditorPlugin mPlugin;

        private G2DTreeNodeGroup treeRoot;

        private EditorMiniMap displayWorld;

        private RightMouseFilter rightFilter;

        private SceneEventEditor eventEditor;
        private SceneVarEditor varEditor;

        public SceneEditor(DataManagerPanel<SceneData> owner, G2DTreeNode<SceneData> node, ISceneEditorPlugin plugin)
        {
            SceneData data = node.Data;

            this.tree_setting_file = new FileInfo(owner.TreeRoot.SettingDir + "\\" + data.ID + ".tree");

            InitializeComponent();

            this.Text = "场景: " + data.ToString();
            this.DoubleBuffered = true;
            this.splitContainer1.Enabled = false;
            this.toolStrip1.Enabled = false;

            // tree and objects //
            {
                this.propertyGrid1.PropertyTabs.AddTabType(
                    typeof(System.Windows.Forms.Design.EventsTab),
                    PropertyTabScope.Global);
                this.treeView1.ImageList = Editor.Instance.Icons;
                this.treeRoot = new G2DTreeNodeGroup("所有单位");
                this.treeRoot.ImageKey = "icons_tool_bar2.png";
                this.treeRoot.SelectedImageKey = "icons_tool_bar2.png";
                this.treeRoot.ContextMenuStrip = groupMenuStrip;
                this.treeView1.Nodes.Add(treeRoot);
            }

            this.mNode = node;
            this.mData = data;
            this.mZoneData = data.ZoneData;
            this.displayWorld = new EditorMiniMap(treeRoot, mZoneData);

            // init plugin //
            {
                this.mPlugin = plugin;
                this.mPlugin.OnGetPluginMessage += new PluginMessageHandler(OnPluginMessageHandler);
                this.mPlugin.AsControl().Dock = DockStyle.Fill;
                this.mPlugin.CallAddObject += call_AddObject;
                this.mPlugin.CallResetObject += call_ResetObject;
                this.panel1.Controls.Add(mPlugin.AsControl());
            }
            // map define //
            {
                var brush = Editor.Instance.DefaultTerrainBrush;
                if (brush != null)
                {
                    toolStripButton_Color.BackColor = Color.FromArgb(brush.Value);
                    toolStripButton_Color.Text = brush.Name.Length > 0 ? brush.Name.Substring(0, 1) : "";
                }
                btn_BrushRect.Tag = MsgSetTerrainBrush.BrushType.Rectangle;
                btn_BrushRound.Tag = MsgSetTerrainBrush.BrushType.Round;
                btn_Brush.Tag = btn_BrushRound;
            }
            this.rightFilter = new RightMouseFilter(mPlugin.AsControl());
            if (!mPlugin.EnableRight)
            {
                Application.AddMessageFilter(rightFilter);
            }
        }

        class RightMouseFilter : IMessageFilter
        {
            const int WM_RBUTTONDBLCLK = 0x206;
            const int WM_RBUTTONDOWN = 0x204;
            const int WM_RBUTTONUP = 0x205;

            private Control component;

            public RightMouseFilter(Control component)
            {
                this.component = component;
            }

            public bool PreFilterMessage(ref System.Windows.Forms.Message m)
            {
                switch (m.Msg)
                {
                    case WM_RBUTTONDBLCLK:
                    case WM_RBUTTONDOWN:
                    case WM_RBUTTONUP:
                        {
                            Point pt = component.PointToClient(Control.MousePosition);
                            if (component.TopLevelControl.Focused)
                            {
                                if (component.Bounds.Contains(pt))
                                    return true;    //返回true则消息被裁取,系统不再处理 
                            }
                        }
                        break;
                    default:
                        return false;    //返回false则消息未被裁取,系统会处理 
                }

                return false;
            }
        }


        private void SceneEditor_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (eventEditor != null)
            {
                eventEditor.Save();
                eventEditor.Close();
                eventEditor = null;
            }
            if (varEditor != null)
            {
                varEditor.Save();
                varEditor.Close();
                varEditor = null;
            }
            System.Windows.Forms.DialogResult result = MessageBox.Show(this,
                "关闭前保存场景?",
                "确认关闭?",
                MessageBoxButtons.YesNoCancel);
            if (result == System.Windows.Forms.DialogResult.Yes)
            {
                SaveToScene();
                Application.RemoveMessageFilter(rightFilter);
            }
            else if (result == System.Windows.Forms.DialogResult.No)
            {
                Application.RemoveMessageFilter(rightFilter);
            }
            else
            {
                e.Cancel = true;
            }
        }

        private void LaunchVarEdit()
        {
            if (varEditor == null)
            {
                varEditor = new SceneVarEditor(this);
                varEditor.FormClosed += new FormClosedEventHandler(
                    (object sender, FormClosedEventArgs e) =>
                    {
                        varEditor.Save();
                        varEditor = null;
                    }
                );
                varEditor.Show();
            }
            else
            {
                FormUtils.SwithToThisForm(varEditor, true);
            }
        }

        private void LaunchEventEdit()
        {
            if (eventEditor == null)
            {
                eventEditor = new SceneEventEditor(this);
                eventEditor.OnDataLoaded += (editor) =>
                {
                    LoadEventsTreeInfo(editor as SceneEventEditor);
                };
                eventEditor.OnDataSaved += (editor) =>
                {
                    SaveEventsTreeInfo(editor as SceneEventEditor);
                };
                eventEditor.Text = "事件列表";
                eventEditor.FormClosed += new FormClosedEventHandler(
                    (object sender, FormClosedEventArgs e) =>
                    {
                        eventEditor.Save();
                        eventEditor = null;
                    }
                );
                eventEditor.Show();
            }
            else
            {
                FormUtils.SwithToThisForm(eventEditor, true);
            }
        }

        //----------------------------------------------------------------------------
        #region SaveLoad


        private readonly FileInfo tree_setting_file;

        private void LoadScene()
        {
            this.numericCellW.Value = mData.Terrain.GridCellW;
            this.numericCellH.Value = mData.Terrain.GridCellH;
            this.numericXCount.Value = mData.Terrain.XCount;
            this.numericYCount.Value = mData.Terrain.YCount;

            post_MsgSetScene(mData);

            foreach (PointData tn in mData.Points)
            {
                LoadSceneObject(tn);
            }
            foreach (RegionData tn in mData.Regions)
            {
                LoadSceneObject(tn);
            }
            foreach (UnitData tn in mData.Units)
            {
                LoadSceneObject(tn);
            }
            foreach (DecorationData tn in mData.Decorations)
            {
                LoadSceneObject(tn);
            }
            foreach (ItemData tn in mData.Items)
            {
                LoadSceneObject(tn);
            }
            foreach (AreaData tn in mData.Areas)
            {
                LoadSceneObject(tn);
            }
            post_MsgShowTerrain();
            post_MsgSetEditorMode(MsgSetEditorMode.MODE_OBJECT);
            post_MsgSetTerrainBrush();
            post_MsgLocateCamera(
                displayWorld.Width / 2,
                displayWorld.Height / 2);

            LoadTreeInfo(tree_setting_file);
            treeRoot.Expand();

        }

        private void SaveToScene()
        {
            if (!bLoadScene) return;

            mData.SetTerrain(mZoneData);

            mData.Points = new List<PointData>();
            mData.Regions = new List<RegionData>();
            mData.Units = new List<UnitData>();
            mData.Decorations = new List<DecorationData>();
            mData.Items = new List<ItemData>();
            mData.Areas = new List<AreaData>();
            foreach (TreeNode tn in treeRoot.GetAllNodes())
            {
                if (tn is ObjectTreeNode)
                {
                    ObjectTreeNode otn = tn as ObjectTreeNode;
                    otn.Data.SavePath = treeRoot.GetSavePath(otn);
                    if (otn.Data is PointData)
                    {
                        mData.Points.Add(otn.Data as PointData);
                    }
                    else if (otn.Data is RegionData)
                    {
                        mData.Regions.Add(otn.Data as RegionData);
                    }
                    else if (otn.Data is DecorationData)
                    {
                        mData.Decorations.Add(otn.Data as DecorationData);
                    }
                    else if (otn.Data is UnitData)
                    {
                        mData.Units.Add(otn.Data as UnitData);
                    }
                    else if (otn.Data is ItemData)
                    {
                        mData.Items.Add(otn.Data as ItemData);
                    }
                    else if (otn.Data is AreaData)
                    {
                        mData.Areas.Add(otn.Data as AreaData);
                    }
                }
            }
            if (eventEditor != null)
            {
                eventEditor.Save();
            }
            if (varEditor != null)
            {
                varEditor.Save();
            }
            if (OnSaved != null)
            {
                OnSaved.Invoke(this, mNode);
            }

            SaveTreeInfo(tree_setting_file);

        }

        private XmlDocument tree_xml_status;
        private XmlElement events_xml_status;
        private XmlElement objects_xml_status;

        private void LoadTreeInfo(FileInfo file)
        {
            try
            {
                var xmltext = File.ReadAllText(file.FullName, CUtils.UTF8);
                tree_xml_status = XmlUtil.FromString(xmltext);
            }
            catch (Exception)
            {
                tree_xml_status = new XmlDocument();
                tree_xml_status.AppendChild(tree_xml_status.CreateElement("root"));
            }
            var eroot = tree_xml_status.DocumentElement;
            objects_xml_status = XmlUtil.FindChild(eroot, "objects") as XmlElement;
            if (objects_xml_status != null)
            {
                G2DTreeNodeGroup.SetTreeInfo(objects_xml_status as XmlElement, treeRoot);
            }
            else
            {
                objects_xml_status = tree_xml_status.CreateElement("objects");
                eroot.AppendChild(objects_xml_status);
            }
            events_xml_status = XmlUtil.FindChild(eroot, "events") as XmlElement;
            if (events_xml_status == null)
            {
                events_xml_status = tree_xml_status.CreateElement("events");
                eroot.AppendChild(events_xml_status);
            }
        }
        private void SaveTreeInfo(FileInfo file)
        {
            try
            {
                objects_xml_status.RemoveAll();
                G2DTreeNodeGroup.GetTreeInfo(objects_xml_status, treeRoot);

                var xmltext = XmlUtil.ToString(tree_xml_status);
                File.WriteAllText(file.FullName, xmltext, CUtils.UTF8);
            }
            catch (Exception) { }
        }
        private void LoadEventsTreeInfo(SceneEventEditor editor)
        {
            editor.LoadTreeInfo(events_xml_status);
        }
        private void SaveEventsTreeInfo(SceneEventEditor editor)
        {
            events_xml_status.RemoveAll();
            editor.SaveTreeInfo(events_xml_status);
        }
        #endregion

        //----------------------------------------------------------------------------

        private void ChangeSceneTerrain()
        {
            try
            {
                ZoneInfo old_info = mData.ZoneData;
                {
                    int cellW = (int)(numericCellW.Value);
                    int cellH = (int)(numericCellH.Value);
                    int xCount = (int)(numericXCount.Value);
                    int yCount = (int)(numericYCount.Value);
                    ZoneInfo new_info = new ZoneInfo(xCount, yCount, cellW, cellH);
                    for (int x = 0; x < xCount && x < old_info.XCount; x++)
                    {
                        for (int y = 0; y < yCount && y < old_info.YCount; y++)
                        {
                            new_info.TerrainMatrix[x, y] = old_info.TerrainMatrix[x, y];
                        }
                    }
                    mZoneData = new_info;
                    mData.SetTerrain(new_info);
                    this.displayWorld.ResetTerrain(mZoneData);
                }
                post_MsgSetScene(mData);
            }
            catch (Exception err)
            {
                MessageBox.Show(err.Message);
            }
        }

        //----------------------------------------------------------------------------
        #region Delegates
        //----------------------------------------------------------------------------

        private void tool_RunGameEmu_Click(object sender, EventArgs e)
        {
            SaveToScene();
            IGameEditorPlugin plugin = EditorPlugin.CurrentPlugin;
            plugin.RunLocalPlay(EditorPlugin.DefaultPlugin, new DirectoryInfo(Editor.DataDir), mData.ID, false);
        }

        private void tool_RunGamePlugin_Click(object sender, EventArgs e)
        {
            SaveToScene();
            try
            {
                IGameEditorPlugin plugin = EditorPlugin.CurrentPlugin;
                plugin.RunTest(EditorPlugin.DefaultPlugin, Editor.DataDir, mData.ID, Editor.GetTestActorTemplateID(mData, 0));
            }
            catch (Exception err)
            {
                MessageBox.Show(err.Message);
            }
        }

        private void btn_TestAstar_Click(object sender, EventArgs e)
        {
            SaveToScene();
            new FormAstar(Editor.DataDir_scenes, Editor.Instance.TerrainDefinition, mData).Show();
        }
        private void btn_ScriptEditor_Click(object sender, EventArgs e)
        {
        }
        private void btn_Events_Click(object sender, EventArgs e)
        {
            LaunchEventEdit();
        }
        private void btn_EnvVars_Click(object sender, EventArgs e)
        {
            LaunchVarEdit();
        }

        //----------------------------------------------------------------------------
        private SceneObjectData call_AddObject(Type type, Action<SceneObjectData> callback)
        {
            return AddSceneObject(type, callback);
        }
        private SceneObjectData call_ResetObject(string name, Action<SceneObjectData> callback)
        {
            var data = this.GetSceneObjectData(name);
            if (data != null)
            {
                callback.Invoke(data);
                RefreshObject(data);
                return data;
            }
            return null;
        }

        //----------------------------------------------------------------------------

        private void addUnitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            AddSceneObject(typeof(UnitData));
        }
        private void addItem_MenuItem_Click(object sender, EventArgs e)
        {
            AddSceneObject(typeof(ItemData));
        }
        private void addRegionToolStripMenuItem_Click(object sender, EventArgs e)
        {
            AddSceneObject(typeof(RegionData));
        }
        private void addPointToolStripMenuItem_Click(object sender, EventArgs e)
        {
            AddSceneObject(typeof(PointData));
        }
        private void addDecoration_MenuItem_Click(object sender, EventArgs e)
        {
            AddSceneObject(typeof(DecorationData));
        }
        private void addArea_MenuItem_Click(object sender, EventArgs e)
        {
            AddSceneObject(typeof(AreaData));
        }
        private void addGroup_MenuItem_Click(object sender, EventArgs e)
        {
            AddSceneGroup();
        }
        private void copyGroup_MenuItem_Click(object sender, EventArgs e)
        {
            CopySelected();
        }
        private void pasteGroup_MenuItem_Click(object sender, EventArgs e)
        {
            Paste();
        }
        private void cloneGroup_MenuItem_Click(object sender, EventArgs e)
        {
            DuplicateSelected();
        }
        private void renameGroup_MenuItem_Click(object sender, EventArgs e)
        {
            RenameSceneGroup();
        }
        //----------------------------------------------------------------------------

        private void btn_Brush_Click(object sender, EventArgs e)
        {
            btn_Brush.Tag = sender;
            btn_Brush.Image = (sender as ToolStripMenuItem).Image;
            post_MsgSetTerrainBrush();
        }
        //----------------------------------------------------------------------------------

        private void propertyGrid1_PropertyValueChanged(object s, PropertyValueChangedEventArgs e)
        {
            if (propertyGrid1.SelectedObject is G2DPropertyDescriptor)
            {
                G2DPropertyDescriptor prop = (G2DPropertyDescriptor)propertyGrid1.SelectedObject;
                if (prop.EditData is UnitData)
                {
                    post_MsgPutUnit(prop.EditData as UnitData);
                }
                else if (prop.EditData is ItemData)
                {
                    post_MsgPutItem(prop.EditData as ItemData);
                }
                else if (prop.EditData is RegionData)
                {
                    post_MsgPutRegion(prop.EditData as RegionData);
                }
                else if (prop.EditData is PointData)
                {
                    post_MsgPutPoint(prop.EditData as PointData);
                }
                else if (prop.EditData is DecorationData)
                {
                    post_MsgPutDecoration(prop.EditData as DecorationData);
                }
                else if (prop.EditData is AreaData)
                {
                    post_MsgPutArea(prop.EditData as AreaData);
                }
                ObjectTreeNode node = GetSelectedAsSceneObject();
                if (node != null)
                {
                    node.RefreshData();
                }
            }
        }

        private void propertyGrid1_Click(object sender, EventArgs e)
        {

        }
        private void propertyGrid1_DragEnter(object sender, DragEventArgs e)
        {
            if (e.Data.GetDataPresent(typeof(ObjectTreeNode)))
            {
                e.Effect = DragDropEffects.Move;
            }
            else
            {
                e.Effect = DragDropEffects.None;
            }
        }

        private void propertyGrid1_DragOver(object sender, DragEventArgs e)
        {
            if (e.Data.GetDataPresent(typeof(ObjectTreeNode)))
            {
                e.Effect = DragDropEffects.Move;
            }
            else
            {
                e.Effect = DragDropEffects.None;
            }
        }


        private void propertyGrid1_DragDrop(object sender, DragEventArgs e)
        {
            ObjectTreeNode dragObjNode = (ObjectTreeNode)e.Data.GetData(typeof(ObjectTreeNode));
            if (propertyGrid1.SelectedObject != null && dragObjNode.Data is PointData)
            {
                PointData srcP = dragObjNode.Data as PointData;
                G2DPropertyDescriptor desc = propertyGrid1.SelectedObject as G2DPropertyDescriptor;
                if (desc.EditData is PointData)
                {
                    PointData dstP = desc.EditData as PointData;
                    if (!dstP.NextNames.Contains(srcP.Name))
                    {
                        dstP.NextNames.Add(srcP.Name);
                        post_MsgPutPoint(dstP);
                        propertyGrid1.Refresh();
                    }
                }
                else if (desc.EditData is UnitData)
                {
                    UnitData dstP = desc.EditData as UnitData;
                    dstP.StartPointName = srcP.Name;
                    propertyGrid1.Refresh();
                }
            }


        }

        //----------------------------------------------------------------------------------

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

        private void treeView1_DragDrop(object sender, DragEventArgs e)
        {
            Point pos = treeView1.PointToClient(new Point(e.X, e.Y));
            TreeNode dropNode = this.treeView1.GetNodeAt(pos);
            G2DTreeNodeBase child_node = (G2DTreeNodeBase)e.Data.GetData(typeof(ObjectTreeNode));
            G2DTreeNodeBase group_node = (G2DTreeNodeBase)e.Data.GetData(typeof(G2DTreeNodeGroup));
            if (dropNode is G2DTreeNodeGroup)
            {
                if (child_node == null && group_node == null)
                {
                    MessageBox.Show("error");
                }
                else if (child_node != null)
                {
                    child_node.RemoveFromParent();
                    dropNode.Nodes.Add(child_node);
                    dropNode.Expand();
                    //treeView1.SelectedNode = child_node;
                }
                else if (group_node != dropNode)
                {
                    if (!G2DTreeNodeBase.ContainsChild(group_node, dropNode, true))
                    {
                        group_node.RemoveFromParent();
                        dropNode.Nodes.Add(group_node);
                        dropNode.Expand();
                        //treeView1.SelectedNode = group_node;
                    }
                }
            }
            else if (dropNode is ObjectTreeNode && child_node is ObjectTreeNode)
            {
                ObjectTreeNode dragObjNode = child_node as ObjectTreeNode;
                ObjectTreeNode dropObjNode = dropNode as ObjectTreeNode;
                if (dragObjNode.Data is PointData &&
                    dropObjNode.Data is PointData)
                {
                    PointData srcP = dragObjNode.Data as PointData;
                    PointData dstP = dropObjNode.Data as PointData;
                    if (!dstP.NextNames.Contains(srcP.Name))
                    {
                        dstP.NextNames.Add(srcP.Name);
                        post_MsgPutPoint(dstP);
                        propertyGrid1.Refresh();
                        MessageBox.Show(dstP.Name + " -> " + srcP.Name + " 已连接");
                    }
                }
                if (dragObjNode.Data is PointData &&
                    dropObjNode.Data is UnitData)
                {
                    PointData srcP = dragObjNode.Data as PointData;
                    UnitData dstP = dropObjNode.Data as UnitData;
                    dstP.StartPointName = srcP.Name;
                    propertyGrid1.Refresh();
                    MessageBox.Show(dstP.Name + " -> " + srcP.Name + " 已设置路径");
                }
            }
        }

        private void treeView1_DragEnter(object sender, DragEventArgs e)
        {
            if (e.Data.GetDataPresent(typeof(ObjectTreeNode)))
            {
                e.Effect = DragDropEffects.Move;
            }
            else if (e.Data.GetDataPresent(typeof(G2DTreeNodeGroup)))
            {
                e.Effect = DragDropEffects.Move;
            }
            else
            {
                e.Effect = DragDropEffects.None;
            }
        }

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

        private void treeView1_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e)
        {
            treeView1.SelectedNode = e.Node;
        }

        private void treeView1_NodeMouseDoubleClick(object sender, TreeNodeMouseClickEventArgs e)
        {
            if (e.Node is ObjectTreeNode)
            {
                ObjectTreeNode tn = e.Node as ObjectTreeNode;
                post_MsgLocateCamera(tn.Data.X, tn.Data.Y);
            }
        }
        private void treeView1_AfterSelect(object sender, TreeViewEventArgs e)
        {
            if (e.Node is ObjectTreeNode)
            {
                SelectSceneObject(e.Node as ObjectTreeNode);
            }
        }
        private void btn_TreeExpandAll_Click(object sender, EventArgs e)
        {
            treeRoot.ExpandAll();
        }

        private void btn_TreeCollapseAll_Click(object sender, EventArgs e)
        {
            foreach (TreeNode tn in treeRoot.Nodes)
            {
                tn.Collapse();
            }
        }
        //----------------------------------------------------------------------------

        private void saveToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (bLoadScene)
            {
                SaveToScene();
            }
        }
        private void buttonSetTerrain_Click(object sender, EventArgs e)
        {
            ChangeSceneTerrain();
        }
        private void toolStripButtonSave_Click(object sender, EventArgs e)
        {
            if (bLoadScene)
            {
                SaveToScene();
            }
        }

        //----------------------------------------------------------------------------

        private void btn_selectUnit_Click(object sender, EventArgs e)
        {
            btn_selectUnit.Checked = true;
            btn_setTerrain.Checked = !btn_selectUnit.Checked;
            post_MsgSetEditorMode(MsgSetEditorMode.MODE_OBJECT);
        }

        private void btn_setTerrain_Click(object sender, EventArgs e)
        {
            btn_setTerrain.Checked = true;
            btn_selectUnit.Checked = !btn_setTerrain.Checked;
            post_MsgSetEditorMode(MsgSetEditorMode.MODE_TERRAIN);
        }

        private void objBtn_Rename_Click(object sender, EventArgs e)
        {
            RenameSceneObject();
        }

        private void objBtn_Remove_Click(object sender, EventArgs e)
        {
            RemoveSelectedSceneObject();
        }

        private void objBtn_Duplicate_Click(object sender, EventArgs e)
        {
            DuplicateSelected();
        }
        private void objBtn_Copy_Click(object sender, EventArgs e)
        {
            CopySelected();
        }
        private void objBtn_Paste_Click(object sender, EventArgs e)
        {
            Paste();
        }
        private void objBtn_CopyNameText_Click(object sender, EventArgs e)
        {
            ObjectTreeNode node = GetSelectedAsSceneObject();
            if (node != null)
            {
                Clipboard.SetText(node.DataID);
            }
        }
        private void objBtn_Event_Click(object sender, EventArgs e)
        {
            ObjectTreeNode node = GetSelectedAsSceneObject();
            if (node != null)
            {

            }
        }
        private void objBtn_OnOff_Click(object sender, EventArgs e)
        {
            ObjectTreeNode node = GetSelectedAsSceneObject();
            if (node != null)
            {
                node.Data.Enable = !node.Data.Enable;
                node.RefreshData();
            }
        }

        //----------------------------------------------------------------------------
        private void btn_CopyToClipboard_Click(object sender, EventArgs e)
        {
            TreeNode node = treeView1.SelectedNode;
            if (node != null)
            {
                Clipboard.SetText(node.Text);
            }
        }
        private void btn_Copy_Click(object sender, EventArgs e)
        {
            TreeNode node = treeView1.SelectedNode;
            if (node != null)
            {
                Clipboard.SetText(node.Text);
            }
            CopySelected();
        }

        private void btn_Paste_Click(object sender, EventArgs e)
        {
            Paste();
        }
        private void btn_Delete_Click(object sender, EventArgs e)
        {
            RemoveSelectedSceneObject();
        }

        //----------------------------------------------------------------------------
        private void panel1_MouseDown(object sender, MouseEventArgs e)
        {
        }
        private void panel1_MouseMove(object sender, MouseEventArgs e)
        {
        }
        private void panel1_MouseUp(object sender, MouseEventArgs e)
        {
        }
        private void toolStripButtonColor_Click(object sender, EventArgs e)
        {
            var cd = Editor.Instance.ShowTerrainDefinitionDialog(this, toolStripButton_Color.BackColor.ToArgb());
            var brush = cd.SelectedBrush;
            if (brush != null)
            {
                toolStripButton_Color.BackColor = Color.FromArgb(brush.Value);
                toolStripButton_Color.Text = brush.Name.Length > 0 ? brush.Name.Substring(0, 1) : "";
                toolStripButton_Color.ToolTipText = brush.Desc;
                post_MsgSetTerrainBrush();
            }
        }
        private void toolStripButtonShowTerrain_Click(object sender, EventArgs e)
        {
            post_MsgShowTerrain();
        }

        private void combo_BrushSize_TextChanged(object sender, EventArgs e)
        {
            post_MsgSetTerrainBrush();
        }

        //---------------------------------------------------------------------------

        private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
        {
            int wx = (int)displayWorld.screenToWorldX(e.X);
            int wy = (int)displayWorld.screenToWorldY(e.Y);
            if (e.Button == MouseButtons.Left)
            {
                post_MsgLocateCamera(wx, wy);
                pictureBox1.Refresh();
            }
        }
        private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
        {
            int wx = (int)displayWorld.screenToWorldX(e.X);
            int wy = (int)displayWorld.screenToWorldY(e.Y);
            if (e.Button == MouseButtons.Left)
            {
                post_MsgLocateCamera(wx, wy);
                pictureBox1.Refresh();
            }
        }
        private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
        {

        }

        private Pen camera_pen = new Pen(Color.White);

        private void pictureBox1_Paint(object sender, PaintEventArgs e)
        {
            float scaleX = pictureBox1.Width / (float)mZoneData.TotalWidth;
            float scaleY = pictureBox1.Height / (float)mZoneData.TotalHeight;
            float scaleD = Math.Min(scaleX, scaleY);
            displayWorld.setWindow(
                new RectangleF(0, 0,
                pictureBox1.Width,
                pictureBox1.Height));
            displayWorld.setCameraScale(scaleD, scaleD);
            displayWorld.setCamera(
                mZoneData.TotalWidth / 2f,
                mZoneData.TotalHeight / 2f);
            displayWorld.render(e.Graphics);
            if (bLastCamera != null)
            {
                e.Graphics.DrawRectangle(camera_pen,
                    displayWorld.worldToScreenX(bLastCamera.X - bLastCamera.W / 2),
                    displayWorld.worldToScreenY(bLastCamera.Y - bLastCamera.H / 2),
                    displayWorld.worldToScreenSizeX(bLastCamera.W),
                    displayWorld.worldToScreenSizeY(bLastCamera.H)
                    );
            }
        }

        private void pictureBox1_ClientSizeChanged(object sender, EventArgs e)
        {
            this.pictureBox1.Refresh();
        }

        private void SceneEditor_KeyDown(object sender, KeyEventArgs e)
        {

        }
        #endregion

        //---------------------------------------------------------------------------------
        #region Post To Scene
        //---------------------------------------------------------------------------------

        private void post_MsgSetScene(SceneData zonedata)
        {
            MsgSetScene ss = new MsgSetScene();
            ss.ProjectName = TemplateManager.Factory.GetType().Name;
            ss.Data = zonedata.ZoneData;
            ss.FileName = zonedata.FileName;
            ss.ResourceDir = Editor.EditorRootDir;
            ss.ResourceProperty = zonedata.ResourceProperty;
            mPlugin.SendMessage(ss);
        }
        private void post_MsgPutUnit(UnitData data)
        {
            MsgPutUnit ss = new MsgPutUnit();
            ss.Data = data;
            ss.UnitData = Editor.Instance.GetTemplateByType<UnitInfo>(data.UnitTemplateID);
            mPlugin.SendMessage(ss);
        }
        private void post_MsgPutItem(ItemData data)
        {
            MsgPutItem ss = new MsgPutItem();
            ss.Data = data;
            ss.Item = Editor.Instance.GetTemplateByType<ItemTemplate>(data.ItemTemplateID);
            mPlugin.SendMessage(ss);
        }
        private void post_MsgPutPoint(PointData data)
        {
            MsgPutPoint ss = new MsgPutPoint();
            ss.Data = data;
            mPlugin.SendMessage(ss);
        }
        private void post_MsgPutRegion(RegionData data)
        {
            MsgPutRegion ss = new MsgPutRegion();
            ss.Data = data;
            mPlugin.SendMessage(ss);
        }
        private void post_MsgPutDecoration(DecorationData data)
        {
            MsgPutDecoration ss = new MsgPutDecoration();
            ss.Data = data;
            mPlugin.SendMessage(ss);
        }
        private void post_MsgPutArea(AreaData data)
        {
            MsgPutArea ss = new MsgPutArea();
            ss.Data = data;
            mPlugin.SendMessage(ss);
        }
        private void post_MsgRemoveObject(string name)
        {
            MsgRemoveObject ss = new MsgRemoveObject();
            ss.Name = name;
            mPlugin.SendMessage(ss);
        }
        private void post_MsgRenameObject(string src, string dst)
        {
            MsgRenameObject ss = new MsgRenameObject();
            ss.SrcName = src;
            ss.DstName = dst;
            mPlugin.SendMessage(ss);
        }
        private void post_MsgSelectObject(string name)
        {
            MsgSelectObject ss = new MsgSelectObject();
            ss.Name = name;
            mPlugin.SendMessage(ss);
        }
        private void post_MsgShowTerrain()
        {
            MsgShowTerrain ss = new MsgShowTerrain();
            ss.Show = toolStripButton_ShowTerrain.Checked;
            mPlugin.SendMessage(ss);
        }
        private void post_MsgLocateCamera(float x, float y)
        {
            MsgLocateCamera ss = new MsgLocateCamera();
            ss.X = x;
            ss.Y = y;
            mPlugin.SendMessage(ss);
        }
        private void post_MsgSetEditorMode(int mode)
        {
            MsgSetEditorMode ss = new MsgSetEditorMode();
            ss.Mode = mode;
            mPlugin.SendMessage(ss);
        }
        private void post_MsgSetTerrainBrush()
        {
            try
            {
                int color = toolStripButton_Color.BackColor.ToArgb();
                int size = int.Parse(combo_BrushSize.Text);
                MsgSetTerrainBrush ss = new MsgSetTerrainBrush();
                ss.ARGB = color;
                ss.Size = size;
                ss.Size = Math.Max(1, ss.Size);
                ss.Brush = (MsgSetTerrainBrush.BrushType)((btn_Brush.Tag as ToolStripMenuItem).Tag);
                mPlugin.SendMessage(ss);
            }
            catch (Exception err)
            {
                MessageBox.Show(err.Message);
            }
        }
        #endregion

        // ---------------------------------------------------------------------------------------------

        #region Recived From Scene

        private bool bLoadScene = false;

        private RspCameraChanged bLastCamera = null;

        private void rsp(RspZoneFlagBathChanged dt)
        {
            foreach (RspZoneFlagChanged dd in dt.Flags)
            {
                try
                {
                    mZoneData.TerrainMatrix[dd.SceneX, dd.SceneY] = dd.Flag;
                }
                catch (Exception ) { }
            }
            pictureBox1.Refresh();
        }


        private void rsp(RspTerrainBrushChanged data)
        {
            combo_BrushSize.Text = data.Size.ToString();
        }

        private void rsp(RspZoneFlagChanged dt)
        {
            try
            {
                mZoneData.TerrainMatrix[dt.SceneX, dt.SceneY] = dt.Flag;
                pictureBox1.Refresh();
            }
            catch (Exception err) { }
        }

        private void rsp(RspOnObjectSelected dt)
        {
            ObjectTreeNode tn = G2DTreeNodeGroup.FindNodeByText<ObjectTreeNode>(treeRoot, dt.Name, true);
            if (tn != null)
            {
                if (dt.Selected)
                {
                    treeView1.SelectedNode = tn;
                    propertyGrid1.SelectedObject = new G2DPropertyDescriptor(tn.Data, new SceneDataAdapters(this));
                }
                else
                {
                    if (tn.IsSelected && treeView1.SelectedNode == tn)
                    {
                        treeView1.SelectedNode = tn.Parent;
                        propertyGrid1.SelectedObject = null;
                    }
                }
            }
        }
        private void rsp(RspObjectPositionChanged dt)
        {
            ObjectTreeNode tn = G2DTreeNodeGroup.FindNodeByText<ObjectTreeNode>(treeRoot, dt.Name, true);
            if (tn != null)
            {
                tn.Data.X = dt.x;
                tn.Data.Y = dt.y;
                propertyGrid1.Refresh();
            }
        }
        private void rsp(RspObjectDirectionChanged dt)
        {
            ObjectTreeNode tn = G2DTreeNodeGroup.FindNodeByText<ObjectTreeNode>(treeRoot, dt.Name, true);
            if (tn != null)
            {
                if (tn.Data is UnitData)
                {
                    UnitData ud = tn.Data as UnitData;
                    ud.Direction = dt.dir;
                }
                else if (tn.Data is ItemData)
                {
                    ItemData ud = tn.Data as ItemData;
                    ud.Direction = dt.dir;
                }
                propertyGrid1.Refresh();
            }
        }
        private void rsp(RspObjectSizeChanged dt)
        {
            ObjectTreeNode tn = G2DTreeNodeGroup.FindNodeByText<ObjectTreeNode>(treeRoot, dt.Name, true);
            if (tn != null && tn.Data is RegionData)
            {
                RegionData rg = tn.Data as RegionData;
                rg.W = dt.x;
                rg.H = dt.y;
                propertyGrid1.Refresh();
            }
        }
        private void rsp(RspPointLinkChanged dt)
        {
            ObjectTreeNode src_tn = G2DTreeNodeGroup.FindNodeByText<ObjectTreeNode>(treeRoot, dt.SrcPointName, true);
            ObjectTreeNode dst_tn = G2DTreeNodeGroup.FindNodeByText<ObjectTreeNode>(treeRoot, dt.DstPointName, true);
            if (src_tn != null &&
                dst_tn != null &&
                src_tn.Data is PointData &&
                dst_tn.Data is PointData)
            {
                PointData sp = src_tn.Data as PointData;
                PointData dp = dst_tn.Data as PointData;
                sp.NextNames.Add(dp.Name);
            }
        }

        private void rsp(RspEditorState dt)
        {
            if (!bLoadScene)
            {
                if (dt.State == RspEditorState.STATE_SUCCEED)
                {
                    LoadScene();
                    this.bLoadScene = true;
                    this.splitContainer1.Enabled = true;
                    this.toolStrip1.Enabled = true;
                }
            }
        }

        private void rsp(RspCameraChanged dt)
        {
            bLastCamera = dt;
            pictureBox1.Refresh();
        }

        private void OnPluginMessageHandler(object data)
        {
            try
            {
                if (data is RspEditorState)
                {
                    rsp(data as RspEditorState);
                }
                else if (data is RspTerrainBrushChanged)
                {
                    rsp(data as RspTerrainBrushChanged);
                }

                else if (data is RspZoneFlagChanged)
                {
                    rsp(data as RspZoneFlagChanged);
                }
                else if (data is RspZoneFlagBathChanged)
                {
                    rsp(data as RspZoneFlagBathChanged);
                }

                else if (data is RspOnObjectSelected)
                {
                    rsp(data as RspOnObjectSelected);
                }

                else if (data is RspObjectPositionChanged)
                {
                    rsp(data as RspObjectPositionChanged);
                }
                else if (data is RspObjectDirectionChanged)
                {
                    rsp(data as RspObjectDirectionChanged);
                }

                else if (data is RspObjectSizeChanged)
                {
                    rsp(data as RspObjectSizeChanged);
                }

                else if (data is RspPointLinkChanged)
                {
                    rsp(data as RspPointLinkChanged);
                }

                else if (data is RspCameraChanged)
                {
                    rsp(data as RspCameraChanged);
                }
            }
            catch (Exception err)
            {
                MessageBox.Show("OnPluginMessageHandler\n" + err.Message);
            }
        }
        #endregion



        //----------------------------------------------------------------------------------


        #region Tree_Node_And_Units


        public class ObjectTreeNode : G2DTreeNode<SceneObjectData>
        {

            public ObjectTreeNode(SceneObjectData data) : base(data) { }
            public ObjectTreeNode(Stream input) : base(input) { }

            public void RefreshData()
            {
                if (!Data.Enable)
                {
                    this.ForeColor = Color.LightGray;
                }
                else
                {
                    this.ForeColor = Color.Black;
                }
            }
        }

        private G2DTreeNodeGroup GetSelectedSceneGroup()
        {
            if (treeView1.SelectedNode is G2DTreeNodeGroup)
            {
                return treeView1.SelectedNode as G2DTreeNodeGroup;
            }
            if (treeView1.SelectedNode is ObjectTreeNode)
            {
                return (treeView1.SelectedNode as ObjectTreeNode).Parent as G2DTreeNodeGroup;
            }
            return null;
        }
        private ObjectTreeNode GetSelectedAsSceneObject()
        {
            if (treeView1.SelectedNode is ObjectTreeNode)
            {
                return treeView1.SelectedNode as ObjectTreeNode;
            }
            return null;
        }

        private void SelectSceneObject(ObjectTreeNode node)
        {
            node.RefreshData();
            if (propertyGrid1.SelectedObject != null)
            {
                G2DPropertyDescriptor desc = propertyGrid1.SelectedObject as G2DPropertyDescriptor;
                if (desc.EditData.Equals(node.Data))
                {
                    return;
                }
            }
            propertyGrid1.SelectedObject = new G2DPropertyDescriptor(node.Data, new SceneDataAdapters(this));
            toolStripTextBox1.Text = node.DataID;
            post_MsgSelectObject(node.DataID);
        }

        public SceneObjectData ShowSelectSceneObject(Type type, string srcName)
        {
            TreeNode droot = G2DListSelectEditor<SceneObjectData>.TreeNodeDuplicate(treeRoot);
            foreach (TreeNode tn in G2DTreeNodeBase.GetAllNodes(droot))
            {
                if (!type.IsInstanceOfType(tn.Tag) && tn.Nodes.Count == 0)
                {
                    tn.Remove();
                }
            }
            SceneObjectData src = GetSceneObjectData(srcName);
            G2DListSelectEditor<SceneObjectData> dialog = new G2DListSelectEditor<SceneObjectData>(droot, treeView1.ImageList, src);
            if (dialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                return dialog.SelectedObject;
            }
            return null;
        }


        public CommonAI.Zone.ZoneEditor.ZoneEvent ShowSelectSceneEvent(string srcName)
        {
            CommonAI.Zone.ZoneEditor.ZoneEvent src = GetSceneEventData(srcName);
            G2DListSelectEditor<CommonAI.Zone.ZoneEditor.ZoneEvent> dialog = new G2DListSelectEditor<CommonAI.Zone.ZoneEditor.ZoneEvent>(
                new List<CommonAI.Zone.ZoneEditor.ZoneEvent>(mData.Events), src);
            if (dialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                return dialog.SelectedObject;
            }
            return null;
        }

        public ZoneVar ShowSelectSceneVar(string srcKey, Type valueType)
        {
            ZoneVar src = GetSceneVarData(srcKey);
            G2DListSelectEditor<ZoneVar> dialog = new G2DListSelectEditor<ZoneVar>(
                GetSceneVarsAsType(valueType), src);
            if (dialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                return dialog.SelectedObject;
            }
            return null;
        }

        private static List<SceneObjectData> copying_objects = new List<SceneObjectData>();

        private void DuplicateSelected()
        {
            var selected = GetSelectedAsSceneObject();
            if (selected != null)
            {
                G2DTreeNodeGroup parent = selected.Parent as G2DTreeNodeGroup;
                SceneObjectData copy = XmlUtil.CloneObject(selected.Data);
                ObjectTreeNode copy_node = new ObjectTreeNode(copy);
                copy_node.ImageKey = selected.ImageKey;
                copy_node.SelectedImageKey = selected.SelectedImageKey;
                copy_node.ContextMenuStrip = selected.ContextMenuStrip;
                copy.Name = selected.Data.Name + "_Copy";
                copy.SavePath = "";
                TryAddSceneNode(copy_node, parent, parent.Nodes.IndexOf(selected) + 1);
                return;
            }
            var group = GetSelectedSceneGroup();
            if (group != null)
            {
                G2DTreeNodeGroup parent = group.Parent as G2DTreeNodeGroup;
                foreach (var sub in group.GetAllNodes())
                {
                    if (sub is ObjectTreeNode)
                    {
                        var otn = sub as ObjectTreeNode;
                        SceneObjectData copy = XmlUtil.CloneObject(otn.Data);
                        ObjectTreeNode copy_node = new ObjectTreeNode(copy);
                        copy_node.ImageKey = sub.ImageKey;
                        copy_node.SelectedImageKey = sub.SelectedImageKey;
                        copy_node.ContextMenuStrip = sub.ContextMenuStrip;
                        copy.Name = otn.Data.Name + "_Copy";
                        copy.SavePath = group.GetSavePath(otn, true);
                        TryAddSceneNode(copy_node, parent, parent.Nodes.IndexOf(group) + 1);
                    }
                }
                return;
            }
        }
        private void CopySelected()
        {
            copying_objects.Clear();
            var node = GetSelectedAsSceneObject();
            if (node != null)
            {
                var parent = node.Parent as G2DTreeNodeGroup;
                var copying = XmlUtil.CloneObject(node.Data);
                copying.SavePath = parent.GetSavePath(node);
                copying_objects.Add(copying);
                return;
            }
            var group = GetSelectedSceneGroup();
            if (group != null)
            {
                foreach (var sub in group.GetAllNodes())
                {
                    if (sub is ObjectTreeNode)
                    {
                        var otn = sub as ObjectTreeNode;
                        var copying = XmlUtil.CloneObject(otn.Data);
                        copying.SavePath = group.GetSavePath(otn, true);
                        copying_objects.Add(copying);
                    }
                }
                return;
            }
        }
        private string BestNewName(string name)
        {
            if (ContainsSceneObject(name))
            {
                int i = name.Length - 1;
                for (; i >= 0; --i)
                {
                    char ch = name[i];
                    if (ch >= '0' && ch <= '9')
                    {
                        continue;
                    }
                    else
                    {
                        break;
                    }
                }
                name = name.Substring(0, i + 1);
            }
            return name + treeRoot.GetAllNodes().Count;
        }
        private void Paste()
        {
            G2DTreeNodeGroup parent = treeRoot;
            int index = parent.Nodes.Count;
            do
            {
                var selected = GetSelectedAsSceneObject();
                if (selected != null)
                {
                    parent = selected.Parent as G2DTreeNodeGroup;
                    index = parent.Nodes.IndexOf(selected) + 1;
                    break;
                }
                var group = GetSelectedSceneGroup();
                if (group != null)
                {
                    parent = group;
                    index = parent.Nodes.Count;
                    break;
                }
                break;
            }
            while (true);
            foreach (var copying_object in copying_objects)
            {
                SceneObjectData copy = XmlUtil.CloneObject(copying_object);
                ObjectTreeNode copy_node = CreateSceneObjectNode(copy);
                TryAddSceneNode(copy_node, parent, index);
            }
        }
        private bool TryAddSceneNode(ObjectTreeNode copy_node, G2DTreeNodeGroup parent, int index)
        {
            string src_name = copy_node.Name;
            SceneObjectData copy = copy_node.Data;
            while (!string.IsNullOrEmpty(copy.Name))
            {
                if (ContainsSceneObject(copy.Name))
                {
                    copy.Name = BestNewName(copy.Name);
                    copy.Name = G2DTextDialog.Show(copy.Name, "复制: " + src_name);
                }
                else
                {
                    copy_node.SetDataID(copy.Name);
                    var group = parent.GetOrCreateGroup(copy.SavePath);
                    if (group != parent)
                    {
                        group.Nodes.Add(copy_node);
                        parent.Expand();
                        group.Expand();
                    }
                    else
                    {
                        parent.Nodes.Insert(index, copy_node);
                        parent.Expand();
                    }
                    copy_node.RefreshData();
                    RefreshObject(copy);
                    treeView1.SelectedNode = copy_node;
                    SelectSceneObject(copy_node);
                    return true;
                }
            }
            return false;
        }

        private void RemoveSelectedSceneObject()
        {
            ObjectTreeNode node = GetSelectedAsSceneObject();
            if (node != null)
            {
                if (MessageBox.Show(
                    "确定要删除: " + node.DataID,
                    "确认",
                    MessageBoxButtons.OKCancel) == DialogResult.OK)
                {
                    node.Parent.Nodes.Remove(node);
                    post_MsgRemoveObject(node.DataID);
                }
            }
        }
        private void RenameSceneObject()
        {
            ObjectTreeNode node = GetSelectedAsSceneObject();
            if (node != null)
            {
                string name = node.DataID;
                while (!string.IsNullOrEmpty(name))
                {
                    name = G2DTextDialog.Show(name, "重命名: " + name);
                    if (name != null)
                    {
                        if (ContainsSceneObject(name))
                        {
                            MessageBox.Show("\"" + name + "\" 已存在!");
                        }
                        else
                        {
                            string src_name = node.DataID;
                            node.SetDataID(name);
                            post_MsgRenameObject(src_name, name);
                            return;
                        }
                    }
                }
            }
        }

        private bool ContainsSceneObject(string name)
        {
            TreeNode tn = G2DTreeNodeBase.FindNodeByText<ObjectTreeNode>(treeRoot, name, true);
            return tn != null;
        }

        private SceneObjectData GetSceneObjectData(string name)
        {
            if (name != null)
            {
                TreeNode tn = G2DTreeNodeBase.FindNodeByText<ObjectTreeNode>(treeRoot, name, true);
                if (tn is ObjectTreeNode)
                {
                    return (tn as ObjectTreeNode).Data;
                }
            }
            return null;
        }

        private CommonAI.Zone.ZoneEditor.ZoneEvent GetSceneEventData(string name)
        {
            if (name != null)
            {
                foreach (CommonAI.Zone.ZoneEditor.ZoneEvent evt in mData.Events)
                {
                    if (evt.Name.Equals(name))
                    {
                        return evt;
                    }
                }
            }
            return null;
        }

        private ZoneVar GetSceneVarData(string name)
        {
            if (name != null)
            {
                foreach (ZoneVar var in mData.EnvironmentVars)
                {
                    if (var.Key.Equals(name))
                    {
                        return var;
                    }
                }
            }
            return null;
        }
        private List<ZoneVar> GetSceneVarsAsType(Type valueType)
        {
            if (valueType == null)
            {
                return new List<ZoneVar>(mData.EnvironmentVars);
            }
            else
            {
                List<ZoneVar> ret = new List<ZoneVar>();
                foreach (ZoneVar var in mData.EnvironmentVars)
                {
                    if (valueType.IsInstanceOfType(var.Value))
                    {
                        ret.Add(var);
                    }
                }
                return ret;
            }
        }

        private void AddSceneGroup()
        {
            G2DTreeNodeGroup parent = GetSelectedSceneGroup();
            if (parent != null)
            {
                string name = G2DTextDialog.Show("分组", "添加过滤器");
                if (name != null)
                {
                    G2DTreeNodeGroup group = parent.AddG2DGroup(name);
                    parent.Expand();
                    treeView1.SelectedNode = group;
                }
            }
        }

        private void RenameSceneGroup()
        {
            G2DTreeNodeGroup parent = GetSelectedSceneGroup();
            if (parent != null)
            {
                string name = G2DTextDialog.Show(parent.Text, "添加过滤器");
                if (name != null)
                {
                    parent.Text = name;
                }
            }
        }

        private ObjectTreeNode CreateSceneObjectNode(SceneObjectData data)
        {
            string imageKey = "icon_res_1.png";
            if (data is PointData)
            {
                imageKey = "icon_trigger.png";
            }
            else if (data is RegionData)
            {
                imageKey = "icon_layer.png";
            }
            else if (data is UnitData)
            {
                imageKey = "icon_res_2.png";
            }
            else if (data is ItemData)
            {
                imageKey = "icon_res_4.png";
            }
            else if (data is DecorationData)
            {
                imageKey = "icon_res_1.png";
            }
            else if (data is AreaData)
            {
                imageKey = "icon_res_6.png";
            }
            ObjectTreeNode node = new ObjectTreeNode(data);
            node.ImageKey = imageKey;
            node.SelectedImageKey = imageKey;
            node.ContextMenuStrip = objectMenuStrip;
            node.RefreshData();
            return node;
        }

        private SceneObjectData AddSceneObject(Type dataType, Action<SceneObjectData> callback = null)
        {
            G2DTreeNodeGroup parent = GetSelectedSceneGroup();
            if (parent == null)
            {
                parent = treeRoot;
            }
            if (parent != null)
            {
                string name = dataType.Name + treeRoot.GetAllNodes().Count;
                while (!string.IsNullOrEmpty(name))
                {
                    name = G2DTextDialog.Show(name, "添加: " + name);
                    if (name != null)
                    {
                        if (ContainsSceneObject(name))
                        {
                            MessageBox.Show("\"" + name + "\" 已存在!");
                        }
                        else
                        {
                            SceneObjectData data = (SceneObjectData)Activator.CreateInstance(dataType);
                            data.Name = name;
                            if (bLastCamera != null)
                            {
                                data.X = bLastCamera.X;
                                data.Y = bLastCamera.Y;
                            }
                            ObjectTreeNode node = CreateSceneObjectNode(data);
                            parent.Nodes.Add(node);
                            parent.Expand();
                            if (callback != null)
                            {
                                callback.Invoke(data);
                            }
                            RefreshObject(data);
                            treeView1.SelectedNode = node;
                            SelectSceneObject(node);
                            return data;
                        }
                    }
                }
            }
            return null;
        }

        private bool LoadSceneObject(SceneObjectData data)
        {
            if (ContainsSceneObject(data.Name))
            {
                MessageBox.Show("\"" + data.Name + "\" 已存在!");
                return false;
            }
            else
            {
                ObjectTreeNode node = CreateSceneObjectNode(data);
                G2DTreeNodeGroup parent = treeRoot.GetOrCreateGroup(data.SavePath);
                parent.Nodes.Add(node);
                RefreshObject(data);
                return true;
            }
        }

        private void RefreshObject(SceneObjectData data)
        {
            if (data is UnitData)
            {
                post_MsgPutUnit(data as UnitData);
            }
            else if (data is ItemData)
            {
                post_MsgPutItem(data as ItemData);
            }
            else if (data is PointData)
            {
                post_MsgPutPoint(data as PointData);
            }
            else if (data is RegionData)
            {
                post_MsgPutRegion(data as RegionData);
            }
            else if (data is DecorationData)
            {
                post_MsgPutDecoration(data as DecorationData);
            }
            else if (data is AreaData)
            {
                post_MsgPutArea(data as AreaData);
            }
        }


        #endregion


        //----------------------------------------------------------------------------------

        class EditorMiniMap : DisplayTerrain
        {
            private G2DTreeNodeGroup treeRoot;

            public EditorMiniMap(G2DTreeNodeGroup treeRoot, ZoneInfo terrain)
            {
                this.treeRoot = treeRoot;
                base.InitTerrain(terrain);
            }

            public override void Dispose()
            {

            }

            public void ResetTerrain(ZoneInfo terrain)
            {
                base.InitTerrain(terrain);
            }

            protected override void renderObjects(Graphics g, RectangleF worldBounds)
            {
                foreach (TreeNode tn in treeRoot.GetAllNodes())
                {
                    if (tn is ObjectTreeNode)
                    {
                        SceneObjectData sd = (tn as ObjectTreeNode).Data;
                        System.Drawing.Drawing2D.GraphicsState state = g.Save();
                        g.TranslateTransform(sd.X, sd.Y);
                        renderNode(g, sd);
                        g.Restore(state);
                    }
                }
            }

            protected override void renderScreen(Graphics g, RectangleF worldBounds)
            {

            }

            private Pen pen = new Pen(Color.White);
            private SolidBrush brush = new SolidBrush(Color.White);

            private void renderNode(Graphics g, SceneObjectData data)
            {
                pen.Color = brush.Color = Color.FromArgb(data.Color);

                if (data is PointData)
                {
                    g.FillEllipse(brush, -1, -1, 2, 2);
                }
                else if (data is RegionData)
                {
                    RegionData rd = data as RegionData;
                    if (rd.RegionType == RegionData.Shape.RECTANGLE)
                    {
                        g.FillRectangle(brush, -rd.W / 2, -rd.H / 2, rd.W, rd.H);
                    }  
                    else if (rd.RegionType == RegionData.Shape.STRIP)
                    {
                        float line_r = rd.W / 2;
                        Line2 line = new Line2(0, 0, 0, 0);
                        MathVector.movePolar(line.p, rd.StripDirection, -rd.H / 2);
                        MathVector.movePolar(line.q, rd.StripDirection, +rd.H / 2);
                        DrawingUtils.FillLineRect(g, brush, line.p.X, line.p.Y, line.q.X, line.q.Y, line_r);
                    }
					else
					{
						g.FillEllipse(brush, -rd.W / 2, -rd.H / 2, rd.W, rd.H);
					}
				}
                else if (data is UnitData)
                {
                    UnitData rd = data as UnitData;
                    UnitInfo ut = Editor.Instance.GetTemplateByType<UnitInfo>(rd.UnitTemplateID);
                    if (ut != null)
                    {
                        g.FillEllipse(brush, -ut.BodySize, -ut.BodySize, ut.BodySize * 2, ut.BodySize * 2);
                    }
                    else
                    {
                        g.FillEllipse(brush, -1, -1, 2, 2);
                    }
                }
                else if (data is ItemData)
                {
                    ItemData rd = data as ItemData;
                    ItemTemplate ut = Editor.Instance.GetTemplateByType<ItemTemplate>(rd.ItemTemplateID);
                    if (ut != null)
                    {
                        g.FillEllipse(brush, -ut.BodySize, -ut.BodySize, ut.BodySize * 2, ut.BodySize * 2);
                    }
                    else
                    {
                        g.FillEllipse(brush, -1, -1, 2, 2);
                    }
                }
                else if (data is DecorationData)
                {
                    DecorationData rd = data as DecorationData;
                    if (rd.RegionType == DecorationData.Shape.RECTANGLE)
                    {
                        g.FillRectangle(brush, -rd.W / 2, -rd.H / 2, rd.W, rd.H);
                    }
                    else
                    {
                        g.FillEllipse(brush, -rd.W / 2, -rd.H / 2, rd.W, rd.H);
                    }
                }
                else if (data is AreaData)
                {
                    AreaData rd = data as AreaData;
                    g.FillEllipse(brush, -1, -1, 2, 2);
                }
            }

        }

    }
}