using CommonAI.Zone;
using CommonAI.Zone.Helper;
using CommonAI.Zone.ZoneEditor;
using CommonAI.ZoneClient.Agent;
using CommonLang;
using CommonLang.Concurrent;
using CommonLang.Log;
using CommonLang.Property;
using CommonLang.Vector;
using pomelo.area;
using pomelo.chat;
using pomelo.connector;
using Pomelo.DotNetClient;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using XmdsBattleClient.Client;
using XmdsBattleClientBot.Bot;
using XmdsBattleClientBot.XmdsBot;

namespace XmdsBotTest.Runner
{
    public class BotRunner : IDisposable
    {
        protected readonly ListLogger events;
        protected readonly BotClient bot;
        protected readonly AddBotConfig add;
        protected readonly int index;
        protected XmdsNetClient client
        {
            get { return bot.Client; }
        }
        protected readonly AtomicReference<string> status = new AtomicReference<string>("");
        private HashMap<Type, RunnerModule> modules = new HashMap<Type, RunnerModule>();

        public BotClient Bot { get { return bot; } }
        public string RoleName { get { return bot.RoleName; } }
        public string SceneName { get { return bot.SceneName; } }
        public Pomelo.DotNetClient.NetWorkState NetState { get { return bot.NetState; } }
        public string Status { get { return status.Value; } }

        public BotRunner() {

        }

        public BotRunner(BotClient bot, int index, AddBotConfig add)
        {
            this.events = new ListLogger("event bot[" + bot.Account + "]");
            this.add = add;
            this.index = index;
            this.bot = bot;
            this.bot.event_OnStart += on_start;
            this.bot.event_OnStop += on_stop;
            this.bot.event_OnUpdate += on_update;
            this.bot.event_OnBattleUpdate += on_bs_update;
            this.bot.Client.GameSocket.IsSaveResponse = true;
            this.bot.Client.OnBeginEnterScene += on_gs_begin_enter_scene;
            this.bot.Client.OnBattlePlayerReady += on_bs_actor_ready;
            this.bot.Client.GameSocket.NetWorkStateChangedEvent += GameSocket_NetWorkStateChangedEvent;
            //this.bot.Client.LoginHandler.AddIpMapping(bot.Config.GetIpMapping());

            foreach (var mt in RunnerModule.GetSubTypes())
            {
                RunnerModule _module = ReflectionUtil.CreateInstance(mt, this) as RunnerModule;
                modules.Add(mt, _module);
            }
        }

        public void Start()
        {
            bot.Start();
        }
        public void Stop()
        {
            bot.Stop();
        }
        public void Dispose()
        {
            bot.Dispose();
            modules.Clear();
        }

        public override string ToString()
        {
            return bot.Account;
        }

        public void PopLogs(List<string> list)
        {
            events.PopLogs(list);
        }
        //--------------------------------------------------------------------------------------------------------

        private void test_entry(EntryRequest request, Action<PomeloException, EntryResponse> cb, object option)
        {
//             var _socket = client.GateSocket;
//             MemoryStream ms = new MemoryStream();
//             _socket.Serializer.Serialize(ms, request);
//             var req = new byte[ms.Length];
//             Array.Copy(ms.GetBuffer(), req, ms.Length);
//             var route = EventTypes.GetRequestKey(typeof(EntryRequest));
//             _socket.onRequestStart(route, option);
//             _socket.request_binary(route, req, (err, rsp) =>
//             {
//                 MemoryStream rs = new MemoryStream(rsp);
//                 var rsp_type = EventTypes.GetResponseType(route);
//                 var response = _socket.Serializer.Deserialize(rs, null, rsp_type);
//                 _socket.onRequestEnd(route, err, response, option);
//                 cb(err, response as EntryResponse);
//             });
        }

        private void GameSocket_NetWorkStateChangedEvent(NetWorkState obj)
        {
            //if (obj == NetWorkState.DISCONNECTED)
            //{
            //    new Thread(() =>
            //    {
            //        Thread.Sleep(5000);
            //        events.Info("waiting 5 sec reconnect...");
            //        //if (!bot.Client.GameSocket.IsConnected)
            //        {
            //            reconnect();
            //        }
            //    }).Start();
            //}
        }

