using System;
using System.Threading;

namespace AX.Network.Common
{
    /// <summary>
    /// 该类可以生成 64 位全局唯一 ID,适合在分布式服务器集群中产生唯一 ID。
    /// </summary>
    /// <remarks>
    /// 该类生成的 ID 比 System.Guid 节省一倍空间。支持每秒生成 1048576 个不重复的 ID。
    /// 它由 时间戳 + 大区号 + 小区号 + 本地递增序号 组成。
    /// 时间戳:    32bit
    /// 大区号:    4bit
    /// 小区号:    8bit
    /// 递增序号: 20bit
    /// 即支持大区 16 个,每个大区下支持 256 个小区,每个小区里支持每秒生成 1048576 个唯一 ID。
    /// </remarks>
    public static class GUID
    {
        private static ulong TimestampMask = 0xffffffff00000000;    //时间戳掩码
        private static ulong BigMask = 0x00000000f0000000;          //大区号掩码
        private static ulong SmallMask = 0x000000000ff00000;        //小区号掩码
        private static ulong BaseMask = 0x00000000000fffff;         //本地 ID 编号掩码
        private static int BaseId = 0;                              //本地 ID

        private static readonly DateTime Jan1st1970 = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
        private static readonly DateTime BaseTime = DateTime.Now;

        /// <summary>
        /// 根据大区号和小区号生成 ID。
        /// </summary>
        public static ulong NewGuid(uint big, uint small)
        {
            ulong timeStamp = (ulong)(DateTime.UtcNow - Jan1st1970).TotalSeconds;

            ulong newId = ((timeStamp << 32) & TimestampMask) |
                            ((big << 28) & BigMask) |
                            ((small << 20) & SmallMask) |
                            ((uint)BaseId & BaseMask);

            Interlocked.Increment(ref BaseId);

            return newId;
        }

        /// <summary>
        /// 获得 Id。
        /// </summary>
        public static long NewGuid()
        {
            return (long)(NewGuid(15, 255)) + (DateTime.Now - BaseTime).Ticks;
        }
    }
}