using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Reflection;
using System.Xml;
using CommonLang.Xml;
using System.IO.Compression;

namespace CommonLang.IO
{
    public static class IOUtil
    {

        public static byte TryReadByte(Stream data)
        {
            int b = data.ReadByte();
            if (b < 0) { throw new IOException("EOF of stream"); }
            return (byte)b;
        }


        /// <summary>
        /// 从输入流复制到输出流
        /// </summary>
        /// <param name="input">输入流</param>
        /// <param name="output">输出流</param>
        /// <param name="total_bytes">总共复制多少字节</param>
        /// <param name="progress">进度回调,返回False表示终止进程</param>
        /// <param name="buffer_size">缓冲区大小</param>
        /// <returns></returns>
        public static bool ReadTo(Stream input, Stream output, long total_bytes, Predicate<int> progress, int buffer_size = 16384)
        {
            byte[] io_buffer = new byte[buffer_size];
            long total_readed = 0;
            while (total_readed < total_bytes)
            {
                if (!progress(0)) return false;
                int expect = (int)Math.Min(io_buffer.Length, total_bytes - total_readed);
                int readed = input.Read(io_buffer, 0, expect);
                total_readed += readed;
                if (!progress(readed)) return false;
                output.Write(io_buffer, 0, readed);
            }
            output.Flush();
            return true;
        }

        public static byte[] ReadExpect(Stream input, int count)
        {
            if (count == 0) return new byte[0];
            byte[] data = new byte[count];
            ReadToEnd(input, data, 0, count);
            return data;
        }
        public static void ReadToEnd(Stream input, byte[] data, int offset, int count)
        {
            if (count == 0) return;
            int readed = input.Read(data, offset, count);
            if (readed <= 0)
                throw new IOException("EOF of stream");
            while (readed < count)
            {
                int bytes = input.Read(data, offset + readed, count - readed);
                if (bytes <= 0)
                {
                    throw new IOException("EOF of stream");
                }
                readed += bytes;
            }
        }

        public static void ReadToEnd(Stream src, Stream dst)
        {
            byte[] buffer = new byte[1024];
            while (true)
            {
                int readed = src.Read(buffer, 0, buffer.Length);
                if (readed > 0)
                {
                    dst.Write(buffer, 0, readed);
                }
                else
                {
                    break;
                }
            }
        }

        public static byte[] ReadToEnd(Stream src)
        {
            using (MemoryStream dst = new MemoryStream())
            {
                ReadToEnd(src, dst);
                return dst.ToArray();
            }
        }

        public static void WriteToEnd(Stream output, byte[] data, int offset, int count)
        {
            output.Write(data, offset, count);
        }


        public static T CloneIExternalizable<T>(IExternalizableFactory decode, T src) where T : IExternalizable, new()
        {
            if (src != null)
            {
                T ret = new T();
                {
                    using (MemoryStream ms = new MemoryStream())
                    {
                        src.WriteExternal(new OutputStream(ms, decode));
                        ms.Position = 0;
                        ret.ReadExternal(new InputStream(ms, decode));
                    }
                }
                return ret;
            }
            return default(T);
        }
        public static IExternalizable Clone(IExternalizableFactory decode, IExternalizable src)
        {
            IExternalizable ret = null;
            if (src != null)
            {
                using (MemoryStream ms = new MemoryStream())
                {
                    new OutputStream(ms, decode).PutExt(src);
                    ms.Position = 0;
                    ret = new InputStream(ms, decode).GetExtAny();
                }
            }
            return ret;
        }

        public static byte[] LoadFromAssembly(Assembly assembly, string resource)
        {
            Stream stream = assembly.GetManifestResourceStream(resource);
            byte[] ret = new byte[stream.Length];
            /*stream.Read(ret, 0, ret.Length);*/
            IOUtil.ReadToEnd(stream, ret, 0, ret.Length);
            return ret;
        }

        public static byte[] ObjectToBin(IExternalizableFactory decode, IExternalizable ext)
        {
            using (MemoryStream ms = new MemoryStream())
            {
                OutputStream output = new OutputStream(ms, decode);
                output.PutExt(ext);
                int len = (int)ms.Position;
                byte[] buffer = ms.GetBuffer();
                Array.Resize(ref buffer, len);
                return buffer;
            }
        }

