using System;
using System.Collections.Generic;
using System.IO;
using System.Text;

namespace Apewer.Internals
{

    internal class ByteHelper
    {

        /// <summary>所有字节取反。</summary>
        public static byte[] Adverse(byte[] argOrigin)
        {
            if (argOrigin == null) return Constant.EmptyBytes;
            if (argOrigin.Length < 1) return Constant.EmptyBytes;
            byte[] vba = new byte[argOrigin.Length];
            for (int i = 0; i < argOrigin.Length; i++) vba[i] = (byte)(255 - argOrigin[i]);
            return vba;
        }

        /// <summary>克隆字节数组。当源为 NULL 时,将获取零元素字节数组。</summary>
        public static byte[] Clone(byte[] argOrigin)
        {
            if (argOrigin == null) return Constant.EmptyBytes;
            if (argOrigin.LongLength < 0L) return Constant.EmptyBytes;
            var result = new byte[argOrigin.LongLength];
            argOrigin.CopyTo(result, 0L);
            return result;
        }

        /// <summary>为文本数据添加 BOM 字节,若已存在则忽略。</summary>
        public static byte[] AddTextBom(byte[] argOrigin)
        {
            if (argOrigin == null) return Constant.Bom;
            if (argOrigin.LongLength < 1L) return Constant.Bom;

            var memory = new MemoryStream();
            var length = argOrigin.Length;
            if (length > 2)
            {
                if ((argOrigin[0] != 0xEF) || (argOrigin[1] != 0xBB) || (argOrigin[2] != 0xBF))
                {
                    memory.Write(Constant.Bom, 0, 3);
                }
            }
            if (length > 0)
            {
                memory.Write(argOrigin, 0, length);
            }
            var data = memory.ToArray();
            memory.Dispose();
            return data;
        }

        /// <summary>去除文本数据的 BOM 字节,若不存在则忽略。</summary>
        public static byte[] WipeTextBom(byte[] bytes)
        {
            if (bytes == null) return Constant.EmptyBytes;
            var length = bytes.Length;
            if (length >= 3)
            {
                if ((bytes[0] == 0xEF) && (bytes[1] == 0xBB) && (bytes[2] == 0xBF))
                {
                    var memory = new MemoryStream();
                    memory.Write(bytes, 3, length - 3);
                    var result = memory.ToArray();
                    memory.Dispose();
                    return result;
                }
            }
            return bytes;
        }

        /// <summary>解析封装的数据,获取多个字节数组。</summary>
        public static List<byte[]> ToList(byte[] argBytes)
        {
            var list = new List<byte[]>();
            if (argBytes == null) return list;
            var ms = new MemoryStream(argBytes);
            int done = 0; // 已处理字节数。
            int count = 0; // 数组数量。
            int total = argBytes.Length; // 总字节数。
            byte[] a = new byte[4]; // 长度。
            byte[] b; // 数据。
            int l; // 长度。
            if (total >= 4)
            {
                ms.Read(a, 0, 4); done += 4;
                if (argBytes[0] <= 127)
                {
                    count = GetInt32(a);
                    for (int i = 0; i < count; i++)
                    {
                        bool addempty = true;
                        if (done + 4 <= total)
                        {
                            ms.Read(a, 0, 4); done += 4;
                            l = GetInt32(a);
                            if (l > 0)
                            {
                                if (done + l > total) l = total - done;
                                if (l > 0)
                                {
                                    b = new byte[l];
                                    ms.Read(b, 0, l); done += l;
                                    list.Add(b);
                                    addempty = false;
                                }
                            }
                            if (addempty) list.Add(Constant.EmptyBytes);
                        }
                        else break;
                    }
                }
            }
            return list;
        }

        /// <summary>封装多个字节数组。</summary>
        public static byte[] FromList(List<byte[]> argList)
        {
            if (argList == null) return Constant.EmptyBytes;
            var count = argList.Count;
            var ms = new MemoryStream();
            var sl = GetBytes(count);
            ms.Write(sl, 0, sl.Length);
            for (int i = 0; i < count; i++)
            {
                var len = GetBytes(argList[i].Length);
                ms.Write(len, 0, len.Length);
                ms.Write(argList[i], 0, argList[i].Length);
            }
            var bs = ms.ToArray();
            ms.Dispose();
            return bs;
        }

        /// <summary>Int32 -> Byte[]</summary>
        private static byte[] GetBytes(int argValue)
        {
            const int t3 = 256 * 256 * 256;
            const int t2 = 256 * 256;
            const int t1 = 256;

            byte[] vbs = { 0, 0, 0, 0 };

            if (argValue >= 0)
            {
                int vint = argValue;

                vbs[0] = (byte)(vint / t3);
                vint = vint % t3;

                vbs[1] = (byte)(vint / t2);
                vint = vint % t2;

                vbs[2] = (byte)(vint / t1);
                vint = vint % t1;

                vbs[3] = (byte)(vint);
            }
            else
            {
                int vminusint = Math.Abs(argValue + 1);
                var vminusbs = GetBytes(vminusint);
                vbs[0] = (byte)(255 - vminusbs[0]);
                vbs[1] = (byte)(255 - vminusbs[1]);
                vbs[2] = (byte)(255 - vminusbs[2]);
                vbs[3] = (byte)(255 - vminusbs[3]);
            }

            return vbs;
        }

        /// <summary>Byte[] -> Int32</summary>
        private static Int32 GetInt32(byte[] argValue)
        {
            if (argValue.Length == 4)
            {
                const int t3 = 256 * 256 * 256;
                const int t2 = 256 * 256;
                const int t1 = 256;

                if (argValue[0] <= 127)
                {
                    int[] vis = { 0, 0, 0, 0 };
                    vis[0] = argValue[0] * t3;
                    vis[1] = argValue[1] * t2;
                    vis[2] = argValue[2] * t1;
                    vis[3] = argValue[3];
                    int vr = vis[0] + vis[1] + vis[2] + vis[3];
                    return vr;
                }
                else
                {
                    if ((argValue[0] == 128) && (argValue[1] == 0) && (argValue[2] == 0) && (argValue[3] == 0))
                    {
                        return int.MinValue;
                    }
                    else
                    {
                        var vbs = new byte[4];
                        vbs[0] = (byte)(255 - argValue[0]);
                        vbs[1] = (byte)(255 - argValue[1]);
                        vbs[2] = (byte)(255 - argValue[2]);
                        vbs[3] = (byte)(255 - argValue[3]);
                        int vminusint = 0 - 1 - GetInt32(vbs);
                        return vminusint;
                    }
                }
            }
            return 0;
        }

        /// <summary>Byte[] -> Base64</summary>
        public static string ToBase64(byte[] argBytes)
        {
            var vnull = "";
            if (argBytes.Length < 1) return vnull;
            try { return Convert.ToBase64String(argBytes); }
            catch { return vnull; }
        }

        /// <summary>Base64 -> Byte[]</summary>
        public static byte[] FromBase64(string argBase64)
        {
            var vnull = Constant.EmptyBytes;
            if (string.IsNullOrEmpty(argBase64)) return vnull;
            try { return Convert.FromBase64String(argBase64); }
            catch { return vnull; }
        }

        /// <summary>创建数组,元素值为零。</summary>
        public static byte[] ZeroArray(int argCount)
        {
            if (argCount < 1) return Constant.EmptyBytes;
            var ba = new Byte[argCount];
            for (int i = 0; i < argCount; i++) ba[i] = 0;
            return ba;
        }

    }

}