package com.artfess.base.util;

import com.alibaba.fastjson.JSON;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import org.apache.commons.jexl2.Expression;
import org.apache.commons.jexl2.JexlContext;
import org.apache.commons.jexl2.JexlEngine;
import org.apache.commons.jexl2.MapContext;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.sql.Time;
import java.sql.Timestamp;
import java.text.DecimalFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.UUID;

public class CommonUtil {
    //本地异常日志记录对象

    public static final long HOURS_PER_DAY = 24L;
    public static final long SECS_PER_MIN = 60L;
    public static final long MINS_PER_HOUR = 60L;
    public static final long MILLIS_PER_SECOND = 1000L;
    public static final long MILLIS_PER_MINUTE = 60000L;
    public static final long MILLIS_PER_HOUR = 3600000L;
    public static final long MILLIS_PER_DAY = 86400000L;
    public static final int DEFAULT_SCALE = 20;
//	static SimpleDateFormat sdf = null;

    public static Map<String, Object> decodeMap(String value) {
        HashMap<String, Object> result = new HashMap<String, Object>();
        if (StringUtil.isNotEmpty(value)) {
            String[] valueArray = value.trim().split(";");
            for (String str : valueArray) {
                if (str.contains("=")) {
                    String[] subValueArray = str.trim().split("=");
                    if (subValueArray.length == 1)
                        result.put(subValueArray[0].trim(), "");
                    else {
                        result.put(subValueArray[0].trim(), subValueArray[1].trim());
                    }
                }
            }
        }
        return result;
    }

    public static String encodeMap(Map<String, Object> map) {
        String result = "";
        for (String key : map.keySet()) {
            Object obj = map.get(key);
            String value = "";
            if (obj != null) {
                value = obj + "";
            }
            result = result + key + "=" + value + ";";
        }
        return result;
    }

    public static String createGUID() {
        return UUID.randomUUID().toString().toUpperCase().replaceAll("-", "");
    }

    public static String createFileFullName(String path, String fileName, String fileKind) {
        StringBuffer sb = new StringBuffer();
        sb.append(StringUtil.isEmpty(path) ? "" : path);
        sb.append("/");
        sb.append(StringUtil.isEmpty(fileName) ? "" : fileName);
        if (StringUtil.isNotEmpty(fileKind))
            sb.append(".").append(fileKind);
        return sb.toString();
    }

    public static Timestamp getCurrentDateTime() {
        return new Timestamp(new Date().getTime());
    }

    public static java.sql.Date getCurrentDate() {
        return java.sql.Date.valueOf(new SimpleDateFormat("yyyy-MM-dd")
                .format(new Date()));
    }

    public static Date trunc(Date value) throws ParseException {
        String dateStr = new SimpleDateFormat("yyyy-MM-dd").format(value);
        return new SimpleDateFormat("yyyy-MM-dd").parse(dateStr);
    }

    public static Date parseDateTime(String value) throws ParseException {
        return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(value);
    }

    public static java.sql.Date getYesterday() {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(getCurrentDate());
        calendar.add(5, -1);

        return java.sql.Date.valueOf(new SimpleDateFormat("yyyy-MM-dd").format(calendar.getTime()));
    }

    public static java.sql.Date getTomorrow() {
        Calendar calendar = Calendar.getInstance();

        calendar.setTime(getCurrentDate());
        calendar.add(5, 1);

        return java.sql.Date.valueOf(new SimpleDateFormat("yyyy-MM-dd").format(calendar.getTime()));
    }

    public static Time getCurrentTime() {
        return Time.valueOf(new SimpleDateFormat("HH:mm:ss").format(new Date()));
    }

    public static int getYear(Date date) {
        verification(date != null, "getYear的参数不能为空。");
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        return calendar.get(1);
    }

    public static int getMonth(Date date) {
        verification(date != null, "getMonth的参数不能为空。");
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        return calendar.get(2) + 1;
    }

    public static int getDay(Date date) {
        verification(date != null, "getDay的参数不能为空。");
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        return calendar.get(5);
    }

    public static int getHour(Date date) {
        verification(date != null, "getHour的参数不能为空。");
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        return calendar.get(10);
    }

    public static int getMinute(Date date) {
        verification(date != null, "getMinute的参数不能为空。");
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        return calendar.get(12);
    }