        public void reconnect()
        {
            new Thread(() =>
            {
                bot.QueueTask(() =>
                {
                    bot.Stop();
                });
                int wait = bot.Random.Next(100, 3000);
                events.Info("waiting " + wait + "ms...");
                Thread.Sleep(wait);
                bot.QueueTask(() =>
                {
                    bot.connect(()=> {
                        on_start(bot);
                    });
                });
            }).Start();
        }
        public void connect()
        {
            if (bot.NetState != NetWorkState.CONNECTED) {
                status.Value = "重连中....";
                new Thread(() =>
                {
                    bot.QueueTask(() =>
                    {
                        bot.Stop();
                    });
                    bot.QueueTask(() =>
                    {
                        bot.connect(() =>
                        {
                            status.Value = "连接成功...";
                            on_start(bot);
                        });
                    });
                }).Start();
            } else
            {
                MessageBox.Show("该客户端已经连接,无需再连");
            }
        }

        /// <summary>
        /// 离开副本
        /// </summary>
        public void leaveScene()
        {
            bot.Client.GameSocket.fightLevelHandler.leaveDungeonRequest((err, res)=>{
                if(err != null)
                {
                    MessageBox.Show("该场景不是副本,无法离开");
                }
            });
        }

        //--------------------------------------------------------------------------------------------------------
        protected virtual void on_start(BotClient obj)
        {
            events.Info("Bot started");

            obj.login(start_enter_server, (err)=>
            {
                obj.register(start_enter_server, on_error);
            });
        }
        protected virtual void on_stop(BotClient obj)
        {
            events.Info("Bot stoped");
        }
        protected virtual void on_update(BotClient obj)
        {
            foreach (var m in modules.Values) { m.OnUpdate(); }
        }

        protected virtual void on_bs_update(CommonAI.ZoneClient.ZoneActor obj)
        {

        }

        protected virtual void on_error(Exception err)
        {
            events.Error(err.Message, err);
            //将错误信息显示到当前状态
            status.Value = err.Message;
        }
        public virtual void log_response(string info, Exception err, dynamic r)
        {
            if (err != null)
                events.Error(info + " : " + err.Message);
            else if (r != null)
                events.Log(info + " : " + r.s2c_code + " : " + r.s2c_msg);
        }
        
        public CommonAI.Data.XmdsUnitPro LastSelectUnitPro { get; private set; }

        protected virtual void start_enter_server()
        {
            bot.gate_EnterServer(on_gate_enter_server, (err) =>
            {
                events.Error(err.Message);
                if (err is PomeloException)
                {
                    var pe = err as PomeloException;
                    if (pe.Code == 500)
                    {
                        reconnect();
                        return;
                    }
                }
            });
        }

        protected virtual void start_re_enter_server()
        {
            events.Log("gate re enter server");
            bot.gate_ReEnterServer((e)=> 
            {
                if (e.s2c_players.Count > 0)
                {
                    events.Log("gate bind player");
                    bot.gate_BindPlayer(e.s2c_players[0].id, on_gate_bind_player, on_error);
                }
            },
            (err) =>
            {
                events.Error(err.Message);
                if (err is PomeloException)
                {
                    var pe = err as PomeloException;
                    if (pe.Code == 500)
                    {
                        reconnect();
                        return;
                    }
                }
            });
        }

