using CommonLang;
using CommonLang.ByteOrder;
using CommonLang.Concurrent;
using CommonLang.IO;
using CommonLang.Log;
using CommonLang.Net;
using CommonLang.Protocol;
using CommonServer.Server;
using SuperSocket.SocketBase;
using SuperSocket.SocketBase.Protocol;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace CommonServer.SSocket.SuperSocket
{
    public class Session : AppSession<Session, BinaryRequestInfo>, ISession
    {
        private Logger log = LoggerFactory.GetLogger("SSSession");
        private HashMap<string, object> mAttributes = new HashMap<string, object>();
        private INetPackageCodec mCodec;
        private bool mClosing = false;
        private SocketAcceptor mOwner;

        public Session() { }

        public string ID { get { return base.SessionID; } }
        public bool IsConnected { get { return base.Connected; } }
        public long TotalSentBytes { get; private set; }
        public long TotalRecvBytes { get; private set; }
        public ISessionListener Listener { get; private set; }

        internal void NewSessionConnected(SocketAcceptor owner, ISessionListener listener, INetPackageCodec codec)
        {
            this.Listener = listener;
            this.mCodec = codec;
            this.mOwner = owner;
        }
        internal void NewRequestReceived(int bytes, object obj)
        {
            this.TotalRecvBytes += bytes;
            this.Listener.OnReceivedMessage(this, obj);
        }

        public bool Send(IMessage message)
        {
            lock (this)
            {
                if (mClosing) return false;
            }
            ArraySegment<byte> segment;
            if (mOwner.DoEncodeInternal(this, message, out segment))
            {
                try
                {
                    send_internal(segment.Array, segment.Offset, segment.Count);
                }
                catch (Exception err)
                {
                    log.Error(err.Message, err);
                    Disconnect(false);
                    return false;
                }
                this.TotalSentBytes += segment.Count;
                mOwner.mTotalSentBytes += segment.Count;
                Listener.OnSentMessage(this, message);
                return true;
            }
            return false;
        }
        private void send_internal(byte[] buff, int offset, int length)
        {
#if DEBUG
            //模拟网络卡//
            if (mOwner.EmulateLag)
            {
                mOwner.SendDelay(this, buff, offset, length);
            }
            else
            {
                base.Send(buff, offset, length);
            }
#else
            base.Send(buff, offset, length);
#endif
        }


        public bool SendResponse(CommonLang.Protocol.IMessage request, CommonLang.Protocol.IMessage response)
        {
            response.MessageID = request.MessageID;
            return Send(response);
        }
        public bool Disconnect(bool force)
        {
            lock (this)
            {
                if (mClosing) return false;
                mClosing = true;
            }
            base.Close(CloseReason.ClientClosing);
            return true;
        }

        protected override void OnSessionStarted()
        {
            base.OnSessionStarted();
            Listener.OnConnected(this);
        }

        protected override void OnSessionClosed(CloseReason reason)
        {
            base.OnSessionClosed(reason);
            Listener.OnDisconnected(this, false, reason.ToString());
        }

        protected override void HandleException(Exception e)
        {
            base.HandleException(e);
            if (Listener != null)
            {
                Listener.OnError(this, e);
            }
        }

        public string GetRemoteAddress()
        {
            return base.RemoteEndPoint.ToString();
        }

        #region ________Attributes________

        public object GetAttribute(string key)
        {
            return mAttributes.Get(key);
        }

        public void SetAttribute(string key, object value)
        {
            mAttributes.Put(key, value);
        }

        public void RemoveAttribute(string key)
        {
            mAttributes.RemoveByKey(key);
        }

        public bool ContainsAttribute(string key)
        {
            return mAttributes.ContainsKey(key);
        }

        public ICollection<string> GetAttributeKeys()
        {
            return mAttributes.Keys;
        }

        #endregion
    }
}