package com.ejweb.modules.front.report.utils;

import java.io.UnsupportedEncodingException;
import java.security.InvalidParameterException;
import java.util.Date;
import java.util.Random;

/**
 * Created by BrianHolsen on 2017-08-08 at 13:35.
 */
public class CaptchaUtil {

    private static byte[] KEY = {0x70, 0x3f, 0x2b, 0x47};
    private static final char[] HEX_TABLE_LOWER_CASE = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
            'a', 'b', 'c', 'd', 'e', 'f'};
    private static int LEN = 6;
    private static int EXPIRE_MININUTES = 3;

    /**
     *
     * @param str
     * @return
     */
    private static String encrypt(String str) {
        if (null == str || str.equals("")) {
            return str;
        }

        Random rand = new Random(new Date().getTime());
        try {
            StringBuffer buffer = new StringBuffer();
            buffer.append(Math.abs(rand.nextInt()) % 10);
            for (int i = 0; i < str.length(); i++) {
                char c = str.charAt(i);
                buffer.append(c);
                for (int j = 0; j < c % 5; j++) {
                    buffer.append(Math.abs(rand.nextInt()) % 10);
                }
            }
            byte[] bts = buffer.toString().getBytes("utf-8");
            for (int i = 0; i < bts.length; i++) {
                bts[i] ^= KEY[i % KEY.length];
            }
            return toHexString(bts);

        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return str;
    }

    private static String decrypt(String str) {
        if (null == str || str.equals("")) {
            return str;
        }
        byte[] bts = toByteArrayFromHexString(str);
        for (int i = 0; i < bts.length; i++) {
            bts[i] ^= KEY[i % KEY.length];
        }
        StringBuffer buffer = new StringBuffer();
        for (int i = 1; i < bts.length; i++) {
            buffer.append((char) bts[i]);
            i += bts[i] % 5;
        }
        return buffer.toString();
    }

    private static String toHexString(int data) {
        StringBuffer buf = new StringBuffer();
        char[] hex_table = HEX_TABLE_LOWER_CASE;

        int index8 = (data >> 28) & 0x0000000F;
        int index7 = (data >> 24) & 0x0000000F;
        int index6 = (data >> 20) & 0x0000000F;
        int index5 = (data >> 16) & 0x0000000F;
        int index4 = (data >> 12) & 0x0000000F;
        int index3 = (data >> 8) & 0x0000000F;
        int index2 = (data >> 4) & 0x0000000F;
        int index1 = data & 0x0000000F;

        buf.append(hex_table[index8])
                .append(hex_table[index7])
                .append(hex_table[index6])
                .append(hex_table[index5])
                .append(hex_table[index4])
                .append(hex_table[index3])
                .append(hex_table[index2])
                .append(hex_table[index1]);
        return buf.toString();
    }

    private static String toHexString(byte[] data) {
        StringBuffer buf = new StringBuffer();

        char[] hex_table = HEX_TABLE_LOWER_CASE;

        for (int i = 0; i < data.length; i++) {
            int index_low = data[i] & 0x0F;
            int index_high = (data[i] >> 4) & 0x0F;
            buf.append(hex_table[index_high]).append(hex_table[index_low]);
        }

        return buf.toString();
    }

    private static byte[] toByteArrayFromHexString(String hexString) {
        if (hexString.length() % 2 != 0) {
            throw new InvalidParameterException("The length of a hex string must be even");
        }

        hexString = hexString.toLowerCase();
        byte[] bts = hexString.getBytes();
        int startIndex = 0;
        if (bts[0] == '0' && (bts[1] == 'x')) {
            startIndex = 2;
        }
        byte[] result = new byte[(bts.length - startIndex) / 2];

        for (int i = startIndex; i < bts.length; i += 2) {
            byte high = bts[i];
            byte low = bts[i + 1];
            if ((high < '0' || (high > '9' && high < 'a') || high > 'f')
                    || (low < '0' || (low > '9' && low < 'a') || low > 'f')) {
                throw new InvalidParameterException("Invalid char(s) in hex string");
            }
            high -= 48;
            low -= 48;
            if (high > 10) {
                high -= 39;
            }
            if (low > 10) {
                low -= 39;
            }
            result[(i - startIndex) / 2] = (byte) ((high << 4) + low);
        }

        return result;
    }

    public static boolean validate(String captcha, String code) {
        if (captcha == null || captcha.equals("") || code == null || code.equals("")) {
            return false;
        }
        try {
            String data = decrypt(code);
            String correctCaptcha = data.substring(0, LEN);
            long time = new Date().getTime();
            long expires = Long.parseLong(data.substring(LEN));
            if (captcha.equals(correctCaptcha) && expires > time) {
                return true;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     *
     * 获取验证码对应的code值
     * @return
     */
    public static String getCaptchaCode() {
        Random rand = new Random(new Date().getTime());
        StringBuffer buffer = new StringBuffer();
        for (int i = 0; i < LEN; i++) {
            buffer.append(Math.abs(rand.nextInt()) % 10);
        }
        //System.out.println(buffer.toString());
        buffer.append(new Date().getTime() + EXPIRE_MININUTES * 60 * 1000);
        //buffer.append(new Date().getTime() + 30 * 1000);
        //System.out.println(buffer.toString());
        return CaptchaUtil.encrypt(buffer.toString());
    }

    public static String getCaptcha(String code) {
        if (code == null || code.equals("")) {
            return "";
        }
        try {
            String data = decrypt(code);
            String correctCaptcha = data.substring(0, LEN);
            return correctCaptcha;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "";
    }

    public static void main(String[] args) throws InterruptedException {

        String code = getCaptchaCode();
        System.out.println(code);
        String captcha = getCaptcha(code);
        System.out.println(captcha);

        System.out.println(validate(captcha, code));
        Thread.sleep(2000);
        System.out.println(validate(captcha, code));

        Thread.sleep(3000);
        System.out.println(validate(captcha, code));
        //   System.out.println(CaptchaUtil.encrypt(buffer.toString()));
    }
}
