package com.yanzuoguang.util.helper;

import java.math.BigDecimal;
import java.math.RoundingMode;

/**
 * 浮点数计算
 *
 * @author 颜佐光
 */
public class CalcHelper {

    private static final int DEF_DIV_SCALE = 10;

    /**
     * 相加
     *
     * @param d1 参数1
     * @param d2 参数2
     * @return 结果
     */
    public static double add(double d1, double d2) {
        BigDecimal b1 = new BigDecimal(Double.toString(d1));
        BigDecimal b2 = new BigDecimal(Double.toString(d2));
        return b1.add(b2).doubleValue();
    }

    /**
     * 相加
     *
     * @param d1 参数1
     * @param d2 参数2
     * @return 结果
     */
    public static double addDouble(Double d1, Double d2) {
        return add(StringHelper.toDouble(d1), StringHelper.toDouble(d2));
    }

    /**
     * 相加
     *
     * @param d1 参数1
     * @param d2 参数2
     * @return 结果
     */
    public static double addList(double d1, double... d2) {
        double ret = d1;
        for (double item : d2) {
            ret = add(ret, item);
        }
        return ret;
    }

    /**
     * 相加
     *
     * @param d1 参数1
     * @param d2 参数2
     * @return 结果
     */
    public static double addListDouble(Double d1, Double... d2) {
        double ret = d1;
        for (double item : d2) {
            ret = add(ret, item);
        }
        return ret;
    }

    /**
     * 相减
     *
     * @param d1 参数1
     * @param d2 参数2
     * @return 结果
     */
    public static double sub(double d1, double d2) {
        BigDecimal b1 = new BigDecimal(Double.toString(d1));
        BigDecimal b2 = new BigDecimal(Double.toString(d2));
        return b1.subtract(b2).doubleValue();
    }

    /**
     * 相减
     *
     * @param d1 参数1
     * @param d2 参数2
     * @return 结果
     */
    public static double subDouble(Double d1, Double d2) {
        return sub(StringHelper.toDouble(d1), StringHelper.toDouble(d2));
    }

    /**
     * 相减
     *
     * @param d1 参数1
     * @param d2 参数2
     * @return 结果
     */
    public static double subList(double d1, double... d2) {
        double ret = d1;
        for (double item : d2) {
            ret = sub(ret, item);
        }
        return ret;
    }

    /**
     * 相减
     *
     * @param d1 参数1
     * @param d2 参数2
     * @return 结果
     */
    public static double subListDouble(Double d1, Double... d2) {
        double ret = d1;
        for (double item : d2) {
            ret = sub(ret, item);
        }
        return ret;
    }

    /**
     * 相乘
     *
     * @param d1 参数1
     * @param d2 参数2
     * @return 结果
     */
    public static double mul(double d1, double d2) {
        BigDecimal b1 = new BigDecimal(Double.toString(d1));
        BigDecimal b2 = new BigDecimal(Double.toString(d2));
        return b1.multiply(b2).doubleValue();
    }

    /**
     * 相乘
     *
     * @param d1 参数1
     * @param d2 参数2
     * @return 结果
     */
    public static double mulDouble(Double d1, Double d2) {
        return mul(StringHelper.toDouble(d1), StringHelper.toDouble(d2));
    }

    /**
     * 相乘
     *
     * @param d1 参数1
     * @param d2 参数2
     * @return 结果
     */
    public static double mulList(double d1, double... d2) {
        double ret = d1;
        for (double item : d2) {
            ret = mul(ret, item);
        }
        return ret;
    }

    /**
     * 相乘
     *
     * @param d1 参数1
     * @param d2 参数2
     * @return 结果
     */
    public static double mulListDouble(Double d1, Double... d2) {
        double ret = d1;
        for (double item : d2) {
            ret = mul(ret, item);
        }
        return ret;
    }

    /**
     * 相除
     *
     * @param d1 参数1
     * @param d2 参数2
     * @return 结果
     */
    public static double div(double d1, double d2) {
        return div(d1, d2, DEF_DIV_SCALE);
    }

    /**
     * 相除
     *
     * @param d1 参数1
     * @param d2 参数2
     * @return 结果
     */
    public static double divDouble(Double d1, Double d2) {
        return div(StringHelper.toDouble(d1), StringHelper.toDouble(d2));
    }

    /**
     * 相除
     *
     * @param d1    参数1
     * @param d2    参数2
     * @param scale 保留小数
     * @return 结果
     */
    public static double div(double d1, double d2, int scale) {
        if (scale < 0) {
            throw new IllegalArgumentException("The scale must be a positive integer or zero");
        }
        BigDecimal b1 = new BigDecimal(Double.toString(d1));
        BigDecimal b2 = new BigDecimal(Double.toString(d2));
        return b1.divide(b2, scale, RoundingMode.HALF_UP).doubleValue();
    }

    /**
     * 相除
     *
     * @param d1    参数1
     * @param d2    参数2
     * @param scale 保留小数
     * @return 结果
     */
    public static double divDouble(Double d1, Double d2, int scale) {
        return div(StringHelper.toDouble(d1), StringHelper.toDouble(d2), scale);
    }

    /**
     * 相除
     *
     * @param d1 参数1
     * @param d2 参数2
     * @return 结果
     */
    public static double divList(double d1, double... d2) {
        double ret = d1;
        for (double item : d2) {
            ret = div(ret, item);
        }
        return ret;
    }

    /**
     * 相除
     *
     * @param d1 参数1
     * @param d2 参数2
     * @return 结果
     */
    public static double divListDouble(Double d1, Double... d2) {
        double ret = d1;
        for (double item : d2) {
            ret = div(ret, item);
        }
        return ret;
    }


    /**
     * 转换为金额
     *
     * @param from         来源数据
     * @param scale        保留浮点数
     * @param roundingMode 四舍五入类型
     * @return 转换为金额
     */
    public static double toMoney(double from, int scale, int roundingMode) {
        return new BigDecimal(Double.toString(from))
                .setScale(scale, roundingMode)
                .doubleValue()
                ;
    }

    /**
     * 转换为金额
     *
     * @param from 来源数据
     * @return 转换为金额
     */
    public static double toMoney(double from) {
        return toMoney(from, 2, BigDecimal.ROUND_HALF_UP);
    }

    /**
     * 判断是否相等
     *
     * @param d1 参数1
     * @param d2 参数2
     * @return 结果
     */
    public static boolean equals(double d1, double d2) {
        BigDecimal b1 = new BigDecimal(Double.toString(d1));
        BigDecimal b2 = new BigDecimal(Double.toString(d2));
        return b1.equals(b2);
    }
}