package com.yifu.cloud.plus.v1.yifu.insurances.util;

import com.google.common.base.Optional;

import java.math.BigDecimal;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * BigDecimal 工具类
 * @Author fxj
 * @Date 2019-09-25
 * @Description 提供精确的浮点数运算(包括加、减、乘、除、四舍五入)工具类
 **/
public class BigDecimalUtils {
        static Pattern  p= Pattern.compile("^[1-9]\\d*\\.\\d*|0\\.\\d*[1-9]\\d*$");
        /**
         * BigDecimal的加法运算封装
         * @author : shijing
         * 2017年3月23日下午4:53:21
         * @param b1
         * @param bn
         * @return
         */
        public static BigDecimal safeAdd(BigDecimal b1, BigDecimal... bn) {
            if (null == b1) {
                b1 = BigDecimal.ZERO;
            }
            if (null != bn) {
                for (BigDecimal b : bn) {
                    b1 = b1.add(null == b ? BigDecimal.ZERO : b);
                }
            }
            return b1;
        }

        /**
         * Integer加法运算的封装
         * @author : shijing
         * 2017年3月23日下午4:54:08
         * @param b1   第一个数
         * @param bn   需要加的加法数组
         * @注 ： Optional  是属于com.google.common.base.Optional<T> 下面的class
         * @return
         */
        public static Integer safeAdd(Integer b1, Integer... bn) {
            if (null == b1) {
                b1 = 0;
            }
            Integer r = b1;
            if (null != bn) {
                for (Integer b : bn) {
                    r += Optional.fromNullable(b).or(0);
                }
            }
            return r > 0 ? r : 0;
        }

        /**
         * 计算金额方法
         * @author : shijing
         * 2017年3月23日下午4:53:00
         * @param b1
         * @param bn
         * @return
         */
        public static BigDecimal safeSubtract(BigDecimal b1, BigDecimal... bn) {
            return safeSubtract(true, b1, bn);
        }

        /**
         * BigDecimal的安全减法运算
         * @author : shijing
         * 2017年3月23日下午4:50:45
         * @param isZero  减法结果为负数时是否返回0，true是返回0（金额计算时使用），false是返回负数结果
         * @param b1		   被减数
         * @param bn        需要减的减数数组
         * @return
         */
        public static BigDecimal safeSubtract(Boolean isZero, BigDecimal b1, BigDecimal... bn) {
            if (null == b1) {
                b1 = BigDecimal.ZERO;
            }
            BigDecimal r = b1;
            if (null != bn) {
                for (BigDecimal b : bn) {
                    r = r.subtract((null == b ? BigDecimal.ZERO : b));
                }
            }
            return isZero ? (r.compareTo(BigDecimal.ZERO) == -1 ? BigDecimal.ZERO : r) : r;
        }

        /**
         * 整型的减法运算，小于0时返回0
         * @author : shijing
         * 2017年3月23日下午4:58:16
         * @param b1
         * @param bn
         * @return
         */
        public static Integer safeSubtract(Integer b1, Integer... bn) {
            if (null == b1) {
                b1 = 0;
            }
            Integer r = b1;
            if (null != bn) {
                for (Integer b : bn) {
                    r -= Optional.fromNullable(b).or(0);
                }
            }
            return null != r && r > 0 ? r : 0;
        }

        /**
         * 金额除法计算，返回2位小数（具体的返回多少位大家自己看着改吧）
         * @author : shijing
         * 2017年3月23日下午5:02:17
         * @param b1
         * @param b2
         * @return
         */
        public static <T extends Number> BigDecimal safeDivide(T b1, T b2){
            return safeDivide(b1, b2, BigDecimal.ZERO);
        }

        /**
         * @description:
         * @param b1
         * @param b2
         * @return: java.math.BigDecimal
         * @author: wangweiguo
         * @date: 2021/8/5
         */
        public static <T extends Number> BigDecimal safeDivide(T b1, T b2, int scale){
            return safeDivide(b1, b2, BigDecimal.ZERO, scale);
        }


        /**
         * BigDecimal的除法运算封装，如果除数或者被除数为0，返回默认值
         * 默认返回小数位后2位，用于金额计算
         * @author : shijing
         * 2017年3月23日下午4:59:29
         * @param b1
         * @param b2
         * @param defaultValue
         * @return
         */
        public static <T extends Number> BigDecimal safeDivide(T b1, T b2, BigDecimal defaultValue) {
            if (null == b1 || null == b2) {
                return defaultValue;
            }
            try {
                return BigDecimal.valueOf(b1.doubleValue()).divide(BigDecimal.valueOf(b2.doubleValue()), 2, BigDecimal.ROUND_HALF_UP);
            } catch (Exception e) {
                return defaultValue;
            }
        }

        /**
         * @description:
         * @param b1
         * @param b2
         * @param defaultValue
         * @param scale
         * @return: java.math.BigDecimal
         * @author: wangweiguo
         * @date: 2021/8/5
         */
        public static <T extends Number> BigDecimal safeDivide(T b1, T b2, BigDecimal defaultValue, int scale) {
            if (null == b1 || null == b2) {
                return defaultValue;
            }
            try {
                return BigDecimal.valueOf(b1.doubleValue()).divide(BigDecimal.valueOf(b2.doubleValue()), scale, BigDecimal.ROUND_HALF_UP);
            } catch (Exception e) {
                return defaultValue;
            }
        }