        public static T BinToObject<T>(IExternalizableFactory decode, byte[] data) where T : IExternalizable, new()
        {
            if (data == null || data.Length == 0) return default(T);
            using (MemoryStream ms = new MemoryStream(data))
            {
                var input = new InputStream(ms, decode);
                return input.GetExt<T>();
            }
        }

        public static IExternalizable BinToObjectAny(IExternalizableFactory decode, byte[] data)
        {
            if (data == null || data.Length == 0) return null;
            using (MemoryStream ms = new MemoryStream(data))
            {
                InputStream input = new InputStream(ms, decode);
                return input.GetExtAny();
            }
        }




        public static void Zip(Stream src, Stream dst)
        {
            GZipStream zipStream = null;
            try
            {
                zipStream = new GZipStream(dst, CompressionMode.Compress, true);
                byte[] buffer = new byte[Math.Min(1024, src.Length)];
                while (true)
                {
                    int bytesRead = src.Read(buffer, 0, buffer.Length);
                    if (bytesRead == 0)
                        break;
                    zipStream.Write(buffer, 0, bytesRead);
                }
                zipStream.Flush();
                dst.Flush();
            }
            finally
            {
                if (zipStream != null) zipStream.Close();
            }
        }

        public static void Unzip(Stream src, Stream dst)
        {
            GZipStream zipStream = null;
            try
            {
                // Create a compression stream pointing to the destiantion stream
                zipStream = new GZipStream(src, CompressionMode.Decompress, true);
                // Read the footer to determine the length of the destiantion file
                byte[] buffer = new byte[1024];
                // Read the compressed data into the buffer
                while (true)
                {
                    int bytesRead = zipStream.Read(buffer, 0, buffer.Length);
                    if (bytesRead == 0)
                        break;
                    dst.Write(buffer, 0, bytesRead);
                }
                dst.Flush();
            }
            finally
            {
                if (zipStream != null) zipStream.Close();
            }
        }

        public static byte[] Zip(byte[] data)
        {
            // Read in the compressed source stream
            MemoryStream src = new MemoryStream(data);
            MemoryStream dst = new MemoryStream(data.Length * 2);
            try
            {
                Zip(src, dst);
                byte[] ret = new byte[dst.Position];
                Array.Copy(dst.GetBuffer(), 0, ret, 0, ret.Length);
                return ret;
            }
            catch (Exception err)
            {
                Console.WriteLine(err.Message + "\r" + err.StackTrace);
                return null;
            }
            finally
            {
                if (src != null) src.Close();
                if (dst != null) dst.Close();
            }
        }

        public static byte[] Unzip(byte[] data)
        {
            // Read in the compressed source stream
            MemoryStream src = new MemoryStream(data);
            MemoryStream dst = new MemoryStream(data.Length);
            try
            {
                Unzip(src, dst);
                byte[] ret = new byte[dst.Position];
                Array.Copy(dst.GetBuffer(), 0, ret, 0, ret.Length);
                return ret;
            }
            catch (Exception err)
            {
                Console.WriteLine(err.Message + "\r" + err.StackTrace);
                return null;
            }
            finally
            {
                if (src != null) src.Close();
                if (dst != null) dst.Close();
            }
        }

    }


    public interface IExternalizable
    {
        void WriteExternal(IOutputStream output);

        void ReadExternal(IInputStream input);
    }

    public interface IExternalizableFactory
    {
        int GetTypeID(Type type);

        Type GetType(int id);
    }

    public enum DataType : byte
    {
        NA = 0,
        U8 = 1,
        S8 = 2,
        U16 = 3,
        S16 = 4,
        U32 = 5,
        S32 = 6,
        U64 = 7,
        S64 = 8,
        F32 = 9,
        F64 = 10,
        UTF = 11,
        EXT = 12,
        UC = 13,
    }

    public delegate T GetData<T>();

    public delegate void PutData<T>(T v);

    public abstract class IOStream
    {
        public static int DEFAULT_ARRAY_LIMIT = UInt16.MaxValue;
        public static int DEFAULT_BYTES_LIMIT = 100 * 1024 * 1024;

        public int ARRAY_LIMIT = DEFAULT_ARRAY_LIMIT;
        public int BYTES_LIMIT = DEFAULT_BYTES_LIMIT;
    }

