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

using System.Text;
using System.Windows.Forms;
using System.Drawing.Drawing2D;
using CommonAI.RTS;
using CommonLang.Vector;
using System.IO;
using GameEditorPlugin.Win32.Runtime;
using CommonFroms.Utils;
using CommonLang.Log;
using CommonAI.Zone;
using GameEditorPlugin;
using CommonLang;
using GameEditorPlugin.Win32.BattleClient;
using System.Runtime.InteropServices;
using CommonFroms;
using CommonAI.ZoneClient;
using CommonAIEditor;
using CommonAI.Zone.Replay;
using GameEditorPlugin.Win32;
using CommonAI.Zone.ZoneEditor;
using CommonFroms.G2D;
using CommonAI.ZoneClient.Agent;
using static CommonAI.ZoneClient.ZoneUnit;

namespace GameEditorPlugin.Win32.Runtime
{
    public partial class FormRuntimeGameLocal : Form
    {
        private readonly DirectoryInfo dataDir;
        private int sceneID;
        private RuntimeGameLocal world;
        private bool step1 = false;
        private float TurboX = 1;
        private bool recorder;

        private ConsoleOutput console;
        private long lastUpdateTimeMS;
        private float mouseX, mouseY;
        private Vector2 pic_lastMouesDown;
        private Vector2 pic_lastCameraPos;


        public EditorScene Zone { get { return world.Battle.Zone; } }
        public RuntimeGameLocal Battle { get { return world; } }
        public PointF MousePos { get { return new PointF(mouseX, mouseY); } }
        public bool IsFreeView { get; set; }

        protected ZoneObject SelectedZoneObject { get { return propertyGrid_selected.SelectedObject as ZoneObject; } }

        public FormRuntimeGameLocal() : this(null, 0, false)
        {
        }
        public FormRuntimeGameLocal(DirectoryInfo data_dir, int sceneID, bool recorder = false)
        {
            this.dataDir = data_dir;
            this.sceneID = sceneID;
            this.IsFreeView = false;
            this.DoubleBuffered = true;
            this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);

            InitializeComponent();

            if (dataDir == null) return;
            this.console = new ConsoleOutput();
            this.recorder = recorder;
            this.pictureBox1.MouseWheel += pictureBox1_MouseWheel;
            this.pictureBox1.KeyDown += pictureBox1_KeyDown;

            this.Disposed += FormRuntimeGameLocal_Disposed;
        }

        private void FormRuntimeGameLocal_Disposed(object sender, EventArgs e)
        {
            if (this.world != null)
            {
                try
                {
                    this.world.Dispose();
                }
                catch (Exception err)
                {
                    MessageBox.Show(err.Message + "\n" + err.StackTrace);
                }
            }
        }

        private void FormRuntimeGameLocal_Load(object sender, EventArgs e)
        {
            if (dataDir == null) return;
            try
            {
                EditorTemplates templates = new EditorTemplates(dataDir.FullName, TemplateManager.MessageCodec);
                templates.LoadAllTemplates(false, true);

                CommonAI.Zone.Replay.BattleRecorder rec = null;
                if (recorder)
                {
                    string rec_name = string.Format("scene_{0}_{1}.rec", sceneID, CUtils.FormatTime(DateTime.Now));
                    rec = new CommonAI.Zone.Replay.BattleRecorder(templates.Templates, sceneID, rec_name);
                    FileStream fos = new FileStream(dataDir.Parent.FullName + "\\" + rec.Name, FileMode.CreateNew, FileAccess.Write);
                    rec.SetOut(fos);
                    this.Disposed += (object sender2, EventArgs e2) =>
                    {
                        try
                        {
                            fos.Flush();
                            fos.Close();
                        }
                        catch (Exception ) { }
                        try
                        {
                            fos.Dispose();
                        }
                        catch (Exception ) { }
                    };
                }

                this.world = new RuntimeGameLocal(templates, sceneID, rec);
                //                 this.world.ShowTerrain = true;
                //                 this.world.ShowGrid = chk_ShowGrid.Checked;
                //                 this.world.ShowAttackRange = chkShowAttackRangeToolStripMenuItem.Checked;
                //                 this.world.ShowDamageRange = chkShowDamageRange.Checked;
                //                 this.world.ShowGuardRange = chkShowGuardRangeToolStripMenuItem.Checked;
                //                 this.world.ShowHP = chkShowHP.Checked;
                //                 this.world.ShowName = chkShowName.Checked;
                //                 this.world.ShowZ = chkShowZ.Checked;
                //                 this.world.ShowLog = chkShowLog.Checked;
                //                 this.world.ShowAllLog = chkShowLogToolStripMenuItem.Checked;
                this.world.GenShowItems(this.toolStripDropDownButton1);
                this.world.Layer.LayerInit += this.Layer_LayerInit;
                this.world.Layer.ActorAdded += this.Layer_ActorAdded;

                foreach (SyncMode mode in Enum.GetValues(typeof(SyncMode)))
                {
                    ToolStripButton item = new ToolStripButton(mode.ToString());
                    item.Tag = mode;
                    item.Click += item_SyncMode_Click;
                    item.CheckOnClick = true;
                    drop_SyncMode.DropDownItems.Add(item);
                    if (world.Layer.ActorSyncMode == mode)
                    {
                        item.Checked = true;
                    }
                }

                this.world.BindMessageFilter(pictureBox1);
                this.OnBattleCreated(world);

                this.timer2.Interval = (int)(1000f / world.Templates.Templates.CFG.SYSTEM_FPS);
                this.timer2.Enabled = true;
                this.timer2.Start();
            }
            catch (Exception err)
            {
                MessageBox.Show(err.Message + "\n" + err.StackTrace);
            }
        }

