package cn.util.uuid;

import java.security.SecureRandom;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Random;
import java.util.concurrent.ThreadLocalRandom;
import cn.util.time.TimeKit;

/**
 * 提供通用唯一识别码（universally unique identifier）（UUID）实现
 */
public class UUIDKit implements java.io.Serializable, Comparable<UUIDKit> 
{
	private static final long serialVersionUID = -1185015143654744140L;
	/**
     * 编码表主键 纯数字25位
     */
    public static String encodingUUID() 
    {
    	DateFormat df = new SimpleDateFormat("yyyyMMddHHmmss");
		Calendar calendar = Calendar.getInstance();
		String dateName = df.format(calendar.getTime());
		return (dateName+getRandom(6)+genNumByTime(5));
    }
	public static String getRandom(int len) {
		String source = "0123456789";
		Random r = new Random();
		StringBuilder rs = new StringBuilder();
		for (int j = 0; j < len; j++) {
			rs.append(source.charAt(r.nextInt(10)));
		}
		return rs.toString();
	}
	public static String genNumByTime(int len)
	{
		String source = "0123456789";
		long t = System.currentTimeMillis();//获得当前时间的毫秒数
		Random rd = new Random(t);//作为种子数传入到Random的构造器中
		StringBuilder rs = new StringBuilder();
		for (int j = 0; j < len; j++) {
			rs.append(source.charAt(rd.nextInt(10)));
		}
		return rs.toString();
	}
    
	/**
	 * 此UUID的最高64有效位
	 */
	private long mostSigBits;

	/**
	 * 此UUID的最低64有效位
	 */
	private long leastSigBits;

	public UUIDKit() { }
	/**
	 * 私有构造
	 *
	 * @param data 数据
	 */
	private UUIDKit(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.mostSigBits = msb;
		this.leastSigBits = lsb;
	}


	/**32位*/
	public static String getUUID_32() {
		return UUIDKit.randomUUID().toString().replace("-", "");
	}