        protected virtual void on_gate_enter_server(EntryResponse e)
        {
            events.Log("gate enter server done : player count = " + e.s2c_players.Count);
            bot.QueueTask((System.Action)(() =>
            {
                if (e.s2c_players.Count > 0)
                {
                    events.Log("gate bind player");
                    bot.gate_BindPlayer(e.s2c_players[0].id, this.on_gate_bind_player, this.on_error);
                }
                else
                {
					//this.LastSelectUnitPro = global::CommonAI.Data.XmdsUnitPro.None;
					this.LastSelectUnitPro = CUtils.RandomEnumValue<global::CommonAI.Data.XmdsUnitPro>(bot.Random);

                    if (LastSelectUnitPro == global::CommonAI.Data.XmdsUnitPro.None)
                    {
                        LastSelectUnitPro = global::CommonAI.Data.XmdsUnitPro.Sword;
                    }
                    string name = CUtils.GetRandomInArray(add.RoleNameFormat, bot.Random);
                    if (add.RandomRoleName || name == null)
                    {
                        events.Log("gate get random name");
                        bot.gate_GetRandomName((int)LastSelectUnitPro, this.on_gate_get_random_name, this.on_error);
                    }
                    else
                    {
                        if (name.Contains("{0}"))
                            name = string.Format(name, index.ToString(add.digit_format));
                        events.Log("gate create role : " + name);
                        bot.gate_CreateRole((int)LastSelectUnitPro, name, this.on_gate_create_role, (err) =>
                        {
                            on_error(err);
                            events.Log("gate get random name");
                            bot.gate_GetRandomName((int)LastSelectUnitPro, this.on_gate_get_random_name, this.on_error);
                        });
                    }
                }
            }));
        }
        protected virtual void on_gate_get_random_name(GetRandomNameResponse e)
        {
            events.Log("gate get random name done");
            bot.QueueTask(() =>
            {
                if (string.IsNullOrEmpty(e.s2c_name))
                {
                    events.Log("gate get random name");
                    bot.gate_GetRandomName((int)LastSelectUnitPro, on_gate_get_random_name, on_error);
                }
                else
                {
                    events.Log("gate create role : " + e.s2c_name);
                    bot.gate_CreateRole((int)LastSelectUnitPro, e.s2c_name, on_gate_create_role, (err) =>
                    {
                        on_error(err);
                        events.Log("gate get random name");
                        bot.gate_GetRandomName((int)LastSelectUnitPro, on_gate_get_random_name, on_error);
                    });
                }
            });
        }
        protected virtual void on_gate_create_role(CreatePlayerResponse e)
        {
            events.Log("gate create role done : " + e.s2c_player.name);
            bot.QueueTask(() =>
            {
                events.Log("gate bind player : " + e.s2c_player.name);
                bot.gate_BindPlayer(e.s2c_player.id, on_gate_bind_player, on_error);
            });
        }
        protected virtual void on_gate_bind_player(BindPlayerResponse e)
        {
            events.Log("gate bind player done : " + e.s2c_player.name);
            foreach (var m in modules.Values) { m.OnGateBindPlayer(e); }
        }
        //--------------------------------------------------------------------------------------------------------

        protected virtual void on_gs_begin_enter_scene(XmdsBattleClient.Battle.XmdsBattleClient obj)
        {
            this.CurrentMoveAgent = null;
            this.CurrentRandomMoveTarget = null;
            events.Log("gs begin enter scene done");
            if (bot.Client.BattleClient != null)
            {
                bot.Client.BattleClient.Layer.ActorAdded += on_bs_actor_added;
            }
            bot.gs_EnterScene(on_gs_enter_scene, on_error);
        }
        protected virtual void on_gs_enter_scene(EnterSceneResponse response)
        {
            events.Log("bs enter scene done : " + response.s2c_instanceId);
            bot.LineIndex = response.s2c_areaIndex;
            bot.SendUnitGuard(true);
            foreach (var m in modules.Values) { m.OnGameEnterScene(response); }
        }
        private void on_bs_actor_ready(CommonAI.ZoneClient.ZoneLayer layer, CommonAI.ZoneClient.ZoneActor actor)
        {
            foreach (var m in modules.Values)
            {
                m.OnBattleActorReady(layer, actor);
            }
        }
        private void on_bs_actor_added(CommonAI.ZoneClient.ZoneLayer layer, CommonAI.ZoneClient.ZoneActor actor)
        {
            actor.OnDoEvent += on_bs_actor_do_event;
            layer.AddTimePeriodicMS(5000, (t) =>
            {
                check_move();
            });
        }
        private void on_bs_actor_do_event(CommonAI.ZoneClient.ZoneObject obj, CommonAI.Zone.ObjectEvent e)
        {
            if (e is UnitDeadEvent)
            {
                if (e.object_id == bot.CurrentZoneActor.ObjectID)
                {
                    on_actor_dead(bot.CurrentZoneActor, e as UnitDeadEvent);
                }
            }
        }
        private void on_actor_dead(CommonAI.ZoneClient.ZoneActor actor, UnitDeadEvent e)
        {
            do_relive(2);
            foreach (var m in modules.Values) { m.OnBattleActorDead(actor, e); }
        }
        //--------------------------------------------------------------------------------------------------------
        public virtual void do_relive(int type)
        {
            bot.Client.GameSocket.playerHandler.reliveRequest(type, (e, r) =>
            {
                log_response("reliveRequest done : ", e, r);
            });
        }
        //--------------------------------------------------------------------------------------------------------
        #region GM
        
