package com.fshark.overseas.advert.util;

import com.google.common.base.Strings;
import com.google.common.hash.Hashing;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.nio.charset.Charset;

/**
 * @author jake.zhang [zhangxj@kingnet.com]
 */
public class Common {

    private static final Logger logger = LoggerFactory.getLogger(Common.class);

    private static final char[] hexDigits = "0123456789abcdef".toCharArray();

    /**
     * 线程 sleep 毫秒值
     * @param millis
     */
    public static void sleep(long millis) {
        try {
            Thread.sleep(millis);
        } catch (Throwable e) {
            logger.error("sleep error.", e);
        }
    }

    /**
     * 转换字节到字符串
     * @param bytes
     * @return
     */
    public static String utf8(byte[] bytes) {
        try {
            return new String(bytes, "UTF8");
        } catch (Throwable e) {
            logger.error("byte[] to utf8 string error.", e);
        }
        return null;
    }

    public static byte[] utf8(String string) {
        try {
            return string.getBytes("UTF8");
        } catch (Throwable e) {
            logger.error("utf8 string to byte[] error.", e);
        }
        return null;
    }

    /**
     * 默认使用 UTF-8 字符集
     * @param str
     * @return
     */
    public static String md5(String str) {
        return md5(str, Charset.forName("UTF-8"));
    }

    public static String bytesToHexString(byte[] source) {
        StringBuilder sb = new StringBuilder(2 * source.length);
        for (byte b : source) {
            sb.append(hexDigits[(b >> 4) & 0xf]).append(hexDigits[b & 0xf]);
        }
        return sb.toString();
    }

    /**
     * 使用 guava MD5 生成结果
     * @param str
     * @param charset
     * @return
     */
    public static String md5(String str, Charset charset) {
        try {
            return bytesToHexString(md5ToBytes(str, charset));
        } catch (Throwable e) {
            logger.error("md5 hashing " + str + " error.", e);
        }
        return null;
    }

    public static byte[] md5ToBytes(String str, Charset charset) {
        return Hashing.md5().hashString(str, charset).asBytes();
    }

    public static long md5ToLong(String str) {
        return md5ToLong(str, Charset.forName("UTF-8"));
    }

    public static long md5ToLong(String str, Charset charset) {
        byte[] hashBytes = md5ToBytes(str, charset);
        return bytesToLong(hashBytes, 0) + bytesToLong(hashBytes, 8);
    }

    public static long bytesToLong(byte[] bytes, int offset) {
        return (bytes[offset] & 0xFFL) | ((bytes[offset + 1] & 0xFFL) << 8) | ((bytes[offset + 2] & 0xFFL) << 16)
                | ((bytes[offset + 3] & 0xFFL) << 24) | ((bytes[offset + 4] & 0xFFL) << 32)
                | ((bytes[offset + 5] & 0xFFL) << 40) | ((bytes[offset + 6] & 0xFFL) << 48)
                | ((bytes[offset + 7] & 0xFFL) << 56);
    }

    /**
     * 默认使用 utf-8 字符集
     * @param str
     * @return
     */
    public static String fastHashing(String str) {
        return fastHashing(str, Charset.forName("UTF-8"));
    }

    /**
     * 使用快速 Hash 128 位结果
     * @param str
     * @param charset
     * @return
     */
    public static String fastHashing(String str, Charset charset) {
        try {
            return bytesToHexString(fastHashingToBytes(str, charset));
        } catch (Throwable e) {
            logger.error("murmur3_128() hashing " + str + " error.", e);
        }
        return null;
    }

    public static long fastHashingToLong(String str) {
        return fastHashingToLong(str, Charset.forName("UTF-8"));
    }

    public static long fastHashingToLong(String str, Charset charset) {
        byte[] hashBytes = fastHashingToBytes(str, charset);
        return bytesToLong(hashBytes, 0) + bytesToLong(hashBytes, 8);
    }

    public static byte[] fastHashingToBytes(String str, Charset charset) {
        return Hashing.murmur3_128().hashString(str, charset).asBytes();
    }

    /**
     * 判斷字符串是否為空
     * @param str 字符串
     * @return true：空
     */
    public static boolean isBlank(String str) {
        return Strings.isNullOrEmpty(str);
    }

}