        private void FormRuntimeGameLocal_Shown(object sender, EventArgs e)
        {
            if (dataDir == null) return;
            console.DockTo = this;
            console.Show();
        }

        private void FormRuntimeGameLocal_FormClosed(object sender, FormClosedEventArgs e)
        {
            if (dataDir == null) return;
            console.Close();
            if (this.world != null)
            {
                this.world.UnbindMessageFilter();
            }
        }

        //---------------------------------------------------------------------------------------
        #region LayerEvents

        protected virtual void OnBattleCreated(RuntimeGameLocal battle)
        {

        }

        protected virtual void Layer_LayerInit(ZoneLayer layer)
        {
            float scale = Math.Max(
                ((float)pictureBox1.Width) / world.Width,
                ((float)pictureBox1.Height) / world.Height);
            this.world.setCameraScale(scale, scale);
        }

        protected virtual void Layer_ActorAdded(ZoneLayer layer, ZoneActor actor)
        {
            actor.IsSkillAutoFocusTarget = btn_IsAutoFocusTarget.Checked;
            actor.SendUnitGuard(btn_AutoAttack.Checked);
            resetSkills(actor);
            actor.OnSkillChanged += Actor_OnSkillChanged;
        }

        protected virtual void Actor_OnSkillChanged(SkillOption op, ZoneUnit unit, int baseSkillID, params int[] skills)
        {
            resetSkills(unit as ZoneActor);
        }

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


        protected virtual void resetSkills(ZoneActor actor)
        {
            toolStripActorSkills.Items.Clear();
            int i = 1;
            using (var list = ListObjectPool<ZoneUnit.SkillState>.AllocAutoRelease())
            {
                actor.GetSkillStatus(list);
                foreach (var skill in list)
                {
                    ToolStripButton tb = new ToolStripButton(i.ToString());
                    tb.DisplayStyle = ToolStripItemDisplayStyle.Text;
                    tb.ToolTipText = skill.Data.ToString();
                    tb.Tag = skill;
                    tb.BackColor = Color.Black;
                    tb.ForeColor = Color.White;
                    tb.Click += new EventHandler((o, e) =>
                    {
                        if (SelectedZoneObject != null)
                        {
                            actor.SendUnitLaunchSkill(skill.Data.ID, SelectedZoneObject.ObjectID);
                        }
                        else
                        {
                            actor.SendUnitLaunchSkill(skill.Data.ID, mouseX, mouseY);
                        }
                    });
                    toolStripActorSkills.Items.Add(tb);
                    i++;
                }
            }
        }

        protected virtual void setSelectedObject(ZoneObject obj)
        {
            propertyGrid_selected.SelectedObject = obj;
            if (obj != null)
            {
                lbl_selected.Text = obj.Name;
            }
            else
            {
                lbl_selected.Text = "";
            }
        }

        #endregion
        //---------------------------------------------------------------------------------------
        #region PictureBoxEvents

        // timer 2 for render system
        protected virtual void timerUpdate_Tick(object sender, EventArgs e)
        {
            pictureBox1.Refresh();
            btnTurbo.Text = "加速x" + TurboX;
            if ((!this.Visible) || (this.WindowState == FormWindowState.Minimized))
            {
                world.Pause = true;
            }
            else
            {
                world.Pause = !(btn_Play.Checked || step1);
                step1 = false;
            }
        }