    public abstract class IOutputStream : IOStream
    {
        protected static System.Text.UTF8Encoding utfenc = new System.Text.UTF8Encoding(false);

        public IOutputStream(IExternalizableFactory factory)
        {
            this.Factory = factory;
        }
        public IExternalizableFactory Factory { get; private set; }

        #region _Abstract_
        public abstract void PutBytes(byte[] bytes);
        public abstract void PutRawData(byte[] bytes, int offset, int count);
        public abstract void PutBool(bool value);
        public abstract void PutU8(byte value);
        public abstract void PutS8(sbyte value);
        public abstract void PutU16(ushort value);
        public abstract void PutS16(short value);
        public abstract void PutU32(uint value);
        public abstract void PutS32(int value);
        public abstract void PutU64(ulong value);
        public abstract void PutS64(long value);
        public abstract void PutF32(float value);
        public abstract void PutF64(double value);
        public abstract void PutUnicode(char value);
        public abstract void PutUTF(string str);
        public abstract long GetBuffPos();
        #endregion

        #region _基础类型_
        /// <summary>
        /// 写入可变长度32位
        /// </summary>
        public void PutVU32(uint value)
        {
            PutVU64(value);
        }
        /// <summary>
        /// 写入可变长度32位
        /// </summary>
        public void PutVS32(int value)
        {
            PutVS64(value);
        }
        /// <summary>
        /// 写入可变长度64位
        /// </summary>
        public void PutVS64(long value)
        {
            ulong m;
            if (value < 0)
            {
                m = (ulong)(((-value) << 1) | 1);
            }
            else
            {
                m = (ulong)(((value) << 1));
            }
            PutVU64(m);
        }
        /// <summary>
        /// 写入可变长度64位
        /// </summary>
        public void PutVU64(ulong value)
        {
            do
            {
                byte b = (byte)(value & 0x7F);
                value = (value >> 7);
                if (value != 0)
                {
                    b = (byte)(b | 0x80);
                }
                this.PutU8(b);
            }
            while (value != 0);
        }

        public void PutEnum8(ValueType enum8)
        {
            byte u8 = (byte)enum8;
            PutU8(u8);
        }
        public void PutEnum32(ValueType enum32)
        {
            int s32 = (int)enum32;
            PutS32(s32);
        }
        public void PutEnum8<T>(T enum8)
        {
            byte u8 = Convert.ToByte(enum8);
            PutU8(u8);
        }
        public void PutEnum32<T>(T enum32)
        {
            int s32 = Convert.ToInt32(enum32);
            PutS32(s32);
        }

        #endregion

        #region _对象类型_

        public void PutExt(IExternalizable value)
        {
            if (value != null)
            {
                int typeID = Factory.GetTypeID(value.GetType());
                if (typeID != 0)
                {
                    PutS32(typeID);
                    value.WriteExternal(this);

					//if(typeID != 0x8601 && typeID != 0x8006 && typeID != 0x8100 && typeID != 0x4003 && typeID != 0x4004 && typeID != 0x000B0010 & 
					//	typeID != 0x4009 && typeID != 0x4104 && typeID != 0x4109 && typeID != 0x8407 && typeID != 0x9001012 && typeID != 0xF000024 && 
					//	typeID != 0xF00001D && typeID != 0x400B && typeID != 0x4107 && typeID != 0x400C && typeID != 0xF000038 && typeID != 0x400C && 
					//	typeID != 0x000B0005 && typeID != 0x900100A && typeID != 0x9001004 && typeID != 0x9001005 && typeID != 0x9001002 && 
					//	typeID != 0x9001013 && typeID != 0x000B0001 && typeID != 0x8401	&& typeID != 0x8116 && typeID != 0x9001010 && 
					//	typeID != 0x9001016 && typeID != 0xF000008 && typeID != 0x9001003 && typeID != 0x9001006 && typeID != 0x4016 && typeID != 0x9005 &&
					//	typeID != 0x9002 && typeID != 0xF00001E && typeID != 0xF000015 && typeID != 0x9006 && typeID != 0x9010)
					//{
					//	Console.WriteLine(" -- putExt -- {0:x}", typeID);
					//}					
                }
                else
                {
                    PutS32(0);
                    //log.Error("Can Not Resolve IExternalizable Message : " + value.GetType());
                    throw new IOException("Can Not Resolve IExternalizable Message : " + value.GetType());
                }
            }
            else
            {
                PutS32(0);
            }
        }