    public static java.sql.Date getFirstDateOfYear(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(2, 0);
        calendar.set(5, 1);
        return java.sql.Date.valueOf(new SimpleDateFormat("yyyy-MM-dd").format(calendar.getTime()));
    }

    public static java.sql.Date getFirstDateOfYear(int year) {
        Calendar calendar = Calendar.getInstance();
        calendar.set(1, year);
        calendar.set(2, 0);
        calendar.set(5, 1);
        return java.sql.Date.valueOf(new SimpleDateFormat("yyyy-MM-dd").format(calendar.getTime()));
    }

    public static java.sql.Date getLastDateOfYear(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(1, 1);
        calendar.set(2, 0);
        calendar.set(5, 0);
        return java.sql.Date.valueOf(new SimpleDateFormat("yyyy-MM-dd").format(calendar.getTime()));
    }

    /**
     * 获得指定日期的前一天
     *
     * @param specifiedDay 指定日期
     * @param pattern      需要返回的日期格式，例如：yyyy-MM-dd HH:mm:ss
     * @return 前一天日期
     */
    public static String getSpecifiedDayBefore(String pattern, String specifiedDay) throws ParseException {
        Calendar c = Calendar.getInstance();
        Date date = new SimpleDateFormat(pattern).parse(specifiedDay);
        c.setTime(date);
        int day = c.get(Calendar.DATE);
        c.set(Calendar.DATE, day - 1);
        String dayBefore = new SimpleDateFormat(pattern).format(c.getTime());
        return dayBefore;
    }

    public static java.sql.Date getLastDateOfYear(int year) {
        Calendar calendar = Calendar.getInstance();
        calendar.set(1, year + 1);
        calendar.set(2, 0);
        calendar.set(5, 0);
        return java.sql.Date.valueOf(new SimpleDateFormat("yyyy-MM-dd").format(calendar.getTime()));
    }

    public static java.sql.Date getFirstDateOfLastYear(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(1, -1);
        calendar.set(2, 0);
        calendar.set(5, 1);
        return java.sql.Date.valueOf(new SimpleDateFormat("yyyy-MM-dd").format(calendar.getTime()));
    }

    public static java.sql.Date getLastDateOfLastYear(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(2, 0);
        calendar.set(5, 0);
        return java.sql.Date.valueOf(new SimpleDateFormat("yyyy-MM-dd").format(calendar.getTime()));
    }

