using CommonAI;
using CommonAI.Zone;
using CommonAI.Zone.Instance;
using CommonAI.Zone.ZoneEditor;
using CommonAIClient.Client;
using CommonLang;
using CommonLang.Concurrent;
using CommonLang.Log;
using CommonLang.Protocol;
using CommonServer.Server;
using RoomService.Net.BsServer;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using XmdsCommon.Plugin;
using XmdsServerNode.Node;
using XmdsServerNode.Node.Interface;

namespace XmdsServerTest.Server
{
    public class NodeTestServer
    {
        private static Logger log = LoggerFactory.GetLogger("TestNodeServer");

        public static NodeTestServer Instance { get; private set; }
        public string ClientConnectString { get { return busAcceptor.ClientConnectString; } }

        public IServer B2CAcceptor { get { return busAcceptor; } }

        public readonly Random random = new Random();

        private List<UnitInfo> test_player_templates = new List<UnitInfo>();

        private IServerFactory factory;
        private IServer busAcceptor = null;
        private B2CServerListener serverListener;

        private AtomicInteger channel_id_gen = new AtomicInteger(0);
        private ZoneNodeManager node_manager = new ZoneNodeManager();
        private HashMap<string, ServerZoneNode> nodes = new HashMap<string, ServerZoneNode>();

        public DirectoryInfo StartupPath { get; private set; }
        public string Status { get; private set; }
        public bool Running { get; private set; }

        public NodeTestServer(DirectoryInfo startup_path)
        {
            Instance = this;
            this.StartupPath = startup_path;
            this.Running = false;
            this.Status = "New";
            this.factory = new CommonServer.SSocket.SuperSocket.ServerFactory();
        }

        public void Start(string host, int port)
        {
            try
            {
                this.serverListener = new B2CServerListener();
                this.Status = "Launching";
                // 初始化节点管理器 //
                {
                    node_manager.Init(StartupPath.FullName, serverListener);
                }
                // 创建战斗场景 //
                {
                    foreach (int scene_id in ZoneNodeManager.Templates.ListScenes())
                    {
                        ZoneNodeManager.Templates.LoadScene(scene_id);
                    }
                }
                // 扫描玩家模板 //
                {
                    foreach (UnitInfo unit in ZoneNodeManager.Templates.Templates.getAllUnits())
                    {
                        XmdsUnitProperties zu = unit.Properties as XmdsUnitProperties;
                        if (zu.BotTestTemplate || unit.UType == UnitInfo.UnitType.TYPE_PLAYER)
                        {
                            test_player_templates.Add(unit);
                        }
                    }
                }
                // 创建网络 //
                {
                    this.busAcceptor = factory.CreateServer(new BattleCodec(ZoneNodeManager.Templates.Templates));
                    CommonLang.Properties game_server_cfg = new CommonLang.Properties();
                    game_server_cfg["SuperSocket.HOST"] = host;
                    game_server_cfg["SuperSocket.PORT"] = port.ToString();
                    game_server_cfg["SuperSocket.CLIENT_CONNECT_STRING"] = host + ":" + port;
                    this.busAcceptor.Open(game_server_cfg, serverListener);
                }

                this.Status = "Running";
                this.Running = true;
            }
            catch (Exception err)
            {
                this.Status = err.Message;
                Console.WriteLine(err.Message);
                Console.WriteLine(err.StackTrace);
            }
        }

        public void Shutdown()
        {
            try
            {
                this.busAcceptor.Dispose();
                this.node_manager.Shutdown();
                this.Status = "Closed";
                this.Running = false;
            }
            catch (Exception err)
            {
                Console.WriteLine(err.Message);
                Console.WriteLine(err.StackTrace);
            }
        }

        public int ZoneNodesCount { get { return nodes.Count; } }


        public List<UnitInfo> ListTestPlayerTemplates()
        {
            return new List<UnitInfo>(test_player_templates);
        }
        public List<ServerZoneNode> ListZoneNodes()
        {
            return new List<ServerZoneNode>(nodes.Values);
        }
        public ServerZoneNode GetZoneNodeByRoomID(string roomID)
        {
            return nodes.Get(roomID);
        }

        public ServerZoneNode AddTestScene(int sceneID)
        {
            if (ZoneNodeManager.Templates.ExistSceneInCache(sceneID))
            {
                ServerZoneNode node = new ServerZoneNode("");
                node.PauseOnNoPlayer = false;
                var uuid = channel_id_gen.IncrementAndGet().ToString();
                node.Start(uuid, sceneID, "", 1, true, 0,0,0, 0, 0, 0,
                    true, CommonAI.Data.SceneType.Normal, null, CommonAI.XmdsConstConfig.AreaType.None);
                nodes.Add(uuid, node);
                return node;
            }
            else
            {
                throw new Exception(string.Format("场景{0}不存在", sceneID));
            }
        }
    }

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

    public class B2CServerListener : IServerListener, IServerProxy
    {
        public B2CServerListener()
        {
        }
        //-------------------------------------------------------------------------------------------------
        #region IServerListener

        public void OnInit(IServer server)
        {
        }
        public void OnDestory()
        {
        }
        public ISessionListener OnSessionConnected(ISession session)
        {
            return new AppSessionPlayer(session);
        }

        #endregion
        //-------------------------------------------------------------------------------------------------
        #region IServerProxy

        public void SendToGameServer(string playerUUID, string eventType, object msg)
        {
        }