        /**
         * BigDecimal的乘法运算封装
         * @author : shijing
         * 2017年3月23日下午5:01:57
         * @param b1
         * @param b2
         * @return
         */
        public static <T extends Number> BigDecimal safeMultiply(T b1, T b2) {
            if (null == b1 || null == b2) {
                return BigDecimal.ZERO;
            }
            return BigDecimal.valueOf(b1.doubleValue()).multiply(BigDecimal.valueOf(b2.doubleValue())).setScale(2, BigDecimal.ROUND_HALF_UP);
        }
        public static <T extends Number> BigDecimal safeMultiply(T b1, T b2, T b3) {
            if (null == b1 || null == b2 || null == b3) {
                return BigDecimal.ZERO;
            }
            return BigDecimal.valueOf(b1.doubleValue()).multiply(BigDecimal.valueOf(b2.doubleValue())).multiply(BigDecimal.valueOf(b3.doubleValue())).setScale(2, BigDecimal.ROUND_HALF_UP);
        }
    /**
     * BigDecimal的乘法运算封装
     * @author : shijing
     * 2017年3月23日下午5:01:57
     * @param b1
     * @param b2
     * @return
     */
    public static <T extends Number> BigDecimal safeMultiply(T b1, T b2,int scale) {
        if (null == b1 || null == b2) {
            return BigDecimal.ZERO;
        }
        return BigDecimal.valueOf(b1.doubleValue()).multiply(BigDecimal.valueOf(b2.doubleValue())).setScale(scale, BigDecimal.ROUND_HALF_UP);
    }
    public static <T extends Number> BigDecimal safeMultiply(T b1, T b2, T b3,int scale) {
        if (null == b1 || null == b2 || null == b3) {
            return BigDecimal.ZERO;
        }
        return BigDecimal.valueOf(b1.doubleValue()).multiply(BigDecimal.valueOf(b2.doubleValue())).multiply(BigDecimal.valueOf(b3.doubleValue())).setScale(scale, BigDecimal.ROUND_HALF_UP);
    }
    public static <T extends Number> BigDecimal safeMultiply(T b1, T b2, T b3,T b4,int scale) {
        if (null == b1 || null == b2 || null == b3) {
            return BigDecimal.ZERO;
        }
        return BigDecimal.valueOf(b1.doubleValue()).multiply(BigDecimal.valueOf(b2.doubleValue())).multiply(BigDecimal.valueOf(b3.doubleValue())).multiply(BigDecimal.valueOf(b4.doubleValue())).setScale(scale, BigDecimal.ROUND_HALF_UP);
    }
        /**
         * null 默认 为 0
         * @Author fxj
         * @Date 2019-09-25
         * @param bigDecimal
         * @return
         **/
        public static BigDecimal isNullToZero(BigDecimal bigDecimal){
            if (null == bigDecimal){
                return BigDecimal.ZERO;
            }
            return bigDecimal;
        }

	/**
	 * null 默认 为 0
	 * @Author zhaji
	 * @Date 2022-08-02
	 * @param bigDecimal
	 * @return
	 **/
	public static Boolean isNullOrZero(BigDecimal bigDecimal){
		if (null == bigDecimal){
			return true;
		}
		if (bigDecimal.compareTo(BigDecimal.ZERO) == 0){
			return true;
		}
		return false;
	}
        /**
         * 对象转为BigDecimal 数据 并四舍五入保留两位小数
         * @Author fxj
         * @Date 2019-10-14
         * @param b1
         * @return
         **/
        public static  BigDecimal objectToBigDecimal(Double b1) {
            if (null == b1) {
                return BigDecimal.ZERO;
            }
            return BigDecimal.valueOf(b1.doubleValue()).setScale(2, BigDecimal.ROUND_HALF_UP);
        }

    /**
     * 判断字符串是否是BigDecimal
     * @param str
     * @return
     */
    public static boolean isBigDecimal(String str){
        if(str==null || str.trim().length() == 0){
            return false;
        }
        char[] chars = str.toCharArray();
        int sz = chars.length;
        int i = (chars[0] == '-') ? 1 : 0;
        if(i == sz){
            return false;
        }
        if(chars[i] == '.'){
            //除了负号，第一位不能为'小数点'
            return false;
        }
        boolean radixPoint = false;
        for(; i < sz; i++){
            if(chars[i] == '.'){
                if(radixPoint){
                    return false;
                }
                radixPoint = true;
            }else if(!(chars[i] >= '0' && chars[i] <= '9')){
                return false;
            }
        }
        return true;
    }
    /**
     * 舍去BigDecimal小数点后三位
     * @param v
     * @param point
     * @return
     */
    public static BigDecimal formatByRoundDown(BigDecimal v, int point){

        return v.setScale(point, BigDecimal.ROUND_DOWN);

    }

    /**
     * 格式化精度
     *
     * @param v
     * @param point
     *            小数位数
     * @return double
     */
    public static BigDecimal formatByRoundHalfUp(BigDecimal v, int point) {
        return v.setScale(point, BigDecimal.ROUND_HALF_UP);
    }

    /**
     * 格式化精度
     *
     * @param str
     * @param point
     *            小数位数
     * @return double
     */
    public static BigDecimal getNumberOfDecimalPlace(String str, int point) {
        Matcher m=p.matcher(str);
        boolean b=m.matches();
        if(b){
        //获取小数点的位置
            int bitPos=str.indexOf(".");
        //字符串总长度减去小数点位置，再减去1，就是小数位数
            int numOfBits=str.length()-bitPos-1;
        if(numOfBits>point){
            BigDecimal big = new BigDecimal(str);
            return big.setScale(point, BigDecimal.ROUND_HALF_UP);
            }
        }
        return new BigDecimal(str);
    }
}
