package com.navinfo.outdoor.util;

import javax.crypto.*;
import javax.crypto.spec.DESKeySpec;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.*;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;

public class Base64 {
    static final char[] alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
            .toCharArray();

    public static char[] encode(byte[] content) {
        CharArrayWriter cw = new CharArrayWriter(4 * content.length / 3);

        int idx = 0;

        int x = 0;

        for (int i = 0; i < content.length; ++i) {
            if (idx == 0)
                x = (content[i] & 0xFF) << 16;
            else if (idx == 1)
                x |= (content[i] & 0xFF) << 8;
            else {
                x |= content[i] & 0xFF;
            }

            if (++idx == 3) {
                cw.write(alphabet[(x >> 18)]);
                cw.write(alphabet[(x >> 12 & 0x3F)]);
                cw.write(alphabet[(x >> 6 & 0x3F)]);
                cw.write(alphabet[(x & 0x3F)]);

                idx = 0;
            }
        }

        if (idx == 1) {
            cw.write(alphabet[(x >> 18)]);
            cw.write(alphabet[(x >> 12 & 0x3F)]);
            cw.write(61);
            cw.write(61);
        }

        if (idx == 2) {
            cw.write(alphabet[(x >> 18)]);
            cw.write(alphabet[(x >> 12 & 0x3F)]);
            cw.write(alphabet[(x >> 6 & 0x3F)]);
            cw.write(61);
        }

        return cw.toCharArray();
    }

    public static byte[] decode(char[] message) throws IOException {
        byte[] buff = new byte[4];
        byte[] dest = new byte[message.length];

        int bpos = 0;
        int destpos = 0;

        for (int i = 0; i < message.length; ++i) {
            int c = message[i];

            if ((c != 10) && (c != 13) && (c != 32)) {
                if (c == 9)
                    continue;

                if ((c >= 65) && (c <= 90)) {
                    buff[(bpos++)] = (byte) (c - 65);
                } else if ((c >= 97) && (c <= 122)) {
                    buff[(bpos++)] = (byte) (c - 97 + 26);
                } else if ((c >= 48) && (c <= 57)) {
                    buff[(bpos++)] = (byte) (c - 48 + 52);
                } else if (c == 43) {
                    buff[(bpos++)] = 62;
                } else if (c == 47) {
                    buff[(bpos++)] = 63;
                } else if (c == 61) {
                    buff[(bpos++)] = 64;
                } else {
                    throw new IOException("Illegal char in base64 code.");
                }

                if (bpos == 4) {
                    bpos = 0;

                    if (buff[0] == 64)
                        break;

                    if (buff[1] == 64)
                        throw new IOException("Unexpected '=' in base64 code.");

                    int v;
                    if (buff[2] == 64) {
                        v = (buff[0] & 0x3F) << 6 | buff[1] & 0x3F;
                        dest[(destpos++)] = (byte) (v >> 4);
                        break;
                    }
                    if (buff[3] == 64) {
                        v = (buff[0] & 0x3F) << 12 | (buff[1] & 0x3F) << 6
                                | buff[2] & 0x3F;
                        dest[(destpos++)] = (byte) (v >> 10);
                        dest[(destpos++)] = (byte) (v >> 2);
                        break;
                    }

                    v = (buff[0] & 0x3F) << 18 | (buff[1] & 0x3F) << 12
                            | (buff[2] & 0x3F) << 6 | buff[3] & 0x3F;
                    dest[(destpos++)] = (byte) (v >> 16);
                    dest[(destpos++)] = (byte) (v >> 8);
                    dest[(destpos++)] = (byte) v;
                }
            }
        }

        byte[] res = new byte[destpos];
        System.arraycopy(dest, 0, res, 0, destpos);

        return res;
    }


    //-----------------------------------------------------

    private static String keyValue = "20140107";
    private static String keyVector = "20144295";
    private static final char[] legalChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".toCharArray();

    /**
     * data[]进行编码
     *
     * @param data
     * @return
     */
    private static String encode_(byte[] data) {
        int start = 0;
        int len = data.length;
        StringBuffer buf = new StringBuffer(data.length * 3 / 2);

        int end = len - 3;
        int i = start;
        int n = 0;

        while (i <= end) {
            int d = ((((int) data[i]) & 0x0ff) << 16) | ((((int) data[i + 1]) & 0x0ff) << 8) | (((int) data[i + 2]) & 0x0ff);

            buf.append(legalChars[(d >> 18) & 63]);
            buf.append(legalChars[(d >> 12) & 63]);
            buf.append(legalChars[(d >> 6) & 63]);
            buf.append(legalChars[d & 63]);

            i += 3;

            if (n++ >= 14) {
                n = 0;
                buf.append(" ");
            }
        }

        if (i == start + len - 2) {
            int d = ((((int) data[i]) & 0x0ff) << 16) | ((((int) data[i + 1]) & 255) << 8);

            buf.append(legalChars[(d >> 18) & 63]);
            buf.append(legalChars[(d >> 12) & 63]);
            buf.append(legalChars[(d >> 6) & 63]);
            buf.append("=");
        } else if (i == start + len - 1) {
            int d = (((int) data[i]) & 0x0ff) << 16;

            buf.append(legalChars[(d >> 18) & 63]);
            buf.append(legalChars[(d >> 12) & 63]);
            buf.append("==");
        }

        return buf.toString();
    }