        private void sendCMD(string cmd, Action<PomeloException, SendChatResponse> cb)
        {
            //bot.Client.GameSocket.chatHandler.sendChatRequest(1, cmd, "", "", cb);
        }

        public virtual void do_gm_add_exp(int exp)
        {
            sendCMD("@gm add exp " + exp, (e, r) =>
            {
                log_response("do_gm_add_exp done : ", e, r);
            });
        }

        public virtual void do_gm_add_upexp(int exp)
        {
            sendCMD("@gm add upexp " + exp, (e, r) =>
            {
                log_response("do_gm_add_upexp done : ", e, r);
            });
        }

        public virtual void do_gm_add_diamond(int exp)
        {
            sendCMD("@gm add diamond " + exp, (e, r) =>
            {
                log_response("do_gm_add_diamond done : ", e, r);
            });
        }
        public virtual void do_gm_add_gold(int exp)
        {
            sendCMD("@gm add gold " + exp, (e, r) =>
            {
                log_response("do_gm_add_gold done : ", e, r);
            });
        }
        public virtual void do_gm_finish_task(int taskTemplateID)
        {
            sendCMD("@gm finishTask " + taskTemplateID, (e, r) =>
            {
                log_response("do_gm_finish_task done : ", e, r);
            });
        }

        public virtual void do_gm_unlock_bag(int num)
        {
            sendCMD("@gm unlock " + num, (e, r) =>
            {
                log_response("do_gm_unlock_bag done : ", e, r);
            });
        }

        /************************************************************************/
        /* 模拟充值成功回调                                                                     */
        /************************************************************************/
        public virtual void do_gm_pay_success(String orderId)
        {
            sendCMD("@gm paySuccess " + orderId, (e, r) =>
            {
                log_response("do_gm_pay_success done : ", e, r);
            });
        }

        public virtual void do_gm_open_func()
        {
            sendCMD("@gm openFunc", (e, r) =>
            {
                log_response("do_gm_open_func done : ", e, r);
            });
        }

        public virtual void do_gm_add_skin() {
            sendCMD("@gm allSkin",(e,r) => {
                log_response("do_gm_add_skin done : ", e, r);
            });
        }

        public virtual void do_gm_add_item(string code, int num)
        {
            sendCMD("@gm add " + code + " " + num, (e, r) =>
            {
                log_response("do_gm_add_item done : ", e, r);
            });
        }