        protected virtual void pictureBox1_MouseDown(object sender, MouseEventArgs e)
        {
            pictureBox1.Focus();
            try
            {
                pic_lastMouesDown = new Vector2(e.Location.X, e.Location.Y);
                if (world != null)
                {
                    float wx = mouseX = world.screenToWorldX(e.X);
                    float wy = mouseY = world.screenToWorldY(e.Y);
                    pic_lastCameraPos = new Vector2(world.CameraX, world.CameraY);

                    if (e.Button == MouseButtons.Left)
                    {
                        if (Keyboard.IsShiftDown)
                        {
                            if (world.Client.Actor != null)
                                world.Client.Actor.SendUnitLaunchNormalAttack(wx, wy);
                        }
                        else
                        {
                            DisplayLayerObject selected = world.PickObject(wx, wy);
                            ZoneItem item = pictureBox1_CheckPickItem();
                            if (item != null)
                            {
                                if (world.Client.Actor != null)
                                {
                                    world.Client.Actor.SendUnitPickObject(item.ObjectID);
                                }
                                setSelectedObject(item);
                            }
                            else if (selected is DisplayGameUnit)
                            {
                                if (world.Client.Actor != null)
                                {
                                    DisplayGameUnit su = selected as DisplayGameUnit;
                                    if (su.Data.Force != world.Client.Actor.Force)
                                    {
                                        world.Client.Actor.SendUnitFocuseTarget(selected.ObjectID);
                                    }
                                    else
                                    {
                                        world.Client.Actor.SendUnitPickObject(selected.ObjectID);
                                    }
                                }
                                setSelectedObject((selected as DisplayGameUnit).Data);
                            }
                            else if (selected is DisplayGameItem)
                            {
                                if (world.Client.Actor != null)
                                {
                                    world.Client.Actor.SendUnitPickObject(selected.ObjectID);
                                }
                                setSelectedObject((selected as DisplayGameItem).Data);
                            }
                            else if (selected is DisplayGameSpell)
                            {
                                setSelectedObject((selected as DisplayGameSpell).Data);
                            }
                            else
                            {
                                setSelectedObject(null);
                            }
                        }
                    }
                    else if (e.Button == MouseButtons.Right)
                    {
                        if (world.Client.Actor != null)
                        {
                            if (Keyboard.GetKeyState(Keys.A))
                            {
                                if (world.Client.Actor.IsGuard)
                                {
                                    world.Client.Actor.SendUnitAttackMoveTo(wx, wy, true);
                                }
                                else
                                {
                                    world.Client.Actor.AddAgent(new ActorMoveAgent(wx, wy, world.CellW / 10f));
                                }
                            }
                            else if (world.Client.Actor.IsGuard)
                            {
                                world.Client.Actor.SendUnitAttackMoveTo(wx, wy, false);
                            }
                            else
                            {
                                world.Client.Actor.SendUnitAxis(
                                    mouseX - world.Client.Actor.X,
                                    mouseY - world.Client.Actor.Y);
                            }
                        }

                    }
                }
            }
            catch (Exception err)
            {
                Console.WriteLine(err.Message);
            }
        }
        protected virtual void pictureBox1_MouseMove(object sender, MouseEventArgs e)
        {
            try
            {
                if (world != null)
                {
                    float wx = mouseX = world.screenToWorldX(e.X);
                    float wy = mouseY = world.screenToWorldY(e.Y);
                    if (world.Client.Actor == null || this.IsFreeView)
                    {
                        if (e.Button == System.Windows.Forms.MouseButtons.Right)
                        {
                            if (pic_lastMouesDown != null)
                            {
                                float x = pic_lastCameraPos.X + world.screenToWorldSizeX(pic_lastMouesDown.X - e.X);
                                float y = pic_lastCameraPos.Y + world.screenToWorldSizeY(pic_lastMouesDown.Y - e.Y);
                                world.setCamera(x, y);
                            }
                        }
                    }
                    if (world.Client.Actor != null)
                    {
                        if (Keyboard.IsShiftDown)
                        {
                            world.Client.Actor.SendUnitFaceTo(wx, wy);
                        }
                        if (e.Button == MouseButtons.Left)
                        {

                        }
                        else if (e.Button == MouseButtons.Right)
                        {
                            if (world.Client.Actor.IsGuard)
                            {
                                //world.Client.Actor.SendUnitMove(wx, wy);
                            }
                            else
                            {
                                world.Client.Actor.SendUnitAxis((float)Math.Atan2(
                                    mouseY - world.Client.Actor.Y,
                                    mouseX - world.Client.Actor.X));
                            }
                        }
                        pictureBox1_CheckPickItem();
                    }
                }
            }
            catch (Exception err)
            {
                Console.WriteLine(err.Message);
            }
        }
        protected virtual void pictureBox1_MouseUp(object sender, MouseEventArgs e)
        {
            try
            {
                pic_lastMouesDown = null;
                pic_lastCameraPos = null;

                if (world != null && world.Client.Actor != null)
                {
                    if (world.Client.Actor.IsGuard)
                    {

                    }
                    else
                    {
                        world.Client.Actor.SendUnitStopMove();
                    }
                }
            }
            catch (Exception err)
            {
                Console.WriteLine(err.Message);
            }
        }
        protected virtual void pictureBox1_MouseWheel(object sender, MouseEventArgs e)
        {
            if (world != null)
            {
                try
                {
                    int d = CMath.getDirect(e.Delta);
                    if (d > 0)
                    {
                        float newD = world.getCameraScale() * 1.1f;
                        world.setCameraScale(newD, newD);
                    }
                    else if (d < 0)
                    {
                        float newD = world.getCameraScale() / 1.1f;
                        world.setCameraScale(newD, newD);
                    }
                }
                catch (Exception err)
                {
                    Console.WriteLine(err.Message);
                }
            }
        }