        public void SendToBattleServer(InstanceZone zone, XmdsServerNode.Node.R2bNotify.R2BNotifyMessage msg)
        {
            msg.OnHandle(zone);
        }

		public void SendMsgToPlayer(string playerUUID, IMessage msg)
		{
			throw new NotImplementedException();
		}

		#endregion

	}

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

    public class AppSessionPlayer : ISessionListener, IPlayer
    {
        private static Logger log = LoggerFactory.GetLogger("AppSessionPlayer");

        private static AtomicInteger s_alloc_object_count = new AtomicInteger(0);
        /// <summary>
        /// 分配实例数量
        /// </summary>
        public static int AllocCount { get { return s_alloc_object_count.Value; } }

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

        private readonly ISession session;

        private ServerZoneNode node;
        private string player_uuid;
        private string display_name;
        private int unit_template_id;

        private EnterRoomRequestC2B login_data;

        private HashMap<string, object> mAttributes = new HashMap<string, object>();
        private ZoneNodeCodec codec = new ZoneNodeCodec(ZoneNodeManager.MessageFactory);

        public AppSessionPlayer(ISession session)
        {
            s_alloc_object_count++;
            this.session = session;
        }
        ~AppSessionPlayer()
        {
            s_alloc_object_count--;
        }

        public void Dispose()
        {

        }

        //----------------------------------------------------------------------------
        #region IPlayer

        public string PlayerUUID { get { return player_uuid; } }
        public string DisplayName { get { return display_name; } }
        public ServerZoneNode.ZoneNodePlayer BindingObject { get; set; }

        public bool IsAttribute(string key)
        {
            return mAttributes.ContainsKey(key);
        }
        public void SetAttribute(string key, object value)
        {
            mAttributes.Put(key, value);
        }
        public object GetAttribute(string key)
        {
            return mAttributes.Get(key);
        }

        public void SendToClient(ArraySegment<byte> data)
        {
            IMessage e;
            if (codec.doDecode(data.Array, out e))
            {
                session.Send(e);
            }
        }
        public void SendToGameServer(object msg)
        {

        }
        public void onPickUnit(InstanceUnit obj, InstanceUnit pickable)
        {

        }
        #endregion
        //----------------------------------------------------------------------------

        public void ForceExit()
        {
            if (node != null)
            {
                this.login_data = null;
                node.OnPlayerLeave(this.BindingObject.BindingActor, (c) => { }, (e) => { }, false);
                session.Disconnect(true);
                node = null;
            }
        }

        //----------------------------------------------------------------------------
        #region ISessionListener

        public void OnConnected(ISession session)
        {
        }
        public void OnDisconnected(ISession session, bool force, string reason)
        {
            if (node != null)
            {
                this.login_data = null;
                node.OnPlayerLeave(this.BindingObject.BindingActor, (c) => { }, (e) => { }, true);
                node = null;
            }
        }
        public void OnError(ISession session, Exception err)
        {
        }
        public void OnSentMessage(ISession session, object message)
        {
        }

        public void OnReceivedMessage(ISession session, object message)
        {
            try
            {
                if (message is EnterRoomRequestC2B)
                {
                    do_EnterRoomResponseB2C(message as EnterRoomRequestC2B);
                }
                else if (message is LeaveRoomRequestC2B)
                {
                    do_LeaveRoomRequestC2B(message as LeaveRoomRequestC2B);
                }
                else
                {
                    do_RecivedMessage(message);
                }
            }
            catch (Exception err)
            {
                log.Error(err.Message, err);
            }
        }

        private void do_EnterRoomResponseB2C(EnterRoomRequestC2B req)
        {
            if (node == null)
            {
                this.node = NodeTestServer.Instance.GetZoneNodeByRoomID(req.RoomID);
                if (node == null)
                {
                    node = CUtils.GetRandomInArray(NodeTestServer.Instance.ListZoneNodes(), NodeTestServer.Instance.random);
                    if (node != null)
                    {
                        req.RoomID = node.UUID;
                    }
                }
                if (node != null)
                {
                    this.login_data = req;
                    this.player_uuid = req.PlayerUUID;
                    this.display_name = req.TestToken.PlayerDisplayName;
                    this.unit_template_id = req.TestToken.Data.UnitTemplateID;
                    var regions = node.Zone.Data.GetStartRegions();
                    var rg = regions.Get(req.TestToken.Data.Force);
                    if (rg == null)
                    {
                        rg = CUtils.GetRandomInArray(node.Zone.Data.GetStartRegionsList(), NodeTestServer.Instance.random);
                        if (rg != null)
                        {
                            var force = (byte)rg.GetAbilityOf<PlayerStartAbilityData>().START_Force;
                            req.TestToken.Data.Force = force;
                        }
                    }
                    PlayerEnterRoomS2R enter = new PlayerEnterRoomS2R();
                    enter.UnitData = req.TestToken.Data;
                    node.OnPlayerEnter(this, enter, (c) => { }, (e) => { });
                }
            }
        }

        private void do_LeaveRoomRequestC2B(LeaveRoomRequestC2B req)
        {
            if (node != null)
            {
                this.login_data = null;
                node.OnPlayerLeave(this.BindingObject.BindingActor, (c) => { }, (e) => { }, false);
                session.Disconnect(true);
                node = null;
            }
        }

        private void do_RecivedMessage(object message)
        {
            if (node != null)
            {
                ArraySegment<byte> data;
                if (codec.doEncode(message as IMessage, out data))
                {
                    node.OnPlayerReceivedMessage(this, data.Array);
                }
            }
        }

        #endregion

    }

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


}