        public int GetTypeID(IExternalizable value)
        {
           return Factory.GetTypeID(value.GetType());
        }

        public void PutObj2Xml(object obj)
        {
            if (obj != null)
            {
                XmlDocument x = XmlUtil.ObjectToXml(obj);
                string utf = XmlUtil.ToString(x);
                byte[] data = CUtils.UTF8.GetBytes(utf);
                PutBytes(data);
            }
            else
            {
                PutBytes(null);
            }
        }
        /// <summary>
        /// 自动检测类型
        /// </summary>
        /// <param name="value"></param>
        public void PutData(object value)
        {
            if (value is byte)
            {
                PutU8((byte)DataType.U8);
                PutU8((byte)value);
            }
            else if (value is sbyte)
            {
                PutU8((byte)DataType.S8);
                PutS8((sbyte)value);
            }

            else if (value is ushort)
            {
                PutU8((byte)DataType.U16);
                PutU16((ushort)value);
            }
            else if (value is short)
            {
                PutU8((byte)DataType.S16);
                PutS16((short)value);
            }

            else if (value is uint)
            {
                PutU8((byte)DataType.U32);
                PutU32((uint)value);
            }
            else if (value is int)
            {
                PutU8((byte)DataType.S32);
                PutS32((int)value);
            }

            else if (value is ulong)
            {
                PutU8((byte)DataType.U64);
                PutU64((ulong)value);
            }
            else if (value is long)
            {
                PutU8((byte)DataType.S64);
                PutS64((long)value);
            }

            else if (value is float)
            {
                PutU8((byte)DataType.F32);
                PutF32((float)value);
            }
            else if (value is double)
            {
                PutU8((byte)DataType.F64);
                PutF64((double)value);
            }

            else if (value is char)
            {
                PutU8((byte)DataType.UC);
                PutUnicode((char)value);
            }

            else if (value is string)
            {
                PutU8((byte)DataType.UTF);
                PutUTF((string)value);
            }

            else if (value is IExternalizable)
            {
                PutU8((byte)DataType.EXT);
                PutExt((IExternalizable)value);
            }
            else
            {
                PutU8((byte)DataType.NA);
            }
        }

        #endregion

        #region _集合类型_

        public void PutUTFArray(string[] array)
        {
            if (array == null)
            {
                PutS32(-1);
            }
            else
            {
                int len = array.Length;
                if (len > ARRAY_LIMIT) { throw new IOException("Collection overflow : " + len + " > " + ARRAY_LIMIT); }
                PutS32(len);
                for (int i = 0; i < len; i++)
                {
                    this.PutUTF(array[i]);
                }
            }
        }
        public void PutUTFList(IList<string> list)
        {
            if (list == null)
            {
                PutS32(-1);
            }
            else
            {
                int len = list.Count;
                if (len > ARRAY_LIMIT) { throw new IOException("Collection overflow : " + len + " > " + ARRAY_LIMIT); }
                PutS32(len);
                for (int i = 0; i < len; i++)
                {
                    this.PutUTF(list[i]);
                }
            }
        }
        public void PutArray<T>(T[] array, PutData<T> action)
        {
            if (array == null)
            {
                PutS32(-1);
            }
            else
            {
                int len = array.Length;
                if (len > ARRAY_LIMIT) { throw new IOException("Collection overflow : " + len + " > " + ARRAY_LIMIT); }
                PutS32(len);
                for (int i = 0; i < len; i++)
                {
                    action.Invoke(array[i]);
                }
            }
        }
        public void PutList<T>(IList<T> list, PutData<T> action)
        {
            if (list == null)
            {
                PutS32(-1);
            }
            else
            {
                int len = list.Count;
                if (len > ARRAY_LIMIT) { throw new IOException("Collection overflow : " + len + " > " + ARRAY_LIMIT); }
                PutS32(len);
                for (int i = 0; i < len; i++)
                {
                    action.Invoke(list[i]);
                }
            }
        }
        public void PutMap<K, V>(IDictionary<K, V> map, PutData<K> k_action, PutData<V> v_action)
        {
            if (map == null)
            {
                PutS32(-1);
            }
            else
            {
                int len = map.Count;
                if (len > ARRAY_LIMIT) { throw new IOException("Collection overflow : " + len + " > " + ARRAY_LIMIT); }
                this.PutS32(len);
                foreach (var kv in map)
                {
                    k_action.Invoke(kv.Key);
                    v_action.Invoke(kv.Value);
                }
            }
        }