        protected virtual void pictureBox1_KeyDown(object sender, KeyEventArgs e)
        {
            try
            {
                if (world != null)
                {
                    if (e.KeyCode == Keys.Space)
                    {
                        btn_Step_Click(btn_Step, e);
                    }
                    else
                    {
                        if (world.Client.Actor != null)
                        {
                            if (e.Shift)
                            {
                                world.ActorUseItem(e);
                            }
                            else
                            {
                                if (SelectedZoneObject != null)
                                {
                                    world.ActorLaunchSkill(e, SelectedZoneObject);
                                }
                                else
                                {
                                    world.ActorLaunchSkill(e, mouseX, mouseY);
                                }
                            }
                        }
                    }
                }
            }
            catch (Exception err)
            {
                Console.WriteLine(err.Message);
            }
        }

        protected virtual void pictureBox1_Paint(object sender, PaintEventArgs e)
        {
            if (world != null)
            {
                try
                {
                    long curTime = CUtils.CurrentTimeMS;
                    int intervalMS = (int)Math.Min(curTime - lastUpdateTimeMS, timer2.Interval);
                    lastUpdateTimeMS = curTime;

                    world.update(intervalMS, TurboX);
                    world.setWindow(new RectangleF(0, 0, pictureBox1.Width, pictureBox1.Height));
                    if (world.Layer.Actor != null)
                    {
                        world.setCamera(world.Layer.Actor.X, world.Layer.Actor.Y);
                    }
                    if (!chkNoRender.Checked)
                    {
                        world.render(e.Graphics);
                    }
                    pictureBox1_CheckPickItem();
                }
                catch (Exception err)
                {
                    timer2.Stop();
                    MessageBox.Show(err.Message + "\n" + err.StackTrace);
                }
            }
        }

        protected virtual ZoneItem pictureBox1_CheckPickItem()
        {
            if (world.Battle.Actor != null)
            {
                pictureBox1.Cursor = Cursors.Default;
                ZoneItem item = world.Battle.Layer.GetNearPickableItem(world.Battle.Actor);
                if (item != null)
                {
                    if (CMath.includeRoundPoint(item.X, item.Y, item.Info.BodySize, mouseX, mouseY))
                    {
                        pictureBox1.Cursor = Cursors.Hand;
                        return item;
                    }
                }
            }
            return null;
        }

        #endregion
        //------------------------------------------------------------------------------------
        #region MenuEvents

        protected virtual void btn_SkipClientEvent_Click(object sender, EventArgs e)
        {
            if (world != null)
            {
                world.SkipClientEvent();
            }
        }

        protected virtual void btn_Stop_Click(object sender, EventArgs e)
        {
            if (btn_Play.Checked)
            {

            }
        }

        protected virtual void btn_Step_Click(object sender, EventArgs e)
        {
            if (btn_Play.Checked)
            {
                btn_Play.Checked = false;
            }
            step1 = true;
        }

