package com.fzm.mall.server.front.util;

import java.util.List;

/**
 * 雪花随机数
 * @author tdz
 * @date 2021/03/02 14:51
 */

public enum IdUtil {
    // 订单编号
    ORDER(8, 8, 8, 6, 6),
    // 申请编号
    APPLY(6, 5, 4, 2, 2),
    // 商品编号
    GOOD(12, 5, 5, 5, 5),
    // 评论编号
    COMMENT(10, 4, 4, 2, 2),
    // 商品评论编号
    GOOD_COMMENT(10, 4, 4, 2, 2),
    // 支付编号
    PAY(8, 10, 8, 4, 4),
    ;

    /**
     * 起始的时间戳
     */
    private final static long START_STAMP = 1480166465631L;

    /**
     * 最大序列号
     */
    private long maxSequence;

    /**
     * 机器标识左移量
     */
    private long machineLeft;
    /**
     * 数据中心左移量
     */
    private long dataCenterLeft;
    /**
     * 时间戳左移量
     */
    private long timestampLeft;
    /**
     * 数据中心
     */
    private long dataCenterId;
    /**
     * 机器标识
     */
    private long machineId;
    /**
     * 序列号
     */
    private long sequence = 0L;
    /**
     * 上一次时间戳
     */
    private long lastStamp = -1L;

    /**
     * @param sequenceBit   序列号占用的位数
     * @param machineBit    机器标识占用的位数
     * @param dataCenterBit 数据中心占用的位数
     * @param dataCenterId  数据中心编号
     * @param machineId     机器标识编号
     */
    IdUtil(long sequenceBit, long machineBit, long dataCenterBit, long dataCenterId, long machineId) {
        this.maxSequence = ~(-1L << sequenceBit);
        this.machineLeft = sequenceBit;
        this.dataCenterLeft = sequenceBit + machineBit;
        this.timestampLeft = dataCenterLeft + dataCenterBit;
        long maxMachineNum = ~(-1L << machineBit);
        long maxDataCenterNum = ~(-1L << dataCenterBit);
        if (dataCenterId > maxDataCenterNum || dataCenterId < 0) {
            throw new IllegalArgumentException("dataCenterId can't be greater than MAX_DATA_CENTER_NUM or less than 0");
        }
        if (machineId > maxMachineNum || machineId < 0) {
            throw new IllegalArgumentException("machineId can't be greater than MAX_MACHINE_NUM or less than 0");
        }
        this.dataCenterId = dataCenterId;
        this.machineId = machineId;
    }

    /**
     * 产生下一个ID
     */
    public synchronized long nextId() {
        long currStamp = getNewStamp();
        if (currStamp < lastStamp) {
            throw new RuntimeException("Clock moved backwards.  Refusing to generate id");
        }

        if (currStamp == lastStamp) {
            // 相同毫秒内，序列号自增
            sequence = (sequence + 1) & maxSequence;
            // 同一毫秒的序列数已经达到最大
            if (sequence == 0L) {
                currStamp = getNextMill();
            }
        } else {
            // 不同毫秒内，序列号置为0
            sequence = 0L;
        }
        lastStamp = currStamp;
        // 时间戳部分
        return (currStamp - START_STAMP) << timestampLeft
                // 数据中心部分
                | dataCenterId << dataCenterLeft
                // 机器标识部分
                | machineId << machineLeft
                // 序列号部分
                | sequence;
    }

    private long getNextMill() {
        long mill = getNewStamp();
        while (mill <= lastStamp) {
            mill = getNewStamp();
        }
        return mill;
    }

    private long getNewStamp() {
        return System.currentTimeMillis();
    }

    public static String listToString(List list, char separator) {
        StringBuffer sb = new StringBuffer();
        StringBuffer str = new StringBuffer("\"");
        for (int i = 0; i < list.size(); i++) {
            sb.append(str).append(list.get(i).toString()).append("\"").append(separator);
        }
        return list.isEmpty() ? "" : sb.toString().substring(0, sb.toString().length() - 1);
    }
}
