package com.dxhy.common.util;

import java.io.UnsupportedEncodingException;
import java.security.GeneralSecurityException;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;

import javax.crypto.Cipher;
import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

public class Security {
    public static String charsetName = "UTF-8";

    public static String toHex(byte[] md) {
        // 把密文转换成十六进制的字符串形式
        int j = md.length;
        char[] hexDigits = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
        char[] str = new char[j * 2];
        int k = 0;
        for (byte byte0 : md) {
            str[k++] = hexDigits[byte0 >>> 4 & 0xf];
            str[k++] = hexDigits[byte0 & 0xf];
        }
        return new String(str);
    }

    private static int hexToNum(char c) {
        int num = 0;
        char[] hexDigits = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
        for (int j = 0; j < hexDigits.length; j++) {
            if (c == hexDigits[j])
                num = j;
        }
        return num;
    }

    public static byte[] toDecimal(String msg) {
        byte[] result = new byte[msg.length() / 2];
        char[] origional = msg.toCharArray();

        for (int i = 0; i < origional.length - 1; i++) {
            if (i % 2 == 0) {
                result[i / 2] = (byte)(hexToNum((origional[i])) * 16 + hexToNum(origional[i + 1]));
            }
        }
        return result;
    }

    /**
     * MD5加密
     * 
     * @param s
     * @return
     */
    public static String MD5(String s) {

        try {
            byte[] btInput = s.getBytes();
            // 获得MD5摘要算法的 MessageDigest 对象
            MessageDigest mdInst = MessageDigest.getInstance("MD5");
            // 使用指定的字节更新摘要
            mdInst.update(btInput);
            // 获得密文
            byte[] md = mdInst.digest();

            return toHex(md);
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * Description 根据键值进行加密
     * 
     * @param key
     * @return
     * @throws UnsupportedEncodingException
     * @throws GeneralSecurityException
     */
    public static String encrypt(String data, String key)
        throws GeneralSecurityException, UnsupportedEncodingException {
        byte[] src = data.getBytes(charsetName);
        Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
        DESKeySpec desKeySpec = new DESKeySpec(key.getBytes(charsetName));

        SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
        SecretKey secretKey = keyFactory.generateSecret(desKeySpec);
        IvParameterSpec iv = new IvParameterSpec(key.getBytes(charsetName));
        cipher.init(Cipher.ENCRYPT_MODE, secretKey, iv);
        return toHex(cipher.doFinal(src));
    }

    /**
     * Description 根据键值进行解密
     * 
     * @param src
     * @param key
     *            加密键byte数组
     * @return
     * @throws UnsupportedEncodingException
     * @throws Exception
     */
    public static String decrypt(String src, String key) throws GeneralSecurityException, UnsupportedEncodingException {
        // 生成一个可信任的随机数源
        byte[] data = toDecimal(src);
        Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");

        DESKeySpec desKeySpec = new DESKeySpec(key.getBytes(charsetName));

        SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
        SecretKey securekey = keyFactory.generateSecret(desKeySpec);

        IvParameterSpec iv = new IvParameterSpec(key.getBytes(charsetName));

        cipher.init(Cipher.DECRYPT_MODE, securekey, iv);
        return new String(cipher.doFinal(data), charsetName);

    }

    /**
     * 获得随机数字
     * 
     * @param num
     *            位数
     * @return
     */
    public static String getRandom(int num) {
        double key = Math.random() * 100000;
        StringBuilder result = new StringBuilder(Integer.toString((int)key));
        if (result.length() > num) {
            result = new StringBuilder(result.substring(result.length() - num));
        } else {
            for (int i = num - result.length(); i > 0; i--) {
                result.insert(0, "0");
            }
        }
        return result.toString();
    }

    private static final ThreadLocal<SimpleDateFormat> dateFormat = new ThreadLocal<>();

    public static String getCurrentString() {
        if (null == dateFormat.get()) {
            dateFormat.set(new SimpleDateFormat("yyyyMMddhhssmmsss"));
        }
        return dateFormat.get().format(new Timestamp(System.currentTimeMillis()));
    }

    public static String getSignature(byte[] data, byte[] key) throws NoSuchAlgorithmException, InvalidKeyException {

        SecretKeySpec signingKey = new SecretKeySpec(key, "HmacSHA1");
        Mac mac = Mac.getInstance("HmacSHA1");
        mac.init(signingKey);
        byte[] rawHmac = mac.doFinal(data);
        return MD5.getEncode(rawHmac);

    }

    public static String bytesToHexString(byte[] bArray) {
        StringBuilder sb = new StringBuilder(bArray.length);
        String sTemp;
        for (byte b : bArray) {
            sTemp = Integer.toHexString(0xFF & b);
            if (sTemp.length() < 2)
                sb.append(0);
            sb.append(sTemp.toUpperCase());
        }
        return sb.toString();
    }
}