        protected virtual void btn_AutoAttack_Click(object sender, EventArgs e)
        {
            if (world != null && world.Client.Actor != null)
            {
                world.Client.Actor.SendUnitGuard(btn_AutoAttack.Checked);
            }
        }
        protected virtual void btn_IsAutoFocusTarget_ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (world.Layer.Actor != null)
            {
                world.Layer.Actor.IsSkillAutoFocusTarget = btn_IsAutoFocusTarget.Checked;
            }
        }


        protected virtual void btn_CleanBuff_Click(object sender, EventArgs e)
        {
            if (world.Layer.Actor != null)
            {
                using (var list = ListObjectPool<ZoneUnit.BuffState>.AllocAutoRelease())
                {
                    world.Layer.Actor.GetBuffStatus(list);
                    foreach (ZoneUnit.BuffState bs in list)
                    {
                        world.Layer.Actor.SendCancelBuff(bs.Data.ID);
                    }
                }
            }
        }

        protected virtual void pickUnitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (world != null && world.Client.Actor != null)
            {
                if (world.SelectedObject != null && world.SelectedObject is DisplayGameUnit)
                {
                    DisplayGameUnit su = world.SelectedObject as DisplayGameUnit;
                    world.Client.Actor.SendUnitPickObject(su.ObjectID);
                }
            }
        }

        protected virtual void item_SyncMode_Click(object sender, EventArgs e)
        {
            ToolStripButton item = sender as ToolStripButton;
            if (item != null)
            {
                world.Layer.ActorSyncMode = (SyncMode)item.Tag;
            }
            foreach (ToolStripButton btn in drop_SyncMode.DropDownItems)
            {
                btn.Checked = ((SyncMode)btn.Tag == world.Layer.ActorSyncMode);
            }
        }

        #endregion
        //------------------------------------------------------------------------------------
        #region QuestEmulate

        protected virtual void btn_QuestAccpetR2B_Click(object sender, EventArgs e)
        {
            if (world.Battle.Actor != null)
            {
                string quest = G2DTextDialog.Show("任务ID", "模拟【游戏服->】接取任务");
                if (quest != null)
                {
                    Zone.QuestAdapter.OnQuestAcceptedHandler(world.Battle.Actor.PlayerUUID, quest);
                }
            }
        }
        protected virtual void btn_QuestStatusChangeR2B_Click(object sender, EventArgs e)
        {
            if (world.Battle.Actor != null)
            {
                string quest = G2DTextDialog.Show("任务ID\r\nKey\r\nValue", "模拟【游戏服->】任务状态改变");
                if (quest != null)
                {
                    string[] kvs = quest.Split(new char[] { '\n' }, 3, StringSplitOptions.RemoveEmptyEntries);
                    if (kvs.Length >= 3)
                    {
                        Zone.QuestAdapter.OnQuestStatusChangedHandler(world.Battle.Actor.PlayerUUID, kvs[0], kvs[1], kvs[2]);
                    }
                }
            }
        }
        protected virtual void btn_QuestCommitR2B_Click(object sender, EventArgs e)
        {
            if (world.Battle.Actor != null)
            {
                string quest = G2DTextDialog.Show("任务ID", "模拟【游戏服->】提交任务");
                if (quest != null)
                {
                    Zone.QuestAdapter.OnQuestCommittedHandler(world.Battle.Actor.PlayerUUID, quest);
                }
            }
        }
        protected virtual void btn_QuestDropR2B_Click(object sender, EventArgs e)
        {
            if (world.Battle.Actor != null)
            {
                string quest = G2DTextDialog.Show("任务ID", "模拟【游戏服->】放弃任务");
                if (quest != null)
                {
                    Zone.QuestAdapter.OnQuestDroppedHandler(world.Battle.Actor.PlayerUUID, quest);
                }
            }
        }

        #endregion
        //------------------------------------------------------------------------------------
        #region Turbo

        private void btn_1X_Click(object sender, EventArgs e)
        {
            TurboX = 1;
        }
        private void btn_2X_Click(object sender, EventArgs e)
        {
            TurboX = 2;
        }
        private void btn_3X_Click(object sender, EventArgs e)
        {

            TurboX = 3;
        }
        private void btn_4X_Click(object sender, EventArgs e)
        {
            TurboX = 4;
        }
        private void btn_5X_Click(object sender, EventArgs e)
        {
            TurboX = 5;
        }
        private void btn_10X_Click(object sender, EventArgs e)
        {
            TurboX = 10;
        }
        private void btn_0_5X_Click(object sender, EventArgs e)
        {
            TurboX = 0.5f;
        }
        private void btn_0_1X_Click(object sender, EventArgs e)
        {
            TurboX = 0.1f;
        }

        private void gCToolStripMenuItem_Click(object sender, EventArgs e)
        {
            System.GC.Collect();
        }

        private void btn_TurboX_ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            string turbo = G2DTextDialog.Show(TurboX.ToString(), "设置加速倍率");
            float turbox = 1;
            if (turbo != null && float.TryParse(turbo, out turbox))
            {
                this.TurboX = turbox;
            }
        }

        #endregion


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




    }

}