using System;
using System.Collections.Generic;
using System.Text;
using CommonNetwork.Sockets;
using CommonLang.Protocol;
using RoomService.Net.BsServer;
using CommonLang.Log;
using RoomService.Net.BsClient;
using CommonAI.ZoneClient;
using CommonAI.Zone;
using CommonLang.IO;
using CommonAI.Zone.ZoneEditor;
using CommonAI.ZoneServer;
using CommonLang.Concurrent;
using CommonNetwork.Net;
using CommonLang.Property;
using CommonLang;
using CommonAI.Zone.Helper;

namespace CommonAIClient.Client
{
    public abstract class BattleClient : AbstractBattle
    {
        private static Logger log = LoggerFactory.GetLogger("BattleClient");
        protected readonly PlayerWillConnectResponseB2R room;
        protected readonly PlayerWillConnectRequestR2B testToken;
        private KickedByServerNotifyB2C kicked;
        private Ping send_ping = new Ping();
        private TimeInterval<int> ping_task = new TimeInterval<int>(2000);
        //private int current_ping = 0;
        public string token { get; private set; }
        public string data_root { get; private set; }
        public abstract INetSession Session { get; }
        public string PlayerUUID { get { return room.PlayerUUID; } }
        public MessageFactoryGenerator MessageFactory { get; private set; }
        public override long RecvPackages { get { return Session.TotalRecvPackages; } }
        public override long SendPackages { get { return Session.TotalSentPackages; } }
        public override int CurrentPing { get { return this.Layer.CurrentPing; } }
        public int PingIntervalMS
        {
            get
            {
                return ping_task.IntervalTimeMS;
            }
            set
            {
                ping_task = new TimeInterval<int>(Math.Max(1000, value));
            }
        }
        public override KickedByServerNotifyB2C KickMessage
        {
            get { return kicked; }
        }
        public override bool IsNet { get { return true; } }

        public BattleClient(
            EditorTemplates datas,
            MessageFactoryGenerator msgFactory,
            PlayerWillConnectResponseB2R room,
            PlayerWillConnectRequestR2B testToken,
            string token)
            : base(datas)
        {
            this.room = room;
            this.testToken = testToken;
            this.token = token;
            this.MessageFactory = msgFactory;
            this.Layer.ActorSyncMode = SyncMode.MoveByClient_PreSkillByClient;
        }


        protected override void Disposing()
        {
            base.Disposing();
            this.mHandleMessage = null;
            this.mDisconnectd = null;
            this.mConnected = null;
            this.mHandleError = null;
        }
        //----------------------------------------------------------------------------------------------------
        abstract public void Start();

        abstract public void Stop();
        //----------------------------------------------------------------------------------------------------

        /// <summary>
        /// 发送单位控制命令
        /// </summary>
        /// <param name="action"></param>
        public override void SendAction(CommonAI.Zone.Action action)
        {
            Session.Send(action);
        }
        /// <summary>
        /// 请求离开房间
        /// </summary>
        public void SendLeaveRoom()
        {
            LeaveRoomRequestC2B req = new LeaveRoomRequestC2B();
            Session.Send(req);
        }
        /// <summary>
        /// 发送聊天
        /// </summary>
        public void SendChatMessage(string message, ChatMessageType type = ChatMessageType.PlayerToForce)
        {
            ChatAction req = new ChatAction();
            req.Message = message;
            req.To = type;
            Session.Send(req);
        }

        //----------------------------------------------------------------------------------------------------
        public override void Update()
        {
            base.Update();
            if (ping_task.Update(Layer.CurrentIntervalMS))
            {
                send_ping.Begin();
                SendAction(send_ping);
            }
        }

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

        protected virtual void callback_sessionOpened(INetSession session)
        {
            this.QueueTask((AbstractBattle client) =>
            {
                BattleClient bc = client as BattleClient;
                log.Info("sessionOpened : " + session);
                if (bc.mConnected != null)
                {
                    bc.mConnected.Invoke(bc);
                }
                EnterRoomRequestC2B req = new EnterRoomRequestC2B();
                req.RoomID = bc.room.Room.RoomID;
                req.PlayerUUID = bc.room.PlayerUUID;
                req.Token = bc.token;
                req.TestToken = bc.testToken;
                session.Send(req);
            });
        }

        protected virtual void callback_sessionClosed(INetSession session)
        {
            this.QueueTask((AbstractBattle client) =>
            {
                BattleClient bc = client as BattleClient;
                log.Info("sessionClosed : " + session);
                if (bc.mDisconnectd != null)
                {
                    bc.mDisconnectd.Invoke(bc);
                }
            });
        }

        protected virtual void callback_messageReceived(INetSession session, object data)
        {
            //             if (data is Pong)
            //             {
            //                 uint ctime = (uint)CUtils.CurrentTimeMS;;
            //                 Pong pong = data as Pong;
            //                 this.current_ping = (int)(ctime - pong.ClientTimeDayOfMS);
            //             }
            if (data is KickedByServerNotifyB2C)
            {
                this.kicked = data as KickedByServerNotifyB2C;
            }
            if (data is EnterRoomResponseB2C)
            {
                EnterRoomResponseB2C enter = data as EnterRoomResponseB2C;
                if (enter.Result == EnterRoomResponseB2C.RESULT_OK)
                {
                    CreateRoomInfoR2B cr = enter.RoomData as CreateRoomInfoR2B;
                }
            }

            this.Layer.ProcessMessage(data as IMessage);
            this.QueueTask((AbstractBattle client) =>
            {
                BattleClient bc = this as BattleClient;
                if (bc.mHandleMessage != null)
                {
                    bc.mHandleMessage.Invoke(bc, data as IMessage);
                }
            });
        }

        protected virtual void callback_messageSent(INetSession session, object data)
        {

        }

        protected virtual void callback_onError(INetSession session, Exception err)
        {
            log.Warn("onError : " + err.Message, err);
            this.QueueTask((AbstractBattle client) =>
            {
                BattleClient bc = client as BattleClient;
                if (bc.mHandleError != null)
                {
                    bc.mHandleError.Invoke(bc, err);
                }
            });
        }
        #region Delegate

        public delegate void OnHandleMessage(BattleClient bc, IMessage msg);
        public delegate void OnDisconnectd(BattleClient bc);
        public delegate void OnConnected(BattleClient bc);
        public delegate void OnError(BattleClient bc, Exception err);

        public event OnHandleMessage HandleMessage { add { mHandleMessage += value; } remove { mHandleMessage -= value; } }
        public event OnDisconnectd Disconnectd { add { mDisconnectd += value; } remove { mDisconnectd -= value; } }
        public event OnConnected Connected { add { mConnected += value; } remove { mConnected -= value; } }
        public event OnError HandleError { add { mHandleError += value; } remove { mHandleError -= value; } }

        private OnHandleMessage mHandleMessage;
        private OnDisconnectd mDisconnectd;
        private OnConnected mConnected;
        private OnError mHandleError;

        #endregion

    }
}