        public virtual void do_gm_add_item()
        {
            //sendCMD("@gm add lclot1-test 1", (e, r) =>
            //{
            //    log_response("do_gm_add_item done : ", e, r);
            //});

            //sendCMD("@gm add lweap1-test 1", (e, r) =>
            //{
            //    log_response("do_gm_add_item done : ", e, r);
            //});
        }
        #endregion
        //--------------------------------------------------------------------------------------------------------
        #region Task
        public virtual BotClient.QuestData do_seek_task(int questID, BotClient.QuestData.SeekAction action)
        {
            var quest = bot.CurrentQuestManager.GetQuest(questID);
            if (quest != null)
            {
                events.Log("do_seek_task : " + quest);
                quest.Seek(action);
            }
            return quest;
        }
        public virtual BotClient.QuestData do_seek_expect_task(BotClient.QuestData.QuestStatus expect, BotClient.QuestData.SeekAction action, bool random = false)
        {
            BotClient.QuestData q = null;
            if ((q = bot.CurrentQuestManager.SeekExpectTask(BotClient.QuestData.QuestType.TRUNK, expect, action, random)) != null)
            {
                events.Log("do_seek_expect_task : " + q);
                return q;
            }
            if ((q = bot.CurrentQuestManager.SeekExpectTask(BotClient.QuestData.QuestType.INVALID, expect, action, random)) != null)
            {
                events.Log("do_seek_expect_task : " + q);
                return q;
            }
            return q;
        }
        public virtual BotClient.QuestData do_seek_random_task(BotClient.QuestData.SeekAction action, bool random = false)
        {
            BotClient.QuestData q = null;
            if ((q = bot.CurrentQuestManager.SeekExpectTask(BotClient.QuestData.QuestType.TRUNK, BotClient.QuestData.QuestStatus.CAN_FINISH, action, random)) != null)
            {
                events.Log("do_seek_random_task : " + q);
                return q;
            }
            if ((q = bot.CurrentQuestManager.SeekExpectTask(BotClient.QuestData.QuestType.TRUNK, BotClient.QuestData.QuestStatus.IN_PROGRESS, action, random)) != null)
            {
                events.Log("do_seek_random_task : " + q);
                return q;
            }
            if ((q = bot.CurrentQuestManager.SeekExpectTask(BotClient.QuestData.QuestType.TRUNK, BotClient.QuestData.QuestStatus.NEW, action, random)) != null)
            {
                events.Log("do_seek_random_task : " + q);
                return q;
            }
            if ((q = bot.CurrentQuestManager.SeekExpectTask(BotClient.QuestData.QuestType.INVALID, BotClient.QuestData.QuestStatus.CAN_FINISH, action, random)) != null)
            {
                events.Log("do_seek_random_task : " + q);
                return q;
            }
            if ((q = bot.CurrentQuestManager.SeekExpectTask(BotClient.QuestData.QuestType.INVALID, BotClient.QuestData.QuestStatus.IN_PROGRESS, action, random)) != null)
            {
                events.Log("do_seek_random_task : " + q);
                return q;
            }
            if ((q = bot.CurrentQuestManager.SeekExpectTask(BotClient.QuestData.QuestType.INVALID, BotClient.QuestData.QuestStatus.NEW, action, random)) != null)
            {
                events.Log("do_seek_random_task : " + q);
                return q;
            }
            return q;
        }
        public virtual void do_update_quest_status(BotClient.QuestData quest)
        {
            events.Log("do_update_quest_status : " + quest + " : " + quest.State);
            bot.Client.GameSocket.taskHandler.updateTaskStatusRequest(quest.TemplateID, (int)quest.Kind, (err, msg) =>
            {
                if (err != null)
                    events.Error("updateTaskStatusRequest error : " + err.Message);
                else
                    events.Log("updateTaskStatusRequest done : " + msg.s2c_code + " : " + msg.s2c_msg);
            });
        }
        public virtual void do_accept_quest(BotClient.QuestData quest, Action<Exception> error = null)
        {
            if (client.BattleActor != null)
            {
                events.Log("do_accept_quest : " + quest + " : " + quest.State);
                client.GameSocket.taskHandler.acceptTaskRequest(quest.TemplateID, (int)quest.Kind, client.BattleActor.ObjectID.ToString(), (err, msg) =>
                {
                    if (err != null)
                    {
                        events.Error("acceptTaskRequest error : " + err.Message);
                        if (error != null) error(err);
                    }
                    else
                    {
                        events.Log("acceptTaskRequest done : " + msg.s2c_code + " : " + msg.s2c_msg);
                    }
                });
            }
        }
        public virtual void do_submit_task(BotClient.QuestData quest, Action<Exception> error = null)
        {
            if (client.BattleActor != null)
            {
                events.Log("do_submit_task : " + quest + " : " + quest.State);
                client.GameSocket.taskHandler.submitTaskRequest(quest.TemplateID, (int)quest.Kind, 0, client.BattleActor.ObjectID.ToString(), (err, msg) =>
                {
                    if (err != null)
                    {
                        events.Error("submitTaskRequest error : " + err.Message);
                        if (error != null) error(err);
                    }
                    else
                    {
                        events.Log("submitTaskRequest done : " + msg.s2c_code + " : " + msg.s2c_msg);
                    }
                });
            }
        }
        #endregion
        //--------------------------------------------------------------------------------------------------------
        #region Move

        public ActorMoveAgent CurrentMoveAgent { get; private set; }
        public SceneObjectData CurrentRandomMoveTarget { get; private set; }

        private Vector2 mLastPos = new Vector2();
        private void check_move()
        {
            float min_step = client.DataRoot.Templates.CFG.OBJECT_MOVE_TO_MIN_STEP_SEC;
            bool not_move = MathVector.getDistance(mLastPos.X, mLastPos.Y, bot.CurrentZoneActor.X, bot.CurrentZoneActor.Y) < min_step;
            mLastPos.SetX(bot.CurrentZoneActor.X);
            mLastPos.SetY(bot.CurrentZoneActor.Y);
            if (not_move)
            {
                CurrentRandomMoveTarget = null;
                if (CurrentMoveAgent != null)
                    CurrentMoveAgent.Stop();
                CurrentMoveAgent = null;
            }
        }