    private static byte[] decode_(String s) {

        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        try {
            decode(s, bos);
        } catch (IOException e) {
            throw new RuntimeException();
        }
        byte[] decodedBytes = bos.toByteArray();
        try {
            bos.close();
            bos = null;
        } catch (IOException ex) {
            System.err.println("Error while decoding BASE64: " + ex.toString());
        }
        return decodedBytes;
    }

    private static void decode(String s, OutputStream os) throws IOException {
        int i = 0;

        int len = s.length();

        while (true) {
            while (i < len && s.charAt(i) <= ' ')
                i++;

            if (i == len)
                break;

            int tri = (decode(s.charAt(i)) << 18)
                    + (decode(s.charAt(i + 1)) << 12)
                    + (decode(s.charAt(i + 2)) << 6)
                    + (decode(s.charAt(i + 3)));

            os.write((tri >> 16) & 255);
            if (s.charAt(i + 2) == '=')
                break;
            os.write((tri >> 8) & 255);
            if (s.charAt(i + 3) == '=')
                break;
            os.write(tri & 255);

            i += 4;
        }
    }

    private static int decode(char c) {
        if (c >= 'A' && c <= 'Z') {
            return ((int) c) - 65;
        } else if (c >= 'a' && c <= 'z') {
            return ((int) c) - 97 + 26;
        } else if (c >= '0' && c <= '9') {
            return ((int) c) - 48 + 26 + 26;
        } else {
            switch (c) {
                case '+':
                    return 62;
                case '/':
                    return 63;
                case '=':
                    return 0;
                default:
                    throw new RuntimeException("unexpected code: " + c);
            }
        }
    }
    /**
     * 加密
     *
     * @param message 待加密的的文本信息
     * @return 返回加密结果
     */
    public static String desEncrypt(String message) throws Exception {
    	SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
    	SecretKey secretKey = keyFactory.generateSecret(new DESKeySpec(keyValue.getBytes("UTF-8")));
        IvParameterSpec iv = new IvParameterSpec(keyVector.getBytes("UTF-8"));
        Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, secretKey, iv);
        return encode_(cipher.doFinal(message.getBytes("UTF-8")));
    }
//    public static String desEncrypt1(String message) throws Exception {
////        SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
////        SecretKey secretKey = keyFactory.generateSecret(new DESKeySpec(keyValue.getBytes("UTF-8")));
//        SecretKeySpec secretKey = new SecretKeySpec(keyValue.getBytes(), "DES");
//        IvParameterSpec iv = new IvParameterSpec(keyVector.getBytes("UTF-8"));
//        Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
//        cipher.init(Cipher.ENCRYPT_MODE, secretKey, iv);
//        return encode_(cipher.doFinal(message.getBytes("UTF-8")));
//    }

    /**
     * 解密
     *
     * @param message 带解密文本信息
     * @return 返回解密结果
     * @throws UnsupportedEncodingException
     * @throws NoSuchPaddingException
     * @throws NoSuchAlgorithmException
     * @throws InvalidAlgorithmParameterException
     * @throws InvalidKeyException
     * @throws BadPaddingException
     * @throws IllegalBlockSizeException
     */
    public static String desDecrypt(String message) throws UnsupportedEncodingException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException {
        byte[] byteMi = Base64.decode_(message);
        SecretKeySpec key = new SecretKeySpec(keyValue.getBytes(), "DES");
        IvParameterSpec iv = new IvParameterSpec(keyVector.getBytes("UTF-8"));
        Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
        cipher.init(Cipher.DECRYPT_MODE, key, iv);
        return new String(cipher.doFinal(byteMi),"UTF-8");
    }

    public static void main(String[] args) throws Exception {
        System.out.println(desDecrypt("eLWAo/Fv9CGJmywsP+j+m0s++56MUl6xCb3lykLFsfi7m4YHfxjjcyxJ8vH+ReTv"));
//        System.out.println(desEncrypt("1626945974657e10adc3949ba59abbe56e057f20f883e"));
    }
}