        /// <summary>
        /// 不包括消息头,列表中元素必须保证类型一致
        /// </summary>
        public void PutStructArray<T>(T[] array) where T : IExternalizable
        {
            if (array == null)
            {
                PutS32(-1);
            }
            else
            {
                int len = array.Length;
                if (len > ARRAY_LIMIT) { throw new IOException("Collection overflow : " + len + " > " + ARRAY_LIMIT); }
                this.PutS32(array.Length);
                for (int i = 0; i < array.Length; i++)
                {
                    array[i].WriteExternal(this);
                }
            }
        }
        /// <summary>
        /// 不包括消息头,列表中元素必须保证类型一致
        /// </summary>
        public void PutStructList<T>(IList<T> array) where T : IExternalizable
        {
            if (array == null)
            {
                PutS32(-1);
            }
            else
            {
                int len = array.Count;
                if (len > ARRAY_LIMIT) { throw new IOException("Collection overflow : " + len + " > " + ARRAY_LIMIT); }
                this.PutS32(array.Count);
                for (int i = 0; i < array.Count; i++)
                {
                    array[i].WriteExternal(this);
                }
            }
        }
        /// <summary>
        /// 不包括消息头,列表中元素必须保证类型一致
        /// </summary>
        public void PutExtArray<T>(T[] array) where T : IExternalizable
        {
            if (array == null)
            {
                PutS32(-1);
            }
            else
            {
                int len = array.Length;
                if (len > ARRAY_LIMIT) { throw new IOException("Collection overflow : " + len + " > " + ARRAY_LIMIT); }
                this.PutS32(array.Length);
                for (int i = 0; i < array.Length; i++)
                {
                    array[i].WriteExternal(this);
                }
            }
        }
        /// <summary>
        /// 不包括消息头,列表中元素必须保证类型一致
        /// </summary>
        public void PutExtList<T>(IList<T> array) where T : IExternalizable
        {
            if (array == null)
            {
                PutS32(-1);
            }
            else
            {
                int len = array.Count;
                if (len > ARRAY_LIMIT) { throw new IOException("Collection overflow : " + len + " > " + ARRAY_LIMIT); }
                this.PutS32(array.Count);
                for (int i = 0; i < array.Count; i++)
                {
                    array[i].WriteExternal(this);
                }
            }
        }

        #endregion

    }

    public abstract class IInputStream : IOStream
    {
        protected static System.Text.UTF8Encoding utfenc = new System.Text.UTF8Encoding(false);
        public IInputStream(IExternalizableFactory factory)
        {
            this.Factory = factory;
        }
        public IExternalizableFactory Factory { get; private set; }

        #region _Abstract_
        public abstract byte[] GetBytes();
        public abstract void GetRawData(byte[] buff, int offset, int count);
        public abstract bool GetBool();
        public abstract byte GetU8();
        public abstract sbyte GetS8();
        public abstract ushort GetU16();
        public abstract short GetS16();
        public abstract uint GetU32();
        public abstract int GetS32();
        public abstract ulong GetU64();
        public abstract long GetS64();
        public abstract float GetF32();
        public abstract double GetF64();
        public abstract char GetUnicode();
        public abstract string GetUTF();
        #endregion

