using CommonAI.Zone;
using CommonAI.ZoneServer.JSGModule;
using CommonLang.ByteOrder;
using CommonLang.IO;
using CommonLang.IO.Attribute;
using CommonLang.Log;
using CommonLang.Property;
using CommonLang.Protocol;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;

namespace XmdsServerNode.Node
{
    public class ZoneNodeCodec
    {
        private Logger log = LoggerFactory.GetLogger("BattleCodec");

        private ArraySegment<byte> ZERO_BUFF = new ArraySegment<byte>(new byte[0]);

        private const int FIXED_HEADER_SIZE = 4;
        private const int DEFAULT_BUFFER_SIZE = 1024;

        private IExternalizableFactory sl = null;
        private TemplateManager templates = ZoneNodeManager.Templates.Templates;

        private MemoryStream input;
        private MemoryStream output;
        private InputStream reader;
        private OutputStream writer;

        public ZoneNodeCodec(IExternalizableFactory externalizableFactory)
        {
            this.sl = externalizableFactory;
            this.input = new MemoryStream(DEFAULT_BUFFER_SIZE);
            this.output = new MemoryStream(DEFAULT_BUFFER_SIZE);
            this.reader = new InputStream(input, sl);
            this.writer = new OutputStream(output, sl);
        }

        public CommonLang.IO.IExternalizableFactory Factory
        {
            get { return sl; }
        }

        public bool doDecode(byte[] data, out IMessage message)
        {
            //lock (input)
            {
                input.Position = 0;
                input.Write(data, 0, data.Length);
                input.Position = 0;

                int typeInt = reader.GetS32();
                Type type = sl.GetType(typeInt);
                if (type == null)
                {
                    log.Error("Unknow Protocol : >>>" + typeInt + "<<<");
                    message = null;
                    return false;
                }
                else
                {
                    IMessage nm = (IMessage)ReflectionUtil.CreateInstance(type);
                    nm.ReadExternal(reader);
                    if (nm is BattleMessage)
                    {
                        ((BattleMessage)nm).EndRead(templates);
					}
#if JSGProfile
					JSGServerProfile.RecordRecv(typeInt, input.Position);
#endif
					message = nm;
                    return true;
                }
            }

        }

        public bool doEncode(IMessage message, out ArraySegment<byte> data)
        {
            int typeInt = sl.GetTypeID(message.GetType());
            if (typeInt == 0)
            {
                log.Error("Unknow Protocol : >>>" + typeInt + "<<< - " + message.GetType().FullName);
                data = ZERO_BUFF;
                return false;
            }
            if (message is BattleMessage)
            {
                ((BattleMessage)message).BeforeWrite(templates);
            }
            //lock (output)
            {
                output.Position = 0;
                writer.PutS32(typeInt);
                message.WriteExternal(writer);
                int len = (int)output.Position;
                data = new ArraySegment<byte>(output.GetBuffer(), 0, len);
            }
            return true;
        }

    }
}