        private SceneObjectData do_bs_actor_random_move_regions<R>(List<R> list, bool attack, float min_distance) where R : SceneObjectData
        {
            var player = bot.CurrentZoneActor;
            var layer = bot.CurrentZoneLayer;
            if (player != null && layer.IsLoaded)
            {
                try
                {
                    bot.SendUnitGuard(attack);
                    if (CurrentRandomMoveTarget == null ||
                        MathVector.getDistance(player.X, player.Y, CurrentRandomMoveTarget.X, CurrentRandomMoveTarget.Y) <= min_distance ||
                        layer.FindPath(player.X, player.Y, CurrentRandomMoveTarget.X, CurrentRandomMoveTarget.Y) == null)
                    {
                        CUtils.RandomList<R>(bot.Random, list);
                        foreach (var rg in list)
                        {
                            if (player.Parent.FindPath(player.X, player.Y, rg.X, rg.Y) != null)
                            {
                                events.Log("do_bs_actor_random_move_region : " + rg.Name);
                                if (!attack)
                                {
                                    do_start_move_agent(rg.X, rg.Y, min_distance);
                                }
                                else
                                {
                                    player.SendUnitAttackMoveTo(rg.X, rg.Y, attack);
                                }
                                CurrentRandomMoveTarget = rg;
                                return rg;
                            }
                        }
                    }
                    else if (bot.CurrentZoneActor.CurrentState == UnitActionStatus.Idle)
                    {
                        if (!attack)
                        {
                            do_start_move_agent(CurrentRandomMoveTarget.X, CurrentRandomMoveTarget.Y, min_distance);
                        }
                        else
                        {
                            player.SendUnitAttackMoveTo(CurrentRandomMoveTarget.X, CurrentRandomMoveTarget.Y, attack);
                        }
                        return CurrentRandomMoveTarget;
                    }
                }
                catch (Exception err)
                {
                    events.Error(err.Message, err);
                }
            }
            return null;
        }
        public virtual SceneObjectData do_bs_actor_random_move_region(bool attack = true, float min_distance = 0.1f)
        {
            return do_bs_actor_random_move_regions<RegionData>(bot.CurrentRegionManager.AllRegions(), attack, min_distance);
        }
        public virtual SceneObjectData do_bs_actor_random_move_transport(bool attack = true, float min_distance = 0.1f)
        {
            return do_bs_actor_random_move_regions<SceneObjectData>(bot.CurrentRegionManager.AllTransports(), attack, min_distance);
        }

        public virtual ActorMoveAgent do_start_move_agent(float x, float y, float distance, bool force_trans = false)
        {
            if (CurrentMoveAgent != null)
            {
                CurrentMoveAgent.Stop();
            }
            CurrentMoveAgent = new ActorMoveAgent(x, y, distance);
            bot.CurrentZoneActor.AddAgent(CurrentMoveAgent);
            bot.SendUnitGuard(false);
            if (CurrentMoveAgent.Result == CommonAI.RTS.Manhattan.AstarManhattan.FindPathResult.Destination)
            {
                bot.CurrentRegionManager.CheckTrans(1, force_trans);
            }
            else if (CurrentMoveAgent.IsEnd)
            {
                bot.CurrentZoneActor.SendUnitAttackMoveTo(x, y, false);
            }
            return CurrentMoveAgent;
        }

        #endregion
        //--------------------------------------------------------------------------------------------------------
        #region Pick