        #region _基础类型_
        /// <summary>
        /// 写入可变长度32位
        /// </summary>
        public UInt32 GetVU32()
        {
            return (UInt32)GetVU64();
        }
        /// <summary>
        /// 写入可变长度32位
        /// </summary>
        public Int32 GetVS32()
        {
            return (Int32)GetVS64();
        }
        /// <summary>
        /// 写入可变长度64位
        /// </summary>
        public Int64 GetVS64()
        {
            ulong m = GetVU64();
            long v = (long)(m >> 1);
            if (m % 2 == 1)
            {
                return -v;
            }
            else
            {
                return v;
            }
        }
        /// <summary>
        /// 写入可变长度64位
        /// </summary>
        public UInt64 GetVU64()
        {
            UInt64 value = 0;
            UInt64 b = 0;
            for (int i = 0; i <= 70; i += 7)
            {
                b = GetU8();
                value |= ((b & 0x7F) << i);
                if ((b & 0x80) == 0)
                    break;
            }
            return value;
        }
        public T GetEnum8<T>()
        {
            byte u8 = GetU8();
            if (Enum.IsDefined(typeof(T), u8))
            {
                return (T)Enum.ToObject(typeof(T), u8);
            }
            return default(T);
        }
        public T GetEnum32<T>()
        {
            int s32 = GetS32();
            if (Enum.IsDefined(typeof(T), s32))
            {
                return (T)Enum.ToObject(typeof(T), s32);
            }
            return default(T);
        }

        #endregion

        #region _对象类型_

        public T GetExt<T>() where T : IExternalizable, new()
        {
            int typeID = GetS32();
            if (typeID != 0)
            {
                Type type = Factory.GetType(typeID);
                if (type != null)
                {
                    T any = (T)Activator.CreateInstance(type);
                    any.ReadExternal(this);
                    return any;
                }
                else
                {
                    throw new IOException("Can Not Resolve IExternalizable Message : 0x" + typeID.ToString("X"));
                }
            }
            return default(T);
        }
        public T GetExt<T>(T ret) where T : IExternalizable
        {
            int typeID = GetS32();
            if (typeID != 0)
            {
                Type type = Factory.GetType(typeID);
                if (type == null)
                {
                    throw new IOException("Can Not Resolve IExternalizable Message : 0x" + typeID.ToString("X"));
                }
                if (!type.IsInstanceOfType(ret))
                {
                    throw new IOException("type can't match:" + type + "->" + ret.GetType());
                }
                else
                {
                    ret.ReadExternal(this);
                    return ret;
                }
            }
            return default(T);
        }
        public IExternalizable GetExtAny()
        {
            int typeID = GetS32();
            if (typeID != 0)
            {
                Type type = Factory.GetType(typeID);
                if (type != null)
                {
                    IExternalizable any = (IExternalizable)Activator.CreateInstance(type);
                    any.ReadExternal(this);
                    return any;
                }
                else
                {
                    throw new IOException("Can Not Resolve IExternalizable Message : 0x" + typeID.ToString("X"));
                }
            }
            return null;
        }

        public T GetXml2Obj<T>(Action<Exception> error = null)
        {
            byte[] data = GetBytes();
            if (data != null && data.Length > 0)
            {
                string xml = CUtils.UTF8.GetString(data);
                XmlDocument x = XmlUtil.FromString(xml);
                T ret = (T)XmlUtil.XmlToObject(x, error);
                return ret;
            }
            return default(T);
        }

        /// <summary>
        /// 自动检测类型
        /// </summary>
        /// <param name="type"></param>
        public object GetData(out DataType type)
        {
            byte dt = GetU8();
            if (Enum.IsDefined(typeof(DataType), dt))
            {
                type = (DataType)dt;
                switch (type)
                {
                    case DataType.U8: return GetU8();
                    case DataType.S8: return GetS8();
                    case DataType.U16: return GetU16();
                    case DataType.S16: return GetS16();
                    case DataType.U32: return GetU32();
                    case DataType.S32: return GetS32();
                    case DataType.U64: return GetU64();
                    case DataType.S64: return GetS64();
                    case DataType.F32: return GetF32();
                    case DataType.F64: return GetF64();
                    case DataType.UC: return GetUnicode();
                    case DataType.UTF: return GetUTF();
                    case DataType.EXT: return GetExtAny();
                }
            }
            type = DataType.NA;
            return null;
        }
        public object GetData()
        {
            byte dt = GetU8();
            if (Enum.IsDefined(typeof(DataType), dt))
            {
                DataType type = (DataType)dt;
                switch (type)
                {
                    case DataType.U8: return GetU8();
                    case DataType.S8: return GetS8();
                    case DataType.U16: return GetU16();
                    case DataType.S16: return GetS16();
                    case DataType.U32: return GetU32();
                    case DataType.S32: return GetS32();
                    case DataType.U64: return GetU64();
                    case DataType.S64: return GetS64();
                    case DataType.F32: return GetF32();
                    case DataType.F64: return GetF64();
                    case DataType.UC: return GetUnicode();
                    case DataType.UTF: return GetUTF();
                    case DataType.EXT: return GetExtAny();
                }
            }
            return null;
        }