	/**
	 * 生成一个由大小写字母和数字组成的length位的随机字符串，并且字符串不重复
	 */
	public static String genCharNum(int length)
	{
		if(length <= 0) {
			length = 5;
		}
		char[] letters = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
				'K', 'L', 'M', 'N', 'O', 'P','Q', 'R', 'S', 'T', 'U', 'V',
				'W', 'X', 'Y', 'Z','a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
				'k', 'l', 'm', 'n', 'o', 'p','q', 'r', 's', 't', 'u', 'v',
				'w', 'x', 'y', 'z','0','1','2','3','4','5','6','7','8','9'};
		boolean[] flags = new boolean[letters.length];
		char[] chs = new char[length];
		for (int i = 0; i < chs.length; i++) {
			int index;
			do {
				index = (int) (Math.random() * (letters.length));
			} while (flags[index]);// 判断生成的字符是否重复
			chs[i] = letters[index];
			flags[index] = true;
		}
		return String.valueOf(chs);
	}
	/**
	 * 产生一个数字
	 */
	public static String genRandomNum(int len) {
		return getRandom(len);
	}


	/**
	 * 返回此{@code UUID} 的字符串表现形式。
	 *
	 * <p>
	 * 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>
	 *
	 * </blockquote>
	 *
	 * @param isSimple 是否简单模式，简单模式为不带'-'的UUID字符串
	 * @return 此{@code UUID} 的字符串表现形式
	 */
	public String toString(boolean isSimple) {
		final StringBuilder builder = new StringBuilder(isSimple ? 32 : 36);
		// time_low
		builder.append(digits(mostSigBits >> 32, 8));
		if (!isSimple) {
			builder.append('-');
		}
		// time_mid
		builder.append(digits(mostSigBits >> 16, 4));
		if (!isSimple) {
			builder.append('-');
		}
		// time_high_and_version
		builder.append(digits(mostSigBits, 4));
		if (!isSimple) {
			builder.append('-');
		}
		// variant_and_sequence
		builder.append(digits(leastSigBits >> 48, 4));
		if (!isSimple) {
			builder.append('-');
		}
		// node
		builder.append(digits(leastSigBits, 12));

		return builder.toString();
	}

	/**
	 * 将此 UUID 与指定的 UUID 比较。
	 *
	 * <p>
	 * 如果两个 UUID 不同，且第一个 UUID 的最高有效字段大于第二个 UUID 的对应字段，则第一个 UUID 大于第二个 UUID。
	 *
	 * @param val 与此 UUID 比较的 UUID
	 * @return 在此 UUID 小于、等于或大于 val 时，分别返回 -1、0 或 1。
	 */
	public int compareTo(UUIDKit val) {
		// The ordering is intentionally set up so that the UUIDs
		// can simply be numerically compared as two numbers
		return (this.mostSigBits < val.mostSigBits ? -1 : //
			(this.mostSigBits > val.mostSigBits ? 1 : //
				(this.leastSigBits < val.leastSigBits ? -1 : //
					(this.leastSigBits > val.leastSigBits ? 1 : //
						0))));
	}
	/**
	 * 返回指定数字对应的hex值
	 *
	 * @param val    值
	 * @param digits 位
	 * @return 值
	 */
	private static String digits(long val, int digits) {
		long hi = 1L << (digits * 4);
		return Long.toHexString(hi | (val & (hi - 1))).substring(1);
	}

	/**
	 * 获取随机数生成器对象<br>
	 * ThreadLocalRandom是JDK 7之后提供并发产生随机数，能够解决多个线程发生的竞争争夺。
	 *
	 * @return {@link ThreadLocalRandom}
	 */
	public static ThreadLocalRandom getRandom() {
		return ThreadLocalRandom.current();
	}


	/**
	 * 获取类型 4（伪随机生成的）UUID 的静态工厂。 使用加密的本地线程伪随机数生成器生成该 UUID。
	 *
	 * @return 随机生成的 {@code UUID}
	 */
	public static UUIDKit fastUUID() {
		return randomUUID(false);
	}
	/**
	 * 简化的UUID，去掉了横线，使用性能更好的ThreadLocalRandom生成UUID
	 *
	 * @return 简化的UUID，去掉了横线
	 */
	public static String fastSimpleUUID() {
		return UUIDKit.fastUUID().toString(true);
	}

	/**
	 * 获取随机UUID，使用性能更好的ThreadLocalRandom生成UUID
	 *
	 * @return 随机UUID
	 */
	public static String fastUUID_S() {
		return UUIDKit.fastUUID().toString();
	}
	/**
	 * 简化的UUID，去掉了横线
	 *
	 * @return 简化的UUID，去掉了横线
	 */
	public static String simpleUUID() {
		return UUIDKit.randomUUID().toString(true);
	}

	/**
	 * 获取随机UUID
	 *
	 * @return 随机UUID
	 */
	public static String randomUUID_S() {
		return UUIDKit.randomUUID().toString();
	}
	/**
	 * 获取类型 4（伪随机生成的）UUID 的静态工厂。 使用加密的强伪随机数生成器生成该 UUID。
	 *
	 * @return 随机生成的 {@code UUID}
	 */
	public static UUIDKit randomUUID() {
		return randomUUID(true);
	}

	/**
	 * 获取类型 4（伪随机生成的）UUID 的静态工厂。 使用加密的强伪随机数生成器生成该 UUID。
	 *
	 * @param isSecure 是否使用{@link SecureRandom}如果是可以获得更安全的随机码，否则可以得到更好的性能
	 * @return 随机生成的 {@code UUID}
	 */
	public static UUIDKit randomUUID(boolean isSecure) {
		final Random ng = getRandom();
		if(isSecure){
		}
		byte[] randomBytes = new byte[16];
		ng.nextBytes(randomBytes);
		randomBytes[6] &= 0x0f; /* clear version */
		randomBytes[6] |= 0x40; /* set to version 4 */
		randomBytes[8] &= 0x3f; /* clear variant */
		randomBytes[8] |= 0x80; /* set to IETF variant */
		return new UUIDKit(randomBytes);
	}

	/** 不重复的验证码*/
	public static String codeGen(int i)
	{
		char[] codeSequence = {'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I',
				'O', 'P', 'L', 'K', 'J', 'H', 'G', 'F', 'D',
				'S', 'A', 'Z', 'X', 'C', 'V', 'B', 'N', 'M', '1',
				'2', '3', '4', '5', '6', '7', '8', '9', '0'};
		Random random = new Random();
		StringBuilder stringBuilder = new StringBuilder();
		int count = 0;
		while (true) {
			// 随机产生一个下标，通过下标取出字符数组中对应的字符
			char c = codeSequence[random.nextInt(codeSequence.length)];
			// 假设取出来的字符在动态字符中不存在，代表没有重复的
			if (stringBuilder.indexOf(c + "") == -1) {
				stringBuilder.append(c);
				count++;
				//控制随机生成的个数
				if (count == i) {
					break;
				}
			}
		}
		return stringBuilder.toString();
	}
	

	 /**
     * 编码文件名 文件名
     */
    public static String encodingFilename_xlsx(String filename) {
        filename = filename + "_" + getUUID_32() + ".xlsx";
        return filename;
    }
    /**
     * 编码文件名 扩展名".xlsx" ".docx"
     */
    public static String encodingFilename(String suffix) {
    	return TimeKit.getToday() + "_" + getUUID_32() + "_r" + suffix;
    }
}