    public static Date addDays(Date date, int days) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(5, days);
        return calendar.getTime();
    }

    public static int getSecond(Date date) {
        verification(date != null, "getYear的参数不能为空！");
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        return calendar.get(13);
    }

    public static java.sql.Date getFirstDateOfMonth(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(5, 1);
        return java.sql.Date.valueOf(new SimpleDateFormat("yyyy-MM-dd").format(calendar.getTime()));
    }

    public static java.sql.Date getLastDateOfMonth(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(2, 1);
        calendar.set(5, 0);
        return java.sql.Date.valueOf(new SimpleDateFormat("yyyy-MM-dd").format(calendar.getTime()));
    }

    public static java.sql.Date getFirstDateOfLastMonth(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(2, -1);
        calendar.set(5, 1);
        return java.sql.Date.valueOf(new SimpleDateFormat("yyyy-MM-dd").format(calendar.getTime()));
    }

    public static java.sql.Date getLastDateOfLastMonth(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);

        calendar.add(2, -1);

        int lastDay = calendar.getActualMaximum(5);
        calendar.set(5, lastDay);

        return java.sql.Date.valueOf(new SimpleDateFormat("yyyy-MM-dd").format(calendar.getTime()));
    }

    public static java.sql.Date getFirstDateOfWeek(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(7, 2);
        return java.sql.Date.valueOf(new SimpleDateFormat("yyyy-MM-dd").format(calendar.getTime()));
    }

    public static java.sql.Date getLastDateOfWeek(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(7, 7);
        calendar.add(5, 1);
        return java.sql.Date.valueOf(new SimpleDateFormat("yyyy-MM-dd").format(calendar.getTime()));
    }

    public static java.sql.Date getFirstDateOfLastWeek(Date date) {
        Calendar calendar = Calendar.getInstance();

        java.sql.Date firstDayOfWeek = getFirstDateOfWeek(date);
        calendar.setTime(firstDayOfWeek);
        calendar.add(5, -7);

        return java.sql.Date.valueOf(new SimpleDateFormat("yyyy-MM-dd").format(calendar.getTime()));
    }

    public static java.sql.Date getLastDateOfLastWeek(Date date) {
        Calendar calendar = Calendar.getInstance();

        java.sql.Date lastDayOfWeek = getFirstDateOfWeek(date);
        calendar.setTime(lastDayOfWeek);
        calendar.add(5, -1);

        return java.sql.Date.valueOf(new SimpleDateFormat("yyyy-MM-dd").format(calendar.getTime()));
    }

    public static int getDayOfWeek(Date date) {
        Calendar localCalendar = Calendar.getInstance();
        localCalendar.setTime(date);
        return localCalendar.get(7);
    }

    public static java.sql.Date getStepDay(Date date, int step) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(6, step);
        return new java.sql.Date(calendar.getTime().getTime());
    }

    public static Integer getDaysBetween(Date start, Date end) {
        Assert.notNull(start, "参数start不能为空。");
        Assert.notNull(end, "参数end不能为空。");

        Long result = Long.valueOf((end.getTime() - start.getTime()) / 86400000L);
        return Integer.valueOf(result.intValue());
    }

    public static String toString(Object obj) {
        if (obj == null)
            return null;
        if ((obj instanceof Timestamp))
            return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format((Date) obj);
        if ((obj instanceof Time))
            return new SimpleDateFormat("HH:mm:ss").format((Date) obj);
        if ((obj instanceof java.sql.Date))
            return new SimpleDateFormat("yyyy-MM-dd").format((Date) obj);
        if ((obj instanceof BigDecimal))
            return new DecimalFormat("#.##################################").format(obj);
        return obj.toString();
    }

    public static int toInteger(Object obj) {
        verification(obj != null, "toInteger的参数不能为空。");
        if ((obj instanceof String))
            return Integer.valueOf((String) obj).intValue();
        if ((obj instanceof Number)) {
            return ((Number) obj).intValue();
        }
        throw new RuntimeException("错误的toInteger参数类型：" + obj.getClass());
    }

    public static BigDecimal toDecimal(Object obj) {
        verification(obj != null, "toDecimal的参数不能为空。");
        if ((obj instanceof BigDecimal)) {
            return (BigDecimal) obj;
        }
        BigDecimal result = null;
        if ((obj instanceof String))
            result = BigDecimal.valueOf(Double.valueOf((String) obj).doubleValue());
        else if ((obj instanceof Number))
            result = BigDecimal.valueOf(((Number) obj).doubleValue());
        else
            throw new RuntimeException("错误的toDecimal参数类型：" + obj.getClass());
        result.setScale(20, RoundingMode.HALF_UP);
        return result;
    }

    public static long toLong(Object obj) {
        verification(obj != null, "toLong的参数不能为空。");
        if ((obj instanceof String))
            return Long.valueOf((String) obj).longValue();
        if ((obj instanceof Number)) {
            return ((Number) obj).longValue();
        }
        throw new RuntimeException("错误的toLong参数类型：" + obj.getClass());
    }

    public static double toDouble(Object obj) {
        verification(obj != null, "toDouble的参数不能为空。");
        if ((obj instanceof String))
            return Double.valueOf((String) obj).doubleValue();
        if ((obj instanceof Number)) {
            return ((Number) obj).doubleValue();
        }
        throw new RuntimeException("错误的toDouble参数类型：" + obj.getClass());
    }

    public static float toFloat(Object obj) {
        verification(obj != null, "toFloat的参数不能为空。");
        if ((obj instanceof String))
            return Float.valueOf((String) obj).floatValue();
        if ((obj instanceof Number)) {
            return ((Number) obj).floatValue();
        }
        throw new RuntimeException("错误的toFloat参数类型：" + obj.getClass());
    }

    public static Float roundTo(Float value, int digit) {
        BigDecimal b = new BigDecimal(value.floatValue());
        return Float.valueOf(b.setScale(digit, 4).floatValue());
    }

    public static java.sql.Date toDate(Object obj) {
        verification(obj != null, "toDate的参数不能为空。");
        if ((obj instanceof java.sql.Date))
            return (java.sql.Date) obj;
        if ((obj instanceof String))
            return java.sql.Date.valueOf((String) obj);
        if ((obj instanceof Date))
            return java.sql.Date.valueOf(new SimpleDateFormat("yyyy-MM-dd").format((Date) obj));
        throw new RuntimeException("错误的toDate参数类型：" + obj.getClass());
    }

    public static Timestamp toDateTime(Object obj) {
        verification(obj != null, "toDateTime的参数不能为空。");
        if ((obj instanceof Timestamp))
            return (Timestamp) obj;
        if ((obj instanceof String))
            try {
                return new Timestamp(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse((String) obj).getTime());
            } catch (Exception localException) {
                throw new RuntimeException("将字符串：" + obj + "转换为DATETIME时出错！");
            }
        if ((obj instanceof Date))
            return new Timestamp(((Date) obj).getTime());
        throw new RuntimeException("错误的toDateTime参数类型：" + obj.getClass());
    }

    public static Time toTime(Object obj) {
        verification(obj != null, "toTime的参数不能为空。");
        if ((obj instanceof Time))
            return (Time) obj;
        if ((obj instanceof String))
            return Time.valueOf((String) obj);
        if ((obj instanceof Date))
            return Time.valueOf(new SimpleDateFormat("HH:mm:ss").format((Date) obj));
        throw new RuntimeException("错误的toTime参数类型：" + obj.getClass());
    }

    public static String toChineseNumber(Number value, boolean isCapital) {
        verification(value != null, "toChineseNumber的参数不能为空。");
        verification(isCapital, "目前不支持转换为小写的汉字数字！");
        if ((value instanceof BigDecimal)) {
            return NumberUtil.formatString((BigDecimal) value);
        }
        return NumberUtil.formatString(value.doubleValue());
    }

    public static String toChineseMoney(Number value) {
        verification(value != null, "toChineseMoney的参数不能为空。");
        String s = null;
        if ((value instanceof BigDecimal))
            s = NumberUtil.formatString((BigDecimal) value);
        else {
            s = NumberUtil.formatString(value.doubleValue());
        }
        return NumberUtil.toMoeny(s);
    }

    public static String ltrim(String value) {
        if (value == null)
            return null;
        if ("".equals(value))
            return "";
        int i = 0;
        while ((i < value.length()) && (value.charAt(i) <= ' '))
            i++;
        return value.substring(i);
    }

    public static String rtrim(String value) {
        if (value == null)
            return null;
        if ("".equals(value))
            return "";
        int i = value.length();
        while ((i > 0) && (value.charAt(i - 1) <= ' '))
            i--;
        return value.substring(0, i);
    }

    public static String lpad(int length, int number) {
        String f = "%0" + length + "d";
        return String.format(f, new Object[]{Integer.valueOf(number)});
    }

    public static String getExtOfFile(String path) {
        String str = getNameOfFile(path);
        if ((str == null) || ("".equals(str)))
            return null;
        return str.indexOf('.') != -1 ? str.substring(str.lastIndexOf('.') + 1, str.length()) : null;
    }

    public static String getPathOfFile(String path) {
        if ((path == null) || ("".equals(path)))
            return null;
        path = path.trim();
        if (path.indexOf('/') == -1)
            return null;
        return path.substring(0, path.lastIndexOf('/'));
    }

    public static String getNameOfFile(String path) {
        if ((path == null) || ("".equals(path)))
            return null;
        path = path.trim();
        if (path.indexOf('/') == -1)
            return path;
        return path.substring(path.lastIndexOf('/') + 1, path.length());
    }

    public static String getNameNoExtOfFile(String path) {
        String fileName = getNameOfFile(path);
        if ((fileName == null) || ("".equals(fileName)))
            return fileName;
        return fileName.indexOf('.') != -1 ? fileName.substring(0, fileName.lastIndexOf('.')) : fileName;
    }

    private static void verification(boolean isOK, String message) {
        if (!isOK) {
            RuntimeException ex = new RuntimeException(message);
            throw ex;
        }
    }


    public static boolean isLongNull(Long value) {
        return (value == null) || (value.intValue() == 0);
    }

    public static boolean isIntegerNull(Integer value) {
        return (value == null) || (value.intValue() == 0);
    }

    /**
     * 判断文件名是否带盘符，重新处理
     *
     * @param fileName
     * @return
     */
    public static String getFileName(String fileName) {
        //判断是否带有盘符信息
        // Check for Unix-style path
        int unixSep = fileName.lastIndexOf('/');
        // Check for Windows-style path
        int winSep = fileName.lastIndexOf('\\');
        // Cut off at latest possible point
        int pos = (winSep > unixSep ? winSep : unixSep);
        if (pos != -1) {
            // Any sort of path separator found...
            fileName = fileName.substring(pos + 1);
        }
        //替换上传文件名字的特殊字符
        fileName = fileName.replace("=", "").replace(",", "").replace("&", "");
        return fileName;
    }

    static class NumberUtil {
        private static String[] quantity = {"", "拾", "佰", "仟", "万", "拾", "佰", "仟", "亿", "拾", "佰", "仟"};

        private static String[] bigNumber = {"零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖"};

        private static int c = 4;

        private static int d = 8;

        private static int e = 1;

        private static int f = 2;

        private static int g = 4;

        private static int h = 8;

        public static String formatString(double paramDouble) {
            return formatString(new DecimalFormat("#.##################################").format(paramDouble));
        }

        public static String formatString(int value) {
            return formatString(String.valueOf(value));
        }

        public static String formatString(BigDecimal value) {
            return formatString(new DecimalFormat("#.##################################").format(value));
        }

        public static String formatString(String value) {
            if ((value == null) || ("".equals(value))) {
                return null;
            }

            Double.valueOf(value);
            StringBuffer sb = new StringBuffer();
            if (value.charAt(0) == '-') {
                sb.append("负");
                value = value.substring(1);
            }

            String[] valueArray = value.split("[.]");
            if ((valueArray.length > 2) || (valueArray.length < 1)) {
                throw new RuntimeException("非法的数值格式：" + value);
            }
            sb.append(smallToBig(valueArray[0]));
            if (valueArray.length == 2) {
                sb.append("点");
                for (int k : valueArray[1].toCharArray())
                    sb.append(bigNumber[(k - 48)]);
            }
            return sb.toString();
        }

        private static String smallToBig(String value) {
            StringBuffer sb = new StringBuffer();
            int i = 0;
            for (int j = 0; j < value.length(); j++) {
                int k = value.length() - j - 1;
                String str = quantity[k];
                int m = value.charAt(j) - '0';
                if (m == 0) {
                    if (((str.equals("亿")) && ((i & g) > 0)) || ((str.equals("万")) && ((i & f) > 0))) {
                        sb.append(str);
                    }
                    if (((i & h) == 0) && (j == value.length() - 1))
                        sb.append(bigNumber[m]);
                    i |= e;
                } else {
                    if (((i & e) > 0) && ((i & h) > 0))
                        sb.append("零");
                    if (k >= d)
                        i |= g;
                    else if (k >= c)
                        i |= f;
                    i &= (e ^ 0xFFFFFFFF);
                    sb.append(bigNumber[m]);
                    sb.append(str);
                    i |= h;
                }
            }

            return sb.toString();
        }

        public static String toMoeny(String value) {
//			CommonUtil.a((value != null) && (!"".equals(value)), "传入的数值不能为空。");
            if (value.indexOf('点') >= 0) {
                String[] valueArray = value.split("点");
//				CommonUtil.a(valueArray.length == 2, "非法的数字字符串：" + value);
//				CommonUtil.a(valueArray[1].length() <= 2, "超出精度的金额数值：" + value);
                StringBuffer sb = new StringBuffer(valueArray[0]);
                sb.append("元");
                sb.append(valueArray[1].charAt(0));
                sb.append("角");
                if (valueArray[1].length() == 2) {
                    sb.append(valueArray[1].charAt(1));
                    sb.append("分");
                }
                return sb.toString();
            }
            return value + "元整";
        }
    }

    /**
     * 根据正则表达式拆分动态计算公式
     *
     * @param expressionStr
     * @return
     */
    public static List<String> getExpressionKey(String expressionStr) {
        if (StringUtils.isEmpty(expressionStr)) {
            return Lists.newArrayList();
        }
        String[] split = expressionStr.split("[^\\w\\d]+");
        if (split.length < 1) {
            return Lists.newArrayList();
        }
        List<String> keyList = new ArrayList<>(Arrays.asList(split));
        keyList.removeIf(e -> StringUtils.isEmpty(e));
        return keyList;
    }

    /**
     * 根据正则表达式拆分动态计算公式并替换成新的计算表达式
     *
     * @param expressionStr
     * @return
     */
    public static String replaceExpression(List<String> keyList, String expressionStr) {
        if (CollectionUtils.isEmpty(keyList) || StringUtils.isEmpty(expressionStr)) {
            return null;
        }
        HashSet<String> set = Sets.newHashSet(keyList);
        for (String str : set) {
            expressionStr = expressionStr.replaceAll(str, "U" + str);
        }
        return expressionStr;
    }


    /**
     * 公式计算
     *
     * @param expressionStr 公式的表达式
     * @param map           传入参数和值
     * @param margin        保留小数位数
     * @return
     */
    public static BigDecimal convertToCode(String expressionStr, Map<String, BigDecimal> map, int margin) {
        if (StringUtils.isEmpty(expressionStr)) {
            return null;
        }
        JexlEngine jexlEngine = new JexlEngine();
        Expression expression = jexlEngine.createExpression(expressionStr);
        JexlContext jexlContext = new MapContext();
        //需要set源代码Math，否则报错
        jexlContext.set("Math", Math.class);
        //需要set源代码 BigDecimal，否则报错
        jexlContext.set("BigDecimal", BigDecimal.class);
        for (String key : map.keySet()) {
            Object p = map.get(key);
            if (null == p) {
                continue;
            }
            Double val = 0.0;
            if (p instanceof BigDecimal) {
                BigDecimal temp = (BigDecimal) p;
                val = temp.doubleValue();
            } else {
                if (cn.hutool.core.util.NumberUtil.isNumber(p.toString())) {
                    val = Double.valueOf(p.toString());
                }
            }
            jexlContext.set(key, val);
        }
        Object evaluate = expression.evaluate(jexlContext);
        BigDecimal result = new BigDecimal(null == evaluate ? "0" : evaluate.toString());
        return result.setScale(margin, BigDecimal.ROUND_HALF_UP);
    }


    public static void main(String[] args) {

        // 计算a+b的时候。第一种方式计算出来的值是错误的。
//        Map<String, BigDecimal> map = new HashMap<>();
////        //使用BIgDecimal可以解决计算错误的问题。
//        map.put("U311001", new BigDecimal("1"));
//        map.put("U311002", new BigDecimal("2"));
//        map.put("U311003", new BigDecimal("3"));
//        map.put("UHR030000s", new BigDecimal("2"));
        String expressionStr = "((311001+311002+311003+311004+311005+311006+311013+311014+311015+311026+311027+311028+313001+313002+313003+311019+311020+311021+311025+312013+312014+312015+346006+346007+346008+346009)" +
                "-(440202+351009+413001+421213+440301+411001+413004+421214+440302+411002+413005+421215+440303+411003+413006+421216+440304+411005+413007+422101+440305+411006+413008+422102+440307+411007+413010+422103+440308+411008+421101+422104+440309+411009+421102+422105+440501+411010+421103+422106+440502+411011+421104+422107+440506+411012+421105+422108+440601+411013+421106+422109+440603+411014+421107+422110+440605+411015+421108+422201+440606+411016+421109+422202+440701+411017+421110+422203+440702+411018+421111+422204+440703+411019+421112+422205+440704+411020+421113+422206+441102+411021+421114+422207+441103+411022+421117+422208+441104+411023+421118+422209+441105+411026+421119+422210+441107+411027+421120+422211+441108+411028+421121+422212+441109+411029+421201+441110+411030+421202+441111+411031+421203+440705+411033+421204+440706+411034+421205+431003+411035+421206+431004+411037+421207+431006+411038+421208+431007+412001+421209+431012+412002+421211+431001+412003+421212)" +
                "-(441201+441202+441204)" +
                "-(440401+440801+440802+440803+440804+440805+440806+440807+440808+440809+440810+440811+440850)" +
                "-(440503+440505+441006+441021+441001+441002+441003+441004+441005+441009+441010+441013+441014+441015+441016+441017+441018+441019+441020+441106+431009)" +
                "-(RD0001+RD0002)" +
                "-(344001+344003+441011+441012+451005+451006+451008+451013+451014+451016+451017+451018+451022+440901+440902+440903+351001+351003+351010)+345004+351007+346010+351012+451020+344004+440904+440101+440102+431005+431013+431002+341001+341002+341005+441101+441112+441115\n" +
                "+PL4200+236101+236102+236103+234201+234202+PL4320+234201+234202+351012+451020+344004+440904)/HR030000s";
        List<String> expressionKey = getExpressionKey(expressionStr);
        String m = "{\"U431013\":0,\"U431012\":-463662.300,\"U351012\":128.400,\"U351010\":11.210,\"U421212\":-336467.630,\"U311001\":28849976.200,\"U421211\":-117891.240,\"U421214\":-14950.130,\"U421213\":-8287.520,\"U311004\":-228664.160,\"U311005\":762.500,\"U311002\":15572119.230,\"U311003\":504129.660,\"U311006\":-317872.840,\"U421216\":-183750.620,\"U421215\":-21.030,\"U351003\":0,\"U351009\":64.070,\"U351007\":0,\"U351001\":1093.080,\"U421102\":-110291.820,\"U421101\":-3839030.520,\"U421104\":-71697.740,\"U421103\":-318499.830,\"U311015\":0.000,\"U311013\":1067.170,\"U413010\":-59862.530,\"U311014\":-4473.990,\"U311019\":1577316.900,\"U421109\":-55971.000,\"U440401\":-12180.180,\"U345004\":76182.890,\"U421106\":-139659.470,\"U421105\":-172510.160,\"U421108\":-1266.360,\"U421107\":-4806.680,\"U440309\":-3949.150,\"U440308\":-21657.730,\"U413001\":-57304.140,\"U413004\":-527577.430,\"U413005\":-38747.230,\"U413006\":70181.020,\"U413007\":-437859.820,\"U413008\":-131008.270,\"U422202\":-22228.160,\"U421113\":0,\"U422201\":-418774.030,\"U421112\":-6898.840,\"U422204\":-20700.110,\"U422203\":-311180.590,\"U421114\":0,\"U421111\":0,\"U421110\":-25932.740,\"U422209\":-10238.550,\"U422206\":-367422.130,\"U421117\":-275181.900,\"U422205\":-41187.120,\"U422208\":-96966.510,\"U421119\":-68173.430,\"U422207\":0,\"U421118\":-35882.060,\"U422212\":-80.000,\"U421120\":-313271.310,\"U422211\":-3210.000,\"U422210\":-7706.510,\"U421121\":-15131.570,\"U440301\":-203077.440,\"U440303\":-27234.850,\"U440302\":-683921.670,\"U440305\":-345434.540,\"U440304\":-109289.350,\"U440307\":-40625.380,\"U422103\":-35764.700,\"U312013\":102587.990,\"U422102\":-239766.150,\"U422105\":-437867.690,\"U422104\":-44797.730,\"U312014\":0,\"U422101\":-627787.890,\"U312015\":15218.130,\"U422107\":-2517.990,\"U422106\":-107863.460,\"U422109\":-4143.000,\"U422108\":-2752.400,\"U411038\":0,\"U346010\":0,\"U411037\":9764.440,\"U411035\":-3060269.240,\"U412003\":-9216.350,\"U411034\":-27502.950,\"U412002\":211086.450,\"U411033\":-516727.660,\"U412001\":-894003.870,\"UPL4320\":-2262797.700,\"UPL4200\":-13788561.980,\"U422110\":0,\"U341005\":0.000,\"U440202\":-306128.600,\"U411031\":0.000,\"U411030\":-149266.730,\"U341001\":-446.230,\"U341002\":173.390,\"U411028\":-1378.430,\"U440903\":-1310152.880,\"U411027\":-31167.980,\"U440902\":-133624.380,\"U411026\":-1584917.130,\"U440904\":-82188.230,\"U411023\":-326704.860,\"U411022\":9201.600,\"U411021\":4380.610,\"U411029\":-475006.960,\"U311020\":105631.570,\"U451008\":-442519.200,\"U311021\":65947.130,\"U311026\":0.000,\"U451006\":-307527.180,\"U311027\":0,\"U451005\":-21685.170,\"U346008\":10854.820,\"U441201\":-78383.630,\"U311025\":1604435.110,\"U346009\":2315.650,\"U346006\":36753.520,\"U411020\":20847.470,\"U346007\":36177.640,\"U441202\":-300.000,\"U311028\":0,\"U441204\":-79947.800,\"U411017\":-4095842.170,\"U411016\":-635396.710,\"U411015\":-616348.660,\"U411014\":-259660.810,\"U411013\":-430456.270,\"U411012\":-143475.110,\"U411011\":-5519.680,\"U411010\":-17910.560,\"U411019\":481.200,\"U411018\":-704430.780,\"U440101\":2914.230,\"U236102\":-145124.000,\"U236101\":-49479.000,\"U440102\":0,\"U440901\":-403257.190,\"U236103\":0,\"U411006\":-17852.400,\"U440804\":-43747.500,\"U411005\":-85070.390,\"U440803\":-29302.080,\"U440806\":-2791.060,\"U411003\":-444029.950,\"U440805\":-1594.150,\"U411002\":-507560.590,\"U440808\":-5947.040,\"U411001\":-13059298.700,\"U440807\":0,\"U440809\":-351953.380,\"U411009\":-39152.920,\"U411008\":-9035.450,\"U411007\":-53728.860,\"U441102\":-7141.650,\"U441101\":0,\"U441104\":-60215.740,\"U441103\":37.940,\"U441106\":0,\"U451022\":-143187.160,\"U441105\":-120641.990,\"U441108\":-34.080,\"U440811\":-1.050,\"U451020\":-169702.350,\"U441107\":-396.000,\"U440810\":-99306.630,\"U441109\":-5604.290,\"U451018\":15.320,\"U451017\":0,\"U451016\":-9103.510,\"U451014\":-75843.770,\"U451013\":3271.990,\"U440802\":-64058.420,\"U440801\":-653788.990,\"U440705\":-20689.010,\"U440704\":-1016.640,\"U440706\":-7422.580,\"U313003\":-94.840,\"U313002\":-3963.720,\"U313001\":-27344.330,\"U441001\":-3368.580,\"U441003\":-51266.420,\"U441002\":-52902.260,\"U441005\":-1465.120,\"U441004\":-1262.560,\"U441006\":-10912.870,\"U441009\":-21266.990,\"U441111\":-183720.240,\"U441110\":-22195.950,\"U441112\":8.660,\"U441115\":0,\"U440701\":-207385.950,\"U440703\":-883.140,\"U440702\":-40965.130,\"U440606\":-38005.920,\"U440605\":-66337.110,\"U441021\":-68779.960,\"U441020\":-13345.090,\"U344003\":48826.130,\"U440850\":-41447.140,\"U344004\":622246.980,\"U344001\":206791.980,\"U441010\":-17955.120,\"U441012\":-30720.990,\"U441011\":-15848.230,\"U441014\":-6560.900,\"U441013\":-13459.710,\"U441016\":-28253.340,\"U441015\":-32815.500,\"U441018\":-217413.170,\"U441017\":-178308.760,\"U440601\":-102097.090,\"U441019\":-37284.640,\"U440603\":-305776.640,\"U440506\":-210685.840,\"U431004\":1810.790,\"U431003\":-1778537.320,\"U431002\":0,\"U431001\":-426501.220,\"U431007\":-10103.430,\"U431006\":-12305.440,\"U431005\":0,\"U431009\":-3474.310,\"U421201\":-4637789.100,\"U421203\":-59406.410,\"U421202\":0.000,\"U421209\":-5720.870,\"U421208\":-17841.460,\"U440501\":-93340.100,\"URD0002\":32747.620,\"URD0001\":1349262.430,\"U421205\":-7298.480,\"U440503\":-14477.490,\"U234202\":7185.000,\"U440502\":-65815.190,\"U421204\":-34552.500,\"U234201\":74119.000,\"U421207\":-49901.520,\"U440505\":-135.900,\"UHR030000s\":5559,\"U421206\":-57523.320}";
        Map map = JSON.parseObject(m, Map.class);
        expressionKey.forEach(key -> {
            key = "U" + key;
            if (!map.containsKey(key)) {
                System.out.println(key);
                map.put("U" + key, BigDecimal.ZERO);
            }

        });
        expressionStr = replaceExpression(expressionKey, expressionStr);
        BigDecimal bigDecimal = CommonUtil.convertToCode(expressionStr, map, 2);
        System.out.println(bigDecimal);

    }

}