        #endregion

        #region _集合类型_

        public string[] GetUTFArray()
        {
            int len = GetS32();
            if (len > ARRAY_LIMIT) { throw new IOException("Collection overflow : " + len + " > " + ARRAY_LIMIT); }
            if (len < 0) return null;
            string[] ret = new string[len];
            for (int i = 0; i < len; i++)
            {
                ret[i] = GetUTF();
            }
            return ret;
        }
        public T[] GetArray<T>(GetData<T> action)
        {
            int len = GetS32();
            if (len > ARRAY_LIMIT) { throw new IOException("Collection overflow : " + len + " > " + ARRAY_LIMIT); }
            if (len < 0) return null;
            T[] ret = new T[len];
            for (int i = 0; i < len; i++)
            {
                T d = action.Invoke();
                ret[i] = d;
            }
            return ret;
        }
        /// <summary>
        /// 不包括消息头,列表中元素必须保证类型一致
        /// </summary>
        public T[] GetStructArray<T>() where T : IExternalizable, new()
        {
            int len = GetS32();
            if (len > ARRAY_LIMIT) { throw new IOException("Collection overflow : " + len + " > " + ARRAY_LIMIT); }
            if (len < 0) return null;
            T[] array = new T[len];
            for (int i = 0; i < len; i++)
            {
                array[i].ReadExternal(this);
            }
            return array;
        }
        /// <summary>
        /// 不包括消息头,列表中元素必须保证类型一致
        /// </summary>
        public T[] GetExtArray<T>() where T : IExternalizable, new()
        {
            int len = GetS32();
            if (len > ARRAY_LIMIT) { throw new IOException("Collection overflow : " + len + " > " + ARRAY_LIMIT); }
            if (len < 0) return null;
            T[] array = new T[len];
            for (int i = 0; i < len; i++)
            {
                array[i] = new T();
                array[i].ReadExternal(this);
            }
            return array;
        }
        public List<string> GetUTFList()
        {
            int len = GetS32();
            if (len > ARRAY_LIMIT) { throw new IOException("Collection overflow : " + len + " > " + ARRAY_LIMIT); }
            if (len < 0) return null;
            List<string> ret = new List<string>(len);
            for (int i = 0; i < len; i++)
            {
                string d = GetUTF();
                ret.Add(d);
            }
            return ret;
        }
        public List<T> GetList<T>(GetData<T> action)
        {
            int len = GetS32();
            if (len > ARRAY_LIMIT) { throw new IOException("Collection overflow : " + len + " > " + ARRAY_LIMIT); }
            if (len < 0) return null;
            List<T> ret = new List<T>(len);
            for (int i = 0; i < len; i++)
            {
                T d = action.Invoke();
                ret.Add(d);
            }
            return ret;
        }

        public List<T> GetListAny<T>() where T : IExternalizable
        {
            int len = GetS32();
            if (len > ARRAY_LIMIT) { throw new IOException("Collection overflow : " + len + " > " + ARRAY_LIMIT); }
            if (len < 0) return null;
            List<T> ret = new List<T>(len);
            for (int i = 0; i < len; i++)
            {
                IExternalizable ext = GetExtAny();
                if (ext != null)
                {
                    ret.Add((T)ext);
                }
            }
            return ret;
        }
        /// <summary>
        /// 不包括消息头,列表中元素必须保证类型一致
        /// </summary>
        public List<T> GetStructList<T>() where T : IExternalizable, new()
        {
            int len = GetS32();
            if (len > ARRAY_LIMIT) { throw new IOException("Collection overflow : " + len + " > " + ARRAY_LIMIT); }
            if (len < 0) return null;
            List<T> list = new List<T>();
            for (int i = 0; i < len; i++)
            {
                T item = new T();
                item.ReadExternal(this);
                list.Add(item);
            }
            return list;
        }
        /// <summary>
        /// 不包括消息头,列表中元素必须保证类型一致
        /// </summary>
        public List<T> GetExtList<T>() where T : IExternalizable, new()
        {
            int len = GetS32();
            if (len > ARRAY_LIMIT) { throw new IOException("Collection overflow : " + len + " > " + ARRAY_LIMIT); }
            if (len < 0) return null;
            List<T> list = new List<T>();
            for (int i = 0; i < len; i++)
            {
                T item = new T();
                item.ReadExternal(this);
                list.Add(item);
            }
            return list;
        }

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

