package com.nuliji.tools;

import org.apache.commons.codec.binary.Base64;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import javax.servlet.http.HttpServletRequest;
import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.*;

/**
 * Created by gaojie on 2017/11/9.
 */
public class Tools {

    private static final Logger logger = LoggerFactory.getLogger(Tools.class);
    protected static Random random = new Random();

    public static String stringMD5(String str) {
        return byteArrayToHexString(getMd5(str));
    }

    public static String stringSha1(String str) {
        return byteArrayToHexString(getSha1(str));
    }

    public static int getRandom() {
        return random.nextInt(999999)%900000+100000;
    }

    public static String getRandomString(int length){
        String str="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
        Random random=new Random();
        StringBuffer sb=new StringBuffer();
        for(int i=0;i<length;i++){
            int number=random.nextInt(62);
            sb.append(str.charAt(number));
        }
        return sb.toString();
    }

    /**
     * 取得指定月份的最大天数
     *
     * @param date 月份，格式yyyy-MM
     * @return
     */
    public static int getMonthDays(String date) {
        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.YEAR, Integer.parseInt(date.substring(0, 4)));
        calendar.set(Calendar.MONTH, Integer.parseInt(date.substring(5, 7)) - 1);
        int maxDay = calendar.getActualMaximum(Calendar.DAY_OF_MONTH);
        return maxDay;
    }

    public static int getDayOfMonth(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        return calendar.get(Calendar.DAY_OF_MONTH);
    }

    public static byte[] getMd5(String str) {
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            md.update(str.getBytes("utf-8"));
            return md.digest();
        } catch (Exception e) {
            System.out.println(e);
        }
        return null;
    }

    public static byte[] getSha1(String str){
        try {
            MessageDigest md = MessageDigest.getInstance("SHA-1");
            md.update(str.getBytes("utf-8"));
            return md.digest();
        } catch (Exception e) {
            System.out.println(e);
        }
        return null;
    }

    public static byte[] getHmacSha1(String str, String key){
        try {
            byte[] data=key.getBytes("utf-8");
            //根据给定的字节数组构造一个密钥,第二参数指定一个密钥算法的名称
            SecretKey secretKey = new SecretKeySpec(data, "HmacSHA1");
            //生成一个指定 Mac 算法 的 Mac 对象
            Mac mac = Mac.getInstance("HmacSHA1");

            //用给定密钥初始化 Mac 对象
            mac.init(secretKey);

            byte[] text = str.getBytes("utf-8");
            //完成 Mac 操作
            return mac.doFinal(text);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        }
        return null;
    }

    public static String byteArrayToHexString(byte[] b) {
        String ret = "";
        for (int i = 0; i < b.length; i++) {
            String hex = Integer.toHexString(b[i] & 255);
            if (hex.length() == 1) {
                hex = '0' + hex;
            }
            ret += hex;
        }
        return ret;
    }

    /**
     * @param bytes
     * @return
     */
    public static byte[] decodeBase64(final byte[] bytes) {
        return Base64.decodeBase64(bytes);
    }

    /**
     * @param str
     * @return
     */
    public static byte[] decodeBase64(final String str) {
        return Base64.decodeBase64(str.getBytes());
    }

    /**
     * 二进制数据编码为BASE64字符串
     *
     * @param bytes
     * @return
     * @throws Exception
     */
    public static String encodeBase64(final byte[] bytes) {
        return new String(Base64.encodeBase64(bytes));
    }

    public static String encodeBase64(final String str) {
        return encodeBase64(str.getBytes());
    }

    //求两个字符串数组的并集，利用set的元素唯一性
    public static <T> Collection<T> union(Collection<T> arr1, Collection<T> arr2) {
        Set<T> set = new HashSet<T>();
        set.addAll(arr1);
        set.addAll(arr2);
        return set;
    }

    //求两个数组的交集
    public static <T> Collection<T> intersect(Collection<T> arr1, Collection<T> arr2) {
        Map<T, Boolean> map = new HashMap<T, Boolean>();
        LinkedList<T> list = new LinkedList<T>();
        for (T str : arr1) {
            if (!map.containsKey(str)) {
                map.put(str, Boolean.FALSE);
            }
        }
        for (T str : arr2) {
            if (map.containsKey(str)) {
                map.put(str, Boolean.TRUE);
            }
        }

        for (Map.Entry<T, Boolean> e : map.entrySet()) {
            if (e.getValue().equals(Boolean.TRUE)) {
                list.add(e.getKey());
            }
        }

        return list;
    }

    //求两个数组的差集: 第一个不在第二个中的元素
    public static <T> Collection<T> minus(Collection<T> arr1, Collection<T> arr2) {
        LinkedList<T> list = new LinkedList<T>();
        list.addAll(arr1);
        for (T str : arr2) {
            if (list.contains(str)) {
                list.remove(str);
            }
        }

        return list;
    }

    public static String joinIds(Collection ids) {
        List<String> list = new ArrayList<>();
    //        logger.debug("join：{}", ids);
        if(ids == null || ids.size() == 0) return "";
        for (Object id : ids) {
            list.add(id.toString());
        }
        return String.join(",", list);
    }

    public static Collection<Long> splitIds(String ids){
        List<Long> l = new ArrayList<>();
    //        logger.debug("split：{}", ids);
        if(ids == null || ids.length() == 0) return l;
        String[] list = ids.split(",");
        for(String s:list){
            l.add(Long.valueOf(s));
        }
        return l;
    }

    public static String getClientIp(HttpServletRequest request){
        String ipAddress = request.getHeader("x-forwarded-for");

        if(ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
            ipAddress = request.getRemoteAddr();
        }
        //对于通过多个代理的情况，第一个IP为客户端真实IP,多个IP按照','分割
        if(ipAddress!=null && ipAddress.length()>15){ //"***.***.***.***".length() = 15
            if(ipAddress.indexOf(",")>0){
                ipAddress = ipAddress.substring(0,ipAddress.indexOf(","));
            }
        }
        return ipAddress;
    }

    public static Date today(){
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(new Date());
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        return calendar.getTime();
    }
    public static Date addDate(Date date, int day){
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        c.add(Calendar.DAY_OF_YEAR, day);
        return date;
    }


    public static TreeMap<String, String> parseXml(String xml) {
        Document document = null;
        TreeMap<String, String> packageMap = new TreeMap<>();
        try {
            document = DocumentHelper.parseText(xml);
        } catch (DocumentException ex) {
            return null;
        }
        Element rootElement = document.getRootElement();
        for (Element element : (List<Element>) rootElement.elements()) {
            packageMap.put(element.getName(), element.getText());
        }
        return packageMap;
    }
}
