content: /*
   ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
   ~                                                                               ~
   ~ The MIT License (MIT)                                                         ~
   ~                                                                               ~
   ~ Copyright (c) 2015-2025 miaixz.org and other contributors.                    ~
   ~                                                                               ~
   ~ Permission is hereby granted, free of charge, to any person obtaining a copy  ~
   ~ of this software and associated documentation files (the "Software"), to deal ~
   ~ in the Software without restriction, including without limitation the rights  ~
   ~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell     ~
   ~ copies of the Software, and to permit persons to whom the Software is         ~
   ~ furnished to do so, subject to the following conditions:                      ~
   ~                                                                               ~
   ~ The above copyright notice and this permission notice shall be included in    ~
   ~ all copies or substantial portions of the Software.                           ~
   ~                                                                               ~
   ~ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR    ~
   ~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,      ~
   ~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE   ~
   ~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER        ~
   ~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ~
   ~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN     ~
   ~ THE SOFTWARE.                                                                 ~
   ~                                                                               ~
   ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
  */
  package org.miaixz.bus.core.data.id;
  
  import java.io.Serial;
  import java.security.MessageDigest;
  import java.security.NoSuchAlgorithmException;
  import java.security.SecureRandom;
  import java.util.Random;
  
  import org.miaixz.bus.core.codec.No128;
  import org.miaixz.bus.core.lang.Symbol;
  import org.miaixz.bus.core.xyz.RandomKit;
  import org.miaixz.bus.core.xyz.StringKit;
  
  /**
   * 提供通用唯一识别码（universally unique identifier）（UUID）实现，UUID表示一个128位的值。 此类拷贝自java.util.UUID，用于生成不带-的UUID字符串
   * <ul>
   * <li>Generate UUID 不同版本UUID在线生成和参考：<a href="https://idtools.co/uuid/v4">Generate UUID</a></li>
   * <li>UUID 的 5 个版本：<a href="https://juejin.cn/post/7297225106203689001">UUID 5 version 区别</a></li>
   * <li>UUID代码实现参考：<a href="https://github.com/sake/uuid4j">sake/uuid4j实现</a></li>
   * </ul>
   * <ul>
   * <li>UUIDv1: Structure,形如：xxxxxxxx-xxxx-1xxx-yxxx-xxxxxxxxxxxx，UUID v1 表示为 32 个字符的十六进制字符串，分五组显示，并用连字符分隔;
   * <strong>基于时间</strong>，同时访问主机的 MAC 地址； generate a time based UUID (V1)</li>
   * <li>UUIDv2: Structure,形如：xxxxxxxx-xxxx-2xxx-yxxx-xxxxxxxxxxxx，UUID v2 的结构与其他 UUID 相同;需要<strong> DCE–分布式计算机环境
   * </strong>生成唯一标识符;由于基于计算主机名，有隐私风险，未大规模使用</li>
   * <li>UUIDv3: Structure,形如：xxxxxxxx-xxxx-3xxx-yxxx-xxxxxxxxxxxx，UUID v3 的结构与其他 UUID 相同;需要<strong> 基于命名·使用MD5哈希加密
   * </strong>生成唯一标识符;</li>
   * <li>UUIDv4: Structure,形如：xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx，UUID v4 的结构与其他 UUID
   * 相同,<strong>使用最多的版本</strong>，使用<strong>随机数生成</strong>。 默认实现都是该版本； generate a random UUID (V4)</li>
   * <li>UUIDv5: Structure,形如：xxxxxxxx-xxxx-5xxx-yxxx-xxxxxxxxxxxx，UUID v5 的结构与其他 UUID 相同,需要根据<strong> 基于命名·使用SHA-1哈希加密
   * </strong>生成唯一标识符； generate name based UUID with SHA1 hashing (v5)</li>
   * <li>UUIDv6: Structure,形如：xxxxxxxx-xxxx-6xxx-yxxx-xxxxxxxxxxxx，UUID v6 的结构与其他 UUID 相同,<strong>与 UUIDv1
   * 的字段兼容版本</strong>,<strong>结合 UUIDv1 和 UUIDv4 的优点</strong>，确保基于时间的自然排序和更好的隐私;</li>
   * <li>UUIDv7: Structure,形如：xxxxxxxx-xxxx-7xxx-yxxx-xxxxxxxxxxxx，UUID v7 的结构与其他 UUID 相同,提供了从 <strong>Unix Epoch
   * 时间戳</strong>派生的时间排序值，以及改进的熵特性。如果可能，<strong>建议使用版本 1 和 6</strong>； generate a ordered time based UUID (V7)</li>
   * </ul>
   * version 字段保存描述此 UUID 类型的值。有 7 种不同的基本 UUID 类型：基于时间的 UUIDv1、DCE 安全 UUIDv2、基于名称的 UUIDv3 、随机生成的 UUIDv4、基于名称的SHA-1算法的
   * UUIDv5、基于时间的随机生成的 UUIDv6 和 基于时间戳的 UUIDv7。 这些类型的 version 值分别为 1、2、3、4、5、6 和 7。最常用的V4 这些通用标识符具有不同的变体。此类的方法用于操作
   * Leach-Salz 变体，不过构造方法允许创建任何 UUID 变体（将在下面进行描述）。 变体 2 (Leach-Salz) UUID 的布局如下： long 型数据的最高有效位由以下无符号字段组成：
   * 
   * <pre>
   * 0xFFFFFFFF00000000 time_low
   * 0x00000000FFFF0000 time_mid
   * 0x000000000000F000 version
   * 0x0000000000000FFF time_hi
   * </pre>
   * 
   * long 型数据的最低有效位由以下无符号字段组成：
   * 
   * <pre>
   * 0xC000000000000000 variant
   * 0x3FFF000000000000 clock_seq
   * 0x0000FFFFFFFFFFFF node
   * </pre>
   * 
   * variant 字段包含一个表示 UUID 布局的值。以上描述的位布局仅在 UUID 的 variant 值为 2（表示 Leach-Salz 变体）时才有效。
   *
   * @author Kimi Liu
   * @since Java 17+
   */
  public class UUID implements java.io.Serializable, Comparable<UUID> {
  
      @Serial
      private static final long serialVersionUID = 2852276107807L;
  
      private final No128 idValue;
  
      /**
       * 私有构造
       *
       * @param data 数据
       */
      private UUID(final byte[] data) {
          long msb = 0;
          long lsb = 0;
          assert data.length == 16 : "data must be 16 bytes in length";
          for (int i = 0; i < 8; i++) {
              msb = (msb << 8) | (data[i] & 0xff);
          }
          for (int i = 8; i < 16; i++) {
              lsb = (lsb << 8) | (data[i] & 0xff);
          }
          this.idValue = new No128(msb, lsb);
      }
  
      /**
       * 使用指定的数据构造新的 UUID。
       *
       * @param mostSigBits  用于 {@code UUID} 的最高有效 64 位
       * @param leastSigBits 用于 {@code UUID} 的最低有效 64 位
       */
      public UUID(final long mostSigBits, final long leastSigBits) {
          this.idValue = new No128(mostSigBits, leastSigBits);
      }
  
      /**
       * 获取类型 4 UUIDv4（伪随机生成的）UUID 的静态工厂。 使用加密的本地线程伪随机数生成器生成该 UUID。
       *
       * @return 随机生成的 {@code UUID}
       */
      public static UUID fastUUID() {
          return randomUUID(false);
      }
  
      /**
       * 获取类型 4 UUIDv4（伪随机生成的）UUID 的静态工厂。 使用加密的强伪随机数生成器生成该 UUID。
       *
       * @return 随机生成的 {@code UUID}
       */
      public static UUID randomUUID() {
          return randomUUID(true);
      }
  
      /**
       * 获取类型 4 UUIDv4（伪随机生成的）UUID 的静态工厂。 使用加密的强伪随机数生成器生成该 UUID。
       *
       * @param isSecure 是否使用{@link SecureRandom}如果是可以获得更安全的随机码，否则可以得到更好的性能
       * @return 随机生成的 {@code UUID}
       */
      public static UUID randomUUID(final boolean isSecure) {
          return randomUUID(isSecure ? Holder.NUMBER_GENERATOR : RandomKit.getRandom());
      }
  
      /**
       * 获取类型 4 UUIDv4（伪随机生成的）UUID 的静态工厂。 使用加密的强伪随机数生成器生成该 UUID。
       *
       * @param random 随机数生成器
       * @return 随机生成的 {@code UUID}
       */
      public static UUID randomUUID(final Random random) {
          final byte[] randomBytes = RandomKit.randomBytes(16, random);
  
          randomBytes[6] &= 0x0f; /* clear version */
          randomBytes[6] |= 0x40; /* set to version 4 */
          randomBytes[8] &= 0x3f; /* clear variant */
          randomBytes[8] |= (byte) 0x80; /* set to IETF variant */
  
          return new UUID(randomBytes);
      }
  
      /**
       * 根据指定的字节数组获取类型 3 UUIDv3（基于名称的·使用MD5哈希加密）UUID 的静态工厂。
       *
       * @param name 用于构造 UUID 的字节数组。
       * @return 根据指定数组生成的 {@code UUID}
       */
      public static UUID nameUUIDFromBytes(final byte[] name) {
          final MessageDigest md;
          try {
              md = MessageDigest.getInstance("MD5");
          } catch (final NoSuchAlgorithmException nsae) {
              throw new InternalError("MD5 not supported");
          }
          final byte[] md5Bytes = md.digest(name);
          md5Bytes[6] &= 0x0f; /* clear version */
          md5Bytes[6] |= 0x30; /* set to version 3 */
          md5Bytes[8] &= 0x3f; /* clear variant */
          md5Bytes[8] |= (byte) 0x80; /* set to IETF variant */
          return new UUID(md5Bytes);
      }
  
      /**
       * 根据 {@link #toString()} 方法中描述的字符串标准表示形式创建{@code UUID}。
       *
       * @param name 指定 {@code UUID} 字符串
       * @return 具有指定值的 {@code UUID}
       * @throws IllegalArgumentException 如果 name 与 {@link #toString} 中描述的字符串表示形式不符抛出此异常
       */
      public static UUID fromString(final String name) {
          final String[] components = name.split(Symbol.MINUS);
          if (components.length != 5) {
              throw new IllegalArgumentException("Invalid UUID string: " + name);
          }
          for (int i = 0; i < 5; i++) {
              components[i] = "0x" + components[i];
          }
  
          long mostSigBits = Long.decode(components[0]);
          mostSigBits <<= 16;
          mostSigBits |= Long.decode(components[1]);
          mostSigBits <<= 16;
          mostSigBits |= Long.decode(components[2]);
  
          long leastSigBits = Long.decode(components[3]);
          leastSigBits <<= 48;
          leastSigBits |= Long.decode(components[4]);
  
          return new UUID(mostSigBits, leastSigBits);
      }
  
      /**
       * 返回指定数字对应的hex值
       *
       * @param val    值
       * @param digits 位
       * @return 值
       */
      private static String digits(final long val, final int digits) {
          final long hi = 1L << (digits * 4);
          return Long.toHexString(hi | (val & (hi - 1))).substring(1);
      }
  
      /**
       * 返回此 UUID 的 128 位值中的最低有效 64 位。
       *
       * @return 此 UUID 的 128 位值中的最低有效 64 位。
       */
      public long getLeastSignificantBits() {
          return this.idValue.getLeastSigBits();
      }
  
      /**
       * 返回此 UUID 的 128 位值中的最高有效 64 位。
       *
       * @return 此 UUID 的 128 位值中最高有效 64 位。
       */
      public long getMostSignificantBits() {
          return this.idValue.getMostSigBits();
      }
  
      /**
       * 与此 {@code UUID} 相关联的版本号. 版本号描述此 {@code UUID} 是如何生成的。 版本号具有以下含意:
       * <ul>
       * <li>UUIDv1 基于时间的 UUID
       * <li>UUIDv2 DCE 安全 UUID
       * <li>UUIDv3 基于名称的MD5散列算法的 UUID
       * <li>UUIDv4 随机生成的 UUID
       * <li>UUIDv5 基于名称的SHA-1散列算法的 UUID
       * <li>UUIDv6 基于时间的随机生成的 UUID （UUIDv1 + UUIDv4）
       * <li>UUIDv7 基于时间戳Unix epoch的 UUID
       * </ul>
       *
       * @return 此 {@code UUID} 的版本号
       */
      public int version() {
          // Version is bits masked by 0x000000000000F000 in MS long
          return (int) ((this.getMostSignificantBits() >> 12) & 0x0f);
      }
  
      /**
       * 与此 {@code UUID} 相关联的变体号。变体号描述 {@code UUID} 的布局。 变体号具有以下含意：
       * <ul>
       * <li>0 为 NCS 向后兼容保留
       * <li>2 <a href="http://www.ietf.org/rfc/rfc4122.txt">IETF&nbsp;RFC&nbsp;4122</a>(Leach-Salz), 用于此类
       * <li>6 保留，微软向后兼容
       * <li>7 保留供以后定义使用
       * </ul>
       *
       * @return 此 {@code UUID} 相关联的变体号
       */
      public int variant() {
          final long leastSigBits = this.getLeastSignificantBits();
          // This field is composed of a varying number of bits.
          // 0 - - Reserved for NCS backward compatibility
          // 1 0 - The IETF aka Leach-Salz variant (used by this class)
          // 1 1 0 Reserved, Microsoft backward compatibility
          // 1 1 1 Reserved for future definition.
          return (int) ((leastSigBits >>> (64 - (leastSigBits >>> 62))) & (leastSigBits >> 63));
      }
  
      /**
       * 与此 UUID 相关联的时间戳值。 60 位的时间戳值根据此 {@code UUID} 的 time_low、time_mid 和 time_hi 字段构造。 所得到的时间戳以 100 毫微秒为单位，从 UTC（通用协调时间）
       * 1582 年 10 月 15 日零时开始。 时间戳值仅在在基于时间的 UUID（其 version 类型为 1）中才有意义。 如果此 {@code UUID} 不是基于时间的 UUID，则此方法抛出
       * UnsupportedOperationException。
       *
       * @return 时间戳值
       * @throws UnsupportedOperationException 如果此 {@code UUID} 不是 version 为 1 的 UUID。
       */
      public long timestamp() throws UnsupportedOperationException {
          final long mostSigBits = this.getMostSignificantBits();
          checkTimeBase();
          return (mostSigBits & 0x0FFFL) << 48//
                  | ((mostSigBits >> 16) & 0x0FFFFL) << 32//
                  | mostSigBits >>> 32;
      }
  
      /**
       * 与此 UUID 相关联的时钟序列值。 14 位的时钟序列值根据此 UUID 的 clock_seq 字段构造。clock_seq 字段用于保证在基于时间的 UUID 中的时间唯一性。 {@code clockSequence}
       * 值仅在基于时间的 UUID（其 version 类型为 1）中才有意义。 如果此 UUID 不是基于时间的 UUID，则此方法抛出 UnsupportedOperationException。
       *
       * @return 此 {@code UUID} 的时钟序列
       * @throws UnsupportedOperationException 如果此 UUID 的 version 不为 1
       */
      public int clockSequence() throws UnsupportedOperationException {
          checkTimeBase();
          return (int) ((this.getLeastSignificantBits() & 0x3FFF000000000000L) >>> 48);
      }
  
      /**
       * 与此 UUID 相关的节点值。 48 位的节点值根据此 UUID 的 node 字段构造。此字段旨在用于保存机器的 IEEE 802 地址，该地址用于生成此 UUID 以保证空间唯一性。 节点值仅在基于时间的 UUID（其
       * version 类型为 1）中才有意义。 如果此 UUID 不是基于时间的 UUID，则此方法抛出 UnsupportedOperationException。
       *
       * @return 此 {@code UUID} 的节点值
       * @throws UnsupportedOperationException 如果此 UUID 的 version 不为 1
       */
      public long node() throws UnsupportedOperationException {
          checkTimeBase();
          return this.getLeastSignificantBits() & 0x0000FFFFFFFFFFFFL;
      }
  
      /**
       * 返回此{@code UUID} 的字符串表现形式。 UUID 的字符串表示形式由此 BNF 描述：
       *
       * <pre>
       * {@code
       * UUID                   = <time_low>-<time_mid>-<time_high_and_version>-<variant_and_sequence>-<node>
       * time_low               = 4*<hexOctet>
       * time_mid               = 2*<hexOctet>
       * time_high_and_version  = 2*<hexOctet>
       * variant_and_sequence   = 2*<hexOctet>
       * node                   = 6*<hexOctet>
       * hexOctet               = <hexDigit><hexDigit>
       * hexDigit               = [0-9a-fA-F]
       * }
       * </pre>
       *
       * @return 此{@code UUID} 的字符串表现形式
       * @see #toString(boolean)
       */
      @Override
      public String toString() {
          return toString(false);
      }
  
      /**
       * 返回此{@code UUID} 的字符串表现形式。 UUID 的字符串表示形式由此 BNF 描述：
       *
       * <pre>
       * {@code
       * UUID                   = <time_low>-<time_mid>-<time_high_and_version>-<variant_and_sequence>-<node>
       * time_low               = 4*<hexOctet>
       * time_mid               = 2*<hexOctet>
       * time_high_and_version  = 2*<hexOctet>
       * variant_and_sequence   = 2*<hexOctet>
       * node                   = 6*<hexOctet>
       * hexOctet               = <hexDigit><hexDigit>
       * hexDigit               = [0-9a-fA-F]
       * }
       * </pre>
       *
       * @param isSimple 是否简单模式，简单模式为不带'-'的UUID字符串
       * @return 此{@code UUID} 的字符串表现形式
       */
      public String toString(final boolean isSimple) {
          final long mostSigBits = this.getLeastSignificantBits();
          final long leastSigBits = this.getLeastSignificantBits();
  
          final StringBuilder builder = StringKit.builder(isSimple ? 32 : 36);
          // time_low
          builder.append(digits(mostSigBits >> 32, 8));
          if (!isSimple) {
              builder.append(Symbol.C_MINUS);
          }
          // time_mid
          builder.append(digits(mostSigBits >> 16, 4));
          if (!isSimple) {
              builder.append(Symbol.C_MINUS);
          }
          // time_high_and_version
          builder.append(digits(mostSigBits, 4));
          if (!isSimple) {
              builder.append(Symbol.C_MINUS);
          }
          // variant_and_sequence
          builder.append(digits(leastSigBits >> 48, 4));
          if (!isSimple) {
              builder.append(Symbol.C_MINUS);
          }
          // node
          builder.append(digits(leastSigBits, 12));
  
          return builder.toString();
      }
  
      /**
       * 返回此 UUID 的哈希码。
       *
       * @return UUID 的哈希码值。
       */
      @Override
      public int hashCode() {
          final long hilo = this.getLeastSignificantBits() ^ this.getMostSignificantBits();
          return ((int) (hilo >> 32)) ^ (int) hilo;
      }
  
      /**
       * 将此对象与指定对象比较。 当且仅当参数不为 {@code null}、而是一个 UUID 对象、具有与此 UUID 相同的 varriant、包含相同的值（每一位均相同）时，结果才为 {@code true}。
       *
       * @param object 要与之比较的对象
       * @return 如果对象相同，则返回 {@code true}；否则返回 {@code false}
       */
      @Override
      public boolean equals(final Object object) {
          if ((null == object) || (object.getClass() != UUID.class)) {
              return false;
          }
          final UUID id = (UUID) object;
  
          final long mostSigBits = this.getLeastSignificantBits();
          final long leastSigBits = this.getLeastSignificantBits();
          return (mostSigBits == id.getMostSignificantBits() && leastSigBits == id.getLeastSignificantBits());
      }
  
      /**
       * 将此 UUID 与指定的 UUID 比较。 如果两个 UUID 不同，且第一个 UUID 的最高有效字段大于第二个 UUID 的对应字段，则第一个 UUID 大于第二个 UUID。
       *
       * @param val 与此 UUID 比较的 UUID
       * @return 在此 UUID 小于、等于或大于 val 时，分别返回 -1、0 或 1。
       */
      @Override
      public int compareTo(final UUID val) {
          // The ordering is intentionally set up so that the UUIDs
          // can simply be numerically compared as two numbers
          int compare = Long.compare(this.getMostSignificantBits(), val.getMostSignificantBits());
          if (0 == compare) {
              compare = Long.compare(this.getLeastSignificantBits(), val.getLeastSignificantBits());
          }
          return compare;
      }
  
      /**
       * 检查是否为time-based版本UUID
       */
      private void checkTimeBase() {
          if (version() != 1) {
              throw new UnsupportedOperationException("Not a time-based UUID");
          }
      }
  
      /**
       * {@link SecureRandom} 的单例
       */
      private static class Holder {
  
          static final SecureRandom NUMBER_GENERATOR = RandomKit.getSecureRandom();
      }
  
  }
  