using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Security.Cryptography;
using System.Globalization;
using System.Runtime.InteropServices;
using System.Collections;

namespace CommonLang
{
    public static class CUtils
    {

        public static readonly Encoding UTF8 = new UTF8Encoding(false, false);
        public static readonly Encoding UTF8_BOM = new UTF8Encoding(true, false);

        //本地时间戳,线程阻塞不是特别准确的,
        public static long localTimeMS = 0;
		public static long S_LOCAL_TIMESTAMPMS = 0;			//本地时间戳

        public static long CurrentTimeMS
        {
            get { return System.DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond; }
        }

        public static void Swap<T>(ref T a, ref T b)
        {
            T ta = a;
            a = b;
            b = ta;
        }

        public static IntPtr ToIntPtr(object obj)
        {
            if (obj == null)
            {
                return new IntPtr(0);
            }
            GCHandle hObject = GCHandle.Alloc(obj, GCHandleType.Pinned);
            IntPtr pObject = hObject.AddrOfPinnedObject();
            if (hObject.IsAllocated)
                hObject.Free();
            return pObject;
        }

        public static bool RandomPercent(Random random, float percent)
        {
            //大于等于 0.0 并且小于 1.0 的双精度浮点数。//
            if (random.NextDouble() * 100f < percent)
            {
                return true;
            }
            return false;
        }

        public static float RandomFactor(Random random, float value, float factor)
        {
            if (factor == 0)
            {
                return value;
            }
            return value + value * (float)(factor / 2f + random.NextDouble() * factor);
        }


        public static T RandomEnumValue<T>(Random random)
        {
            Array values = Enum.GetValues(typeof(T));
            int count = values.Length;
            if (count > 0)
            {
                var ret = values.GetValue(random.Next(0, count));
                return (T)ret;
            }
            return default(T);
        }

        #region CLONE

        public static T TryClone<T>(T src) where T : class, ICloneable
        {
            if (src == null) return null;
            return (T)src.Clone();
        }

        public static T[] CloneArray<T>(T[] src)
            where T : class, ICloneable
        {
            if (src == null) return null;
            T[] ret = new T[src.Length];
            for (int i = 0; i < src.Length; i++)
            {
                if (src[i] != null)
                {
                    ret[i] = (T)src[i].Clone();
                }
                else
                {
                    ret[i] = null;
                }
            }
            return ret;
        }

        public static List<T> CloneList<T>(IList<T> src)
            where T : class, ICloneable
        {
            if (src == null) return null;
            List<T> ret = new List<T>(src.Count);
            for (int i = 0; i < src.Count; i++)
            {
                if (src[i] != null)
                {
                    ret.Add((T)src[i].Clone());
                }
                else
                {
                    ret.Add(null);
                }
            }
            return ret;
        }

        public static Dictionary<K, V> CloneMap<K, V>(IDictionary<K, V> map)
            where V : ICloneable
        {
            if (map == null) return null;
            Dictionary<K, V> ret = new Dictionary<K, V>(map.Count);
            foreach (K k in map.Keys)
            {
                ret.Add(k, (V)ret[k].Clone());
            }
            return ret;
        }

        #endregion

        #region STRING

        public static string DecodeUTF8(byte[] data)
        {
            if (data.Length > 3)
            {
                if ((data[0] == 0xEF) && (data[1] == 0xBB) && (data[2] == 0xBF))
                {
                    return UTF8_BOM.GetString(data);
                }
            }
            return UTF8.GetString(data);
        }

        public static string ToHexString(byte[] data)
        {
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < data.Length; i++)
            {
                byte d = data[i];
                sb.Append(d.ToString("x2"));
            }
            return sb.ToString();
        }

        public static string BinToHex(byte[] bin)
        {
            StringBuilder hexdata = new StringBuilder();
            for (int i = 0; i < bin.Length; i++)
            {
                string hex = bin[i].ToString("X2");
                if (hex.Length < 2)
                {
                    hexdata.Append("0" + hex);
                }
                else if (hex.Length == 2)
                {
                    hexdata.Append(hex);
                }
            }
            return hexdata.ToString();
        }