        public L GetGenericUTFList<L>() where L : class, IList<string>, new()
        {
            int len = GetS32();
            if (len > ARRAY_LIMIT) { throw new IOException("Collection overflow : " + len + " > " + ARRAY_LIMIT); }
            if (len < 0) return null;
            var ret = new L();
            for (int i = 0; i < len; i++)
            {
                string d = GetUTF();
                ret.Add(d);
            }
            return ret;
        }
        public L GetGenericList<L, T>(GetData<T> action) where L : class, IList<T>, new()
        {
            int len = GetS32();
            if (len > ARRAY_LIMIT) { throw new IOException("Collection overflow : " + len + " > " + ARRAY_LIMIT); }
            if (len < 0) return null;
            L ret = new L();
            for (int i = 0; i < len; i++)
            {
                T d = action.Invoke();
                ret.Add(d);
            }
            return ret;
        }
        public L GetGenericListAny<L, T>()
            where T : IExternalizable
            where L : class, IList<T>, new()
        {
            int len = GetS32();
            if (len > ARRAY_LIMIT) { throw new IOException("Collection overflow : " + len + " > " + ARRAY_LIMIT); }
            if (len < 0) return null;
            var ret = new L();
            for (int i = 0; i < len; i++)
            {
                IExternalizable ext = GetExtAny();
                if (ext != null)
                {
                    ret.Add((T)ext);
                }
            }
            return ret;
        }
        /// <summary>
        /// 不包括消息头,列表中元素必须保证类型一致
        /// </summary>
        public L GetGenericStructList<L, T>()
            where T : struct, IExternalizable
            where L : class, IList<T>, new()
        {
            int len = GetS32();
            if (len > ARRAY_LIMIT) { throw new IOException("Collection overflow : " + len + " > " + ARRAY_LIMIT); }
            if (len < 0) return null;
            var list = new L();
            for (int i = 0; i < len; i++)
            {
                T item = new T();
                item.ReadExternal(this);
                list.Add(item);
            }
            return list;
        }
        /// <summary>
        /// 不包括消息头,列表中元素必须保证类型一致
        /// </summary>
        public L GetGenericExtList<L, T>()
            where T : IExternalizable, new()
            where L : class, IList<T>, new()
        {
            int len = GetS32();
            if (len > ARRAY_LIMIT) { throw new IOException("Collection overflow : " + len + " > " + ARRAY_LIMIT); }
            if (len < 0) return null;
            var list = new L();
            for (int i = 0; i < len; i++)
            {
                T item = new T();
                item.ReadExternal(this);
                list.Add(item);
            }
            return list;
        }
        //--------------------------------------------------------------------------------------------
        public HashMap<K, V> GetMap<K, V>(GetData<K> k_action, GetData<V> v_action)
        {
            int len = GetS32();
            if (len > ARRAY_LIMIT) { throw new IOException("Collection overflow : " + len + " > " + ARRAY_LIMIT); }
            if (len < 0) return null;
            HashMap<K, V> ret = new HashMap<K, V>(len);
            for (int i = 0; i < len; i++)
            {
                K k = k_action.Invoke();
                V v = v_action.Invoke();
                ret[k] = v;
            }
            return ret;
        }
        public M GetGenericMap<M, K, V>(GetData<K> k_action, GetData<V> v_action) where M : class, IDictionary<K, V>, new()
        {
            int len = GetS32();
            if (len > ARRAY_LIMIT) { throw new IOException("Collection overflow : " + len + " > " + ARRAY_LIMIT); }
            if (len < 0) return null;
            M ret = new M();
            for (int i = 0; i < len; i++)
            {
                K k = k_action.Invoke();
                V v = v_action.Invoke();
                ret[k] = v;
            }
            return ret;
        }
        //--------------------------------------------------------------------------------------------
        #endregion


    }

}