        public virtual CommonAI.ZoneClient.ZoneItem do_try_pick_nearest_item(out Vector2 move_to)
        {
            move_to = null;
            if (bot.CurrentZoneActor.CurrentState != UnitActionStatus.Pick)
            {
                var item = bot.CurrentZoneLayer.GetNearPickableItem(bot.CurrentZoneActor);
                if (item != null)
                {
                    events.Log("try pick nearest item : " + item.Info.Name);
                    if (MathVector.getDistance(bot.CurrentZoneActor.X, bot.CurrentZoneActor.Y, item.X, item.Y) < item.RadiusSize)
                    {
                        bot.CurrentZoneActor.SendUnitPickObject(item.ObjectID);
                        return item;
                    }
                    else
                    {
                        move_to = new Vector2(item.X, item.Y);
                    }
                }
            }
            return null;
        }
        public virtual CommonAI.ZoneClient.ZoneItem do_start_pick_any_item()
        {
            if (bot.CurrentZoneActor.CurrentState != UnitActionStatus.Pick)
            {
                var item = bot.CurrentZoneLayer.GetNearPickableItem(bot.CurrentZoneActor);
                if (item != null)
                {
                    events.Log("do pick item : " + item.Info.Name);
                    bot.CurrentZoneActor.SendUnitPickObject(item.ObjectID);
                    return item;
                }
            }
            return null;
        }

        #endregion

        #region BagAndEquip

        #endregion
        //--------------------------------------------------------------------------------------------------------
        public abstract class RunnerModule
        {
            public string module_name = "模块名";

            private static HashMap<Type, bool> s_SubModules = new HashMap<Type, bool>();
            public static List<Type> GetSubTypes()
            {
                var ret = new List<Type>();
                foreach (var mt in typeof(RunnerModule).Assembly.GetTypes())
                {
                    if (mt.IsSubclassOf(typeof(RunnerModule)) && !mt.IsAbstract)
                    {
                        ret.Add(mt);
                    }
                }
                return ret;
            }

            /// <summary>
            /// 获取类中的属性值
            /// </summary>
            /// <param name="FieldName"></param>
            /// <param name="obj"></param>
            /// <returns></returns>
            public string GetModelValue(string FieldName, object obj)
            {
                try
                {
                    Type Ts = obj.GetType();
                    object o = Ts.GetProperty(FieldName).GetValue(obj, null);
                    string Value = Convert.ToString(o);
                    if (string.IsNullOrEmpty(Value)) return null;
                    return Value;
                }
                catch
                {
                    return null;
                }
            }

            public static void SetModuleEnable(Type type, bool value)
            {
                s_SubModules[type] = value;
            }
            public static bool GetModuleEnable(Type type)
            {
                bool enable = false;
                if (s_SubModules.TryGetValue(type, out enable))
                {
                    return enable;
                }
                return false;
            }
            static RunnerModule()
            {
                foreach (var mt in GetSubTypes())
                {
                    s_SubModules.Add(mt, true);
                }
            }

            private bool m_Enable;
            protected BotClient bot { get; private set; }
            protected BotRunner runner { get; private set; }
            protected XmdsNetClient client { get; private set; }
            protected Logger log { get; private set; }
            public bool Enable { get { return m_Enable; } }

            public void autoJoinTeam()
            {
                if(IsCanJoin)
                {
                    autoJoinTeamRequest();
                }
            }

            public virtual void autoJoinTeamRequest()
            {

            }
            protected virtual int rand()
            {
                return 20;
            }
            public bool IsCanJoin
            {
                get { return Enable && bot.IsFree && (runner.CurrentMoveAgent == null) && bot.Random.Next(100) < rand(); }
            }
            public RunnerModule() {

            }

            public RunnerModule(BotRunner r)
            {
                this.runner = r;
                this.bot = r.Bot;
                this.client = bot.Client;
                this.log = r.events;
                this.m_Enable = GetModuleEnable(GetType());
            }

            public void SetStatus(string st)
            {
                runner.status.Value = st;
            }

            internal void OnUpdate()
            {
                bool enable = GetModuleEnable(GetType());
                if (m_Enable != enable)
                {
                    m_Enable = enable;
                    OnEnableChanged(enable);
                }
            }

            protected virtual void OnEnableChanged(bool enable) { }

            protected internal virtual void OnGateBindPlayer(BindPlayerResponse e) { }
            protected internal virtual void OnGameEnterScene(EnterSceneResponse response) { }
            protected internal virtual void OnBattleActorReady(CommonAI.ZoneClient.ZoneLayer layer, CommonAI.ZoneClient.ZoneActor actor) { }
            protected internal virtual void OnBattleActorDead(CommonAI.ZoneClient.ZoneActor actor, UnitDeadEvent e) { }

        }
    }

}