        public static byte[] HexToBin(string hex)
        {
            if (hex.Length % 2 != 0)
            {
                hex = "0" + hex;
            }
            int count = hex.Length;
            byte[] os = new byte[count / 2 + 1];
            for (int i = 0; i < count; i += 2)
            {
                string hch = hex.Substring(i, 2);
                byte read = byte.Parse(hch, NumberStyles.AllowHexSpecifier);
                os[i / 2] = read;
            }
            return os;
        }

        public static string ToBytesSizeString(long bytes)
        {
            long b = bytes;
            long kb = b >> 10;
            long mb = kb >> 10;
            long gb = mb >> 10;
            long tb = gb >> 10;

            if (tb > 10)
            {
                return tb + "." + gb % 1024 + "t";
            }
            if (gb > 10)
            {
                return gb + "." + mb % 1024 + "g";
            }
            if (mb > 10)
            {
                return mb + "." + kb % 1024 + "m";
            }
            if (kb > 10)
            {
                return kb + "." + b % 1024 + "k";
            }

            return b + "b";

        }

        public static string ListToString(IList list, string split = ", ", string prefix = "", string suffix = "")
        {
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < list.Count; i++)
            {
                object obj = list[i];
                sb.Append(prefix + obj);
                if (i < list.Count - 1)
                {
                    sb.Append(split);
                }
                sb.Append(suffix);
            }
            return sb.ToString();
        }
        public static string MapToString(IDictionary list, string kv_split = "=", string line_split = "\n", string prefix = "", string suffix = "")
        {
            StringBuilder sb = new StringBuilder();
            int i = 0;
            foreach (object key in list.Keys)
            {
                object obj = list[key];
                sb.Append(prefix + key + kv_split + obj + suffix);
                if (i < list.Count - 1)
                {
                    sb.Append(line_split);
                }
                i++;
            }
            return sb.ToString();
        }
        public static string ArrayToString(Array list, string split = ", ", string prefix = "", string suffix = "")
        {
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < list.Length; i++)
            {
                object obj = list.GetValue(i);
                sb.Append(prefix + obj);
                if (i < list.Length - 1)
                {
                    sb.Append(split);
                }
                sb.Append(suffix);
            }
            return sb.ToString();
        }


        /// <summary>
        /// 
        /// </summary>
        /// <param name="time"></param>
        /// <param name="format">YYMMDD_hhmmss</param>
        /// <returns></returns>
        public static string FormatTime(DateTime time, string format = "YYMMDD_hhmmss")
        {
            format = format.Replace("YY", time.Year.ToString("d4"));
            format = format.Replace("MM", time.Month.ToString("d2"));
            format = format.Replace("DD", time.Day.ToString("d2"));
            format = format.Replace("hh", time.Hour.ToString("d2"));
            format = format.Replace("mm", time.Minute.ToString("d2"));
            format = format.Replace("ss", time.Second.ToString("d2"));
            return format;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="seconds"></param>
        /// <param name="format">hhmmss</param>
        /// <returns></returns>
        public static string FormatTime(int seconds, string format = "hh:mm:ss")
        {
            format = format.Replace("hh", (seconds / 60 / 60).ToString());
            format = format.Replace("mm", (seconds / 60 % 60).ToString("d2"));
            format = format.Replace("ss", (seconds % 60).ToString("d2"));
            return format;
        }

        #endregion


        #region ARRAY_AND_COLLECTIONS

        public static IList<T> RemoveAll<T>(IList<T> src, ICollection<T> list)
        {
            if (list.Count > 0)
            {
                for (int i = src.Count - 1; i >= 0; i--)
                {
                    T e = src[i];
                    if (e != null && list.Contains(e))
                    {
                        src.RemoveAt(i);
                    }
                }
            }
            return src;
        }

        public static void RandomList<T>(Random random, IList<T> src)
        {
            for (int i = src.Count - 1; i >= 0; i--)
            {
                int r = random.Next(0, src.Count);
                T t = src[r];
                src[r] = src[i];
                src[i] = t;
            }
        }
        public static void RandomArray<T>(Random random, T[] src)
        {
            for (int i = src.Length - 1; i >= 0; i--)
            {
                int r = random.Next(0, src.Length);
                T t = src[r];
                src[r] = src[i];
                src[i] = t;
            }
        }
        public static T[] ArrayLink<T>(T[] a, params T[] b)
        {
            T[] dst = new T[a.Length + b.Length];
            Array.Copy(a, 0, dst, 0, a.Length);
            Array.Copy(b, 0, dst, a.Length, b.Length);
            return dst;
        }

        public static void ArrayCopy<T>(ICollection<T> src, Queue<T> dst)
        {
            foreach (T t in src)
            {
                dst.Enqueue(t);
            }
        }
        public static void ArrayCopy<T>(ICollection<T> src, ICollection<T> dst)
        {
            foreach (T t in src)
            {
                dst.Add(t);
            }
        }

        public static bool ArraysEqual<T>(T[] a1, T[] a2)
        {
            if (ReferenceEquals(a1, a2))
                return true;

            if (a1 == null || a2 == null)
                return false;

            if (a1.Length != a2.Length)
                return false;

            EqualityComparer<T> comparer = EqualityComparer<T>.Default;
            for (int i = 0; i < a1.Length; i++)
            {
                if (!comparer.Equals(a1[i], a2[i])) return false;
            }
            return true;
        }

        public static T GetRandomInArray<T>(IList<T> list, Random random)
        {
            if (list.Count == 0) return default(T);
            int rd = random.Next(list.Count);
            return list[rd];
        }

        public static T GetRandomInArray<T>(T[] list, Random random)
        {
            if (list.Length == 0) return default(T);
            int rd = random.Next(list.Length);
            return list[rd];
        }


        public static int[] GetArrayRanges(Array array)
        {
            Type type = array.GetType();
            int rank = type.GetArrayRank();
            int[] ranges = new int[rank];
            for (int i = 0; i < rank; i++)
            {
                ranges[i] = array.GetLength(i);
            }
            return ranges;
        }

        public static int[] GetArrayRankIndex(int[] ranks, int total_index)
        {
            int[] ret = new int[ranks.Length];
            if (ranks.Length == 1)
            {
                ret[0] = total_index;
                return ret;
            }
            if (ranks.Length == 2)
            {
                ret[0] = total_index / ranks[1];
                ret[1] = total_index % ranks[1];
                return ret;
            }
            if (ranks.Length == 3)
            {
                ret[0] = total_index / ranks[2] / ranks[1];
                ret[1] = total_index / ranks[2] % ranks[1];
                ret[2] = total_index % ranks[2];
                return ret;
            }
            if (ranks.Length == 4)
            {
                ret[0] = total_index / ranks[3] / ranks[2] / ranks[1];
                ret[1] = total_index / ranks[3] / ranks[2] % ranks[1];
                ret[2] = total_index / ranks[3] % ranks[2];
                ret[3] = total_index % ranks[3];
                return ret;
            }
            return GetArrayIndex(ranks, total_index);
        }

        public static int GetArrayTotalIndex(int[] ranks, params int[] indices)
        {
            int total_index = 0;
            if (ranks.Length == 1)
            {
                total_index = indices[0];
                return total_index;
            }
            if (ranks.Length == 2)
            {
                total_index += indices[0] * ranks[1];
                total_index += indices[1];
                return total_index;
            }
            if (ranks.Length == 3)
            {
                total_index += indices[0] * ranks[2] * ranks[1];
                total_index += indices[1] * ranks[2];
                total_index += indices[2];
                return total_index;
            }
            if (ranks.Length == 4)
            {
                total_index += indices[0] * ranks[3] * ranks[2] * ranks[1];
                total_index += indices[1] * ranks[3] * ranks[2];
                total_index += indices[2] * ranks[3];
                total_index += indices[3];
                return total_index;
            }
            return GetArrayIndex(ranks, indices);
        }


        private static int[] GetArrayIndex(int[] arrayStruct, int index)
        {
            int[] valueArray = new int[arrayStruct.Length];
            int[] tempArray = new int[arrayStruct.Length];

            int[] outIndex = new int[arrayStruct.Length];

            valueArray[arrayStruct.Length - 1] = 1;
            for (int i = arrayStruct.Length - 1 - 1; i >= 0; --i)
            {
                valueArray[i] = arrayStruct[i + 1] * valueArray[i + 1];
            }

            if (index < 0 || index > valueArray[0] * arrayStruct[0])
                throw new Exception(" Array Out of index " + index);

            outIndex[0] = index / valueArray[0];
            tempArray[0] = outIndex[0] * valueArray[0];

            for (int i = 1; i < arrayStruct.Length; ++i)
            {
                outIndex[i] = (index - tempArray[i - 1]) / valueArray[i];
                tempArray[i] = tempArray[i - 1] + outIndex[i] * valueArray[i];
            }

            return outIndex;
        }

        private static int GetArrayIndex(int[] arrayStruct, int[] arrayIndex)
        {
            int index = 0;

            int[] valueArray = new int[arrayStruct.Length];

            valueArray[arrayStruct.Length - 1] = 1;
            for (int i = arrayStruct.Length - 1 - 1; i >= 0; --i)
            {
                valueArray[i] = arrayStruct[i + 1] * valueArray[i + 1];
            }

            for (int i = 0; i < arrayStruct.Length; ++i)
            {
                index += valueArray[i] * arrayIndex[i];
            }

            return index;
        }

        public static T GetMinOrMax<T>(T[] array, int index)
        {
            if (array.Length > 0)
            {
                if (index < 0)
                {
                    return array[0];
                }
                if (index >= array.Length)
                {
                    return array[array.Length - 1];
                }
                return array[index];
            }
            return default(T);
        }

        public static T GetMinOrMax<T>(IList<T> array, int index)
        {
            if (array.Count > 0)
            {
                if (index < 0)
                {
                    return array[0];
                }
                if (index >= array.Count)
                {
                    return array[array.Count - 1];
                }
                return array[index];
            }
            return default(T);
        }



        public delegate bool TestRemove<T>(T data);

        public static void RemoveAll<T>(LinkedList<T> list, TestRemove<T> test)
        {
            if (list.Count > 0)
            {
                List<LinkedListNode<T>> removed = null;
                for (LinkedListNode<T> it = list.Last; it != null; it = it.Previous)
                {
                    T t = it.Value;
                    if (test(t))
                    {
                        if (removed == null)
                        {
                            removed = new List<LinkedListNode<T>>(2);
                        }
                        removed.Add(it);
                    }
                }
                if (removed != null)
                {
                    foreach (LinkedListNode<T> it in removed)
                    {
                        list.Remove(it);
                    }
                }
            }
        }

        public static void RemoveAll<T>(ICollection<T> list, TestRemove<T> test)
        {
            if (list.Count > 0)
            {
                List<T> removed = null;
                foreach (T t in list)
                {
                    if (test(t))
                    {
                        if (removed == null)
                        {
                            removed = new List<T>(2);
                        }
                        removed.Add(t);
                    }
                }
                if (removed != null)
                {
                    for (int i = removed.Count - 1; i >= 0; --i)
                    {
                        list.Remove(removed[i]);
                    }
                }
            }
        }

        public static void RemoveAll<T>(IList<T> list, TestRemove<T> test)
        {
            if (list.Count > 0)
            {
                List<T> removed = null;
                for (int i = list.Count - 1; i >= 0; --i)
                {
                    T t = list[i];
                    if (test(t))
                    {
                        if (removed == null)
                        {
                            removed = new List<T>(2);
                        }
                        removed.Add(t);
                    }
                }
                if (removed != null)
                {
                    for (int i = removed.Count - 1; i >= 0; --i)
                    {
                        list.Remove(removed[i]);
                    }
                }
            }
        }

        public static List<T> ToGenericList<T>(IEnumerable list, int capacity = 0)
        {
            List<T> ret = (capacity > 0) ? new List<T>(capacity) : new List<T>();
            foreach (object obj in list)
            {
                ret.Add((T)obj);
            }
            return ret;
        }

        public static void SetListSize<T>(List<T> list, int length)
        {
            int d = length - list.Count;
            if (d < 0)
            {
                list.RemoveRange(length, -d);
            }
            else if (d > 0)
            {
                for (int i = 0; i < d; i++)
                {
                    list.Add(default(T));
                }
            }
        }


        public static void SwapInList<T>(List<T> list, int i, int j)
        {
            T oi = list[i];
            list[i] = list[j];
            list[j] = oi;
        }

        public static void SwapInArray<T>(T[] array, int i, int j)
        {
            T oi = array[i];
            array[i] = array[j];
            array[j] = oi;
        }

		/** 转换成整数 */
		public static int CastInt(float value)
		{
			if(value < 0)
			{
				return (int)(value - 0.5);
			}

			return (int)(value + 0.5);
		}

		public static int CastInt(double value)
		{
			if (value < 0)
			{
				return (int)(value - 0.5);
			}

			return (int)(value + 0.5);
		}

		#endregion

	}
}