using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace FObjBase
{
    /// <summary>
    /// 协议包
    /// </summary>
    public class Pack_Proto : IPack 
    {
        /// <summary>
        /// 协议包长度
        /// </summary>
        private UInt16 plen;
        /// <summary>
        /// 目标obj id
        /// </summary>
        public UInt32 destid;
        /// <summary>
        /// 源obj id
        /// </summary>
        public UInt32 srcid;
        /// <summary>
        /// 交易号
        /// </summary>
        public UInt32 magic;
        /// <summary>
        /// 动作码
        /// </summary>
        public UInt16 info;
        /// <summary>
        /// 数据
        /// </summary>
        public byte[] buf;

        /// <summary>
        /// 转为 字节s
        /// </summary>
        /// <returns></returns>
        public byte[] ToBytes()
        {
            List<byte> buf = new List<byte>();
            plen = (UInt16)(2 + 4 * 3 + 2);
            if(this.buf!=null)
                plen = (UInt16)(plen + this.buf.Length);
            

            buf.AddRange(BitConverter.GetBytes(plen));
            buf.AddRange(BitConverter.GetBytes(destid));
            buf.AddRange(BitConverter.GetBytes(srcid));
            buf.AddRange(BitConverter.GetBytes(magic));
            buf.AddRange(BitConverter.GetBytes(info));
            if(this.buf!=null)
                buf.AddRange(this.buf);

            return buf.ToArray();
        }

        /// <summary>
        /// 解析 字节s 
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public bool TryParse(byte[] value)
        {
            if(value.Length<(2 + 4 * 3 + 2))
                return false;
            int index = 0;
            plen = BitConverter.ToUInt16(value, index);
            index += 2;
            if(value.Length!=plen)
                return false;

            destid = BitConverter.ToUInt32(value, index);
            index += 4;
            srcid = BitConverter.ToUInt32(value, index);
            index += 4;
            magic = BitConverter.ToUInt32(value, index);
            index += 4;
            info = BitConverter.ToUInt16(value, index);
            index += 2;
            int len = value.Length - index;
            if (len <= 0)
                return true;

            buf = new byte[len];
            Array.Copy(value, index, buf, 0, len);
            return true;
        }
    }
    /// <summary>
    /// 协议包的动作码
    /// </summary>
    public class Proto
    { 
        #region client->server
        /// <summary>
        /// client->server;
        /// setvalue 
        /// fobj 基本动作码 不能改!!!
        /// </summary>
        public const  UInt16 INFO_SET_VALUE = 0x0002;
        /// <summary>
        /// client->server;
        /// getvalue 
        /// fobj 基本动作码 不能改!!!
        /// </summary>
        public const  UInt16 INFO_GET_VALUE = 0x0003;
        /// <summary>
        /// client->server;
        /// callfunction 
        /// fobj 基本动作码 不能改!!!
        /// </summary>
        public const  UInt16 INFO_CALL_FUNCTION = 0x0004;
        /// <summary>
        /// client->server;
        /// config_sense 
        /// fobj 基本动作码 不能改!!!
        /// </summary>
        public const  UInt16 INFO_CONFIG_SENSE_OBJ = 0x0005;

        /// <summary>
        /// client->server
        /// obj 已经不在了, 释放资源
        /// </summary>
        public const UInt16 INFO_OBJ_DISPOSE = 0x0009;
        #endregion
        #region 大包
        /// <summary>
        /// push, set, get, call 数据包太大, 被分拆多次发送
        /// 每次发送大包
        /// </summary>
        public const UInt16 INFO_PUSH_BIGSIZE = 0x0006;
        /// <summary>
        /// 请求继续发送大包
        /// </summary>
        public const UInt16 INFO_REQUEST_BIGSIZE = 0x0406;
        #endregion

        #region server->client
        /// <summary>
        /// server->client;
        /// getvalue 返回 
        /// fobj 基本动作码 不能改!!!
        /// </summary>
        public const UInt16 INFO_PUSH_GET_VALUE = 0x0403;
        /// <summary>
        /// server->client;
        /// callfunction 返回 
        /// fobj 基本动作码 不能改!!!
        /// </summary>
        public const UInt16 INFO_PUSH_CALL_FUNCTION = 0x0404;
        /// <summary>
        /// server->client;
        /// pushinfo 
        /// fobj 基本动作码 不能改!!!
        /// </summary>
        public const UInt16 INFO_PUSH_EVENT=0x0410;

        #endregion
    }
    /// <summary>
    /// 大包
    /// </summary>
    public class Pack_BigSize : IPack 
    {
        /// <summary>
        /// 动作 Get, Set, Push, Call, 都允许大包模式
        /// </summary>
        public UInt16 infoid;
        /// <summary>
        /// 功能号
        /// </summary>
        public UInt16 funcid;
        /// <summary>
        /// 总数据量大小
        /// </summary>
        public int size;
        /// <summary>
        /// 当前数据量在总数据量的位置
        /// </summary>
        public int position;
        /// <summary>
        /// 当前数据量
        /// </summary>
        public byte[] buf;
        /// <summary>
        /// 转为 字节s
        /// </summary>
        /// <returns></returns>
        public byte[] ToBytes()
        {
            List<byte> buf = new List<byte>();
            buf.AddRange(BitConverter.GetBytes(infoid));
            buf.AddRange(BitConverter.GetBytes(funcid));
            buf.AddRange(BitConverter.GetBytes(size));
            buf.AddRange(BitConverter.GetBytes(position));
            buf.AddRange(BitConverter.GetBytes(this.buf.Length));
            buf.AddRange(this.buf);
            return buf.ToArray();
        }
        /// <summary>
        /// 解析 字节s 
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public bool TryParse(byte[] value)
        {
            int cnt = 2 + 2 + 4 + 4 + 4;
            if (value.Length < cnt)
                return false;
            int idx = 0;

            infoid = BitConverter.ToUInt16(value, idx);
            idx += 2;
            funcid = BitConverter.ToUInt16(value, idx);
            idx += 2;

            size = BitConverter.ToInt32(value, idx);
            idx += 4;
            position = BitConverter.ToInt32(value, idx);
            idx += 4;
            int len = BitConverter.ToInt32(value, idx);
            idx += 4;

            cnt += len;
            if (value.Length < cnt)
                return false;
            buf = new byte[len];
            Array.Copy(value, idx, buf, 0, buf.Length);
            return true;
        }
    }

    /// <summary>
    /// Get Set Push CallFunction 数据包
    /// </summary>
    public class Pack_GetSetPushCall : IPack 
    {
        /// <summary>
        /// 功能号
        /// </summary>
        public UInt16 infoid;
        /// <summary>
        /// 数据
        /// </summary>
        public byte[] infodata = null;

        /// <summary>
        /// 转为 字节s
        /// </summary>
        /// <returns></returns>
        public byte[] ToBytes()
        {
            List<byte> buf = new List<byte>();
            buf.AddRange(BitConverter.GetBytes(infoid));
            if (infodata != null)
            {
                buf.AddRange(infodata);
            }
            return buf.ToArray();
        }

        /// <summary>
        /// 解析 字节s 
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public bool TryParse(byte[] value)
        {
            if (value.Length < 2)
                return false;
            infoid = BitConverter.ToUInt16(value, 0);
            int info_len = value.Length - 2;
            
            if (info_len > 0)
            {
                infodata = new byte[info_len];
                Buffer.BlockCopy(value, 2, infodata, 0, info_len);
            }
            else
                infodata = null;
            return true;
        }
    }
}