package com.rjconsultores.ventaboletos.utilerias;

import java.math.BigDecimal;
import java.math.MathContext;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.text.ParseException;
import java.util.Locale;

import org.apache.commons.lang.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

/**
 * Clase MoneyHelper
 * 
 * Referência: http://www.javapractices.com/topic/TopicAction.do?Id=13
 * 
 * @author RJ Consultores
 */
public class MoneyHelper {
	private static Logger log = LogManager.getLogger(MoneyHelper.class);

	private static int DECIMALS = 2;
	private static int ROUNDING_MODE = BigDecimal.ROUND_HALF_EVEN;
	public static BigDecimal HUNDRED = new BigDecimal("100");
	private static int MATH_CONTEXT = 2;

	public MoneyHelper() {

	}

	public static BigDecimal instanciar(String aValor) {
		return arredondar(BigDecimal.valueOf(Float.valueOf(aValor)));
	}

	public static BigDecimal instanciar(BigDecimal aValor) {
		return arredondar(aValor);
	}

	public static BigDecimal somar(BigDecimal... aAmount) {
		BigDecimal total = BigDecimal.ZERO;
		for (BigDecimal value : aAmount) {
			BigDecimal fAmountOne = value == null ? BigDecimal.ZERO : arredondar(value);
			total = total.add(fAmountOne);
		}
		return total.setScale(DECIMALS, ROUNDING_MODE);
	}

	public static BigDecimal somar(int customScale, BigDecimal... aAmount) {
		BigDecimal total = BigDecimal.ZERO;
		for (BigDecimal value : aAmount) {
			BigDecimal fAmountOne = value == null ? BigDecimal.ZERO : arredondar(value, customScale);
			total = total.add(fAmountOne);
		}
		return total.setScale(customScale, ROUNDING_MODE);
	}

	public static BigDecimal somar(BigDecimal aAmountOne, BigDecimal aAmountTwo) {
		BigDecimal fAmountOne = aAmountOne == null ? BigDecimal.ZERO : arredondar(aAmountOne);
		BigDecimal fAmountTwo = aAmountTwo == null ? BigDecimal.ZERO : arredondar(aAmountTwo);

		return fAmountOne.add(fAmountTwo).setScale(DECIMALS, ROUNDING_MODE);
	}

	public static BigDecimal somar(BigDecimal aAmountOne, BigDecimal aAmountTwo, int customScale) {
		BigDecimal fAmountOne = aAmountOne == null ? BigDecimal.ZERO : arredondar(aAmountOne, customScale);
		BigDecimal fAmountTwo = aAmountTwo == null ? BigDecimal.ZERO : arredondar(aAmountTwo, customScale);

		return fAmountOne.add(fAmountTwo).setScale(customScale, ROUNDING_MODE);
	}

	public static BigDecimal subtrair(BigDecimal aAmountOne, BigDecimal aAmountTwo) {
		BigDecimal fAmountOne = arredondar(aAmountOne);
		BigDecimal fAmountTwo = arredondar(aAmountTwo);

		return fAmountOne.subtract(fAmountTwo).setScale(DECIMALS, ROUNDING_MODE);
	}

	public static BigDecimal subtrair(BigDecimal aAmountOne, BigDecimal aAmountTwo, int customScale) {
		BigDecimal fAmountOne = arredondar(aAmountOne, customScale);
		BigDecimal fAmountTwo = arredondar(aAmountTwo, customScale);

		return fAmountOne.subtract(fAmountTwo).setScale(customScale, ROUNDING_MODE);
	}

	public static BigDecimal dividir(BigDecimal aAmount, BigDecimal aDivisor) {
		BigDecimal fAmount = arredondar(aAmount);
		BigDecimal fDivisor = arredondar(aDivisor);

		return fAmount.divide(fDivisor, DECIMALS, ROUNDING_MODE);
	}

	public static BigDecimal dividir(BigDecimal aAmount, BigDecimal aDivisor, int customScale) {
		BigDecimal fAmount = arredondar(aAmount, customScale);
		BigDecimal fDivisor = arredondar(aDivisor, customScale);

		return fAmount.divide(fDivisor, customScale, ROUNDING_MODE);
	}

	public static BigDecimal multiplicar(BigDecimal aAmount, BigDecimal aMultiplicand) {
		BigDecimal fAmount = arredondar(aAmount);
		BigDecimal fMultiplicand = arredondar(aMultiplicand);

		return fAmount.multiply(fMultiplicand, new MathContext(ROUNDING_MODE)).setScale(DECIMALS, ROUNDING_MODE);
	}

	public static BigDecimal multiplicar(BigDecimal aAmount, BigDecimal aMultiplicand, int customScale) {
		BigDecimal fAmount = arredondar(aAmount, customScale);
		BigDecimal fMultiplicand = arredondar(aMultiplicand, customScale);

		return fAmount.multiply(fMultiplicand, new MathContext(ROUNDING_MODE)).setScale(customScale, ROUNDING_MODE);
	}

	public static BigDecimal arredondar(BigDecimal aNumber) {
		if (aNumber != null) {
			return aNumber.setScale(DECIMALS, ROUNDING_MODE);
		} else {
			return null;
		}
	}

	public static BigDecimal arredondar(BigDecimal aNumber, int decimals, int rounding_mode) {
		if (aNumber != null) {
			return aNumber.setScale(decimals, rounding_mode);
		} else {
			return null;
		}
	}

	public static BigDecimal arredondar(Float aNumber) {
		return BigDecimal.valueOf(aNumber).setScale(DECIMALS, ROUNDING_MODE);
	}

	public static boolean isMaior(BigDecimal aAmountOne, BigDecimal aAmountTwo) {
		BigDecimal fAmountOne = arredondar(aAmountOne);
		BigDecimal fAmountTwo = arredondar(aAmountTwo);

		return fAmountOne.compareTo(fAmountTwo) > 0;
	}

	public static boolean isMaiorIgual(BigDecimal aAmountOne, BigDecimal aAmountTwo) {
		BigDecimal fAmountOne = arredondar(aAmountOne);
		BigDecimal fAmountTwo = arredondar(aAmountTwo);

		return fAmountOne.compareTo(fAmountTwo) >= 0;
	}

	public static boolean isMenor(BigDecimal aAmountOne, BigDecimal aAmountTwo) {
		BigDecimal fAmountOne = arredondar(aAmountOne);
		BigDecimal fAmountTwo = arredondar(aAmountTwo);

		return fAmountOne.compareTo(fAmountTwo) < 0;
	}

	public static boolean isMenorIgual(BigDecimal aAmountOne, BigDecimal aAmountTwo) {
		BigDecimal fAmountOne = arredondar(aAmountOne);
		BigDecimal fAmountTwo = arredondar(aAmountTwo);

		return fAmountOne.compareTo(fAmountTwo) <= 0;
	}

	public static boolean isIgual(BigDecimal aAmountOne, BigDecimal aAmountTwo) {
		BigDecimal fAmountOne = arredondar(aAmountOne);
		BigDecimal fAmountTwo = arredondar(aAmountTwo);

		return fAmountOne.compareTo(fAmountTwo) == 0;
	}

	public static BigDecimal getDiferenca(BigDecimal aAmountOne, BigDecimal aAmountTwo) {
		return aAmountTwo.subtract(aAmountOne);
	}

	public static BigDecimal getPercentual(BigDecimal aAmountOne, BigDecimal aAmountTwo) {

		BigDecimal diferenca = getDiferenca(aAmountOne, aAmountTwo);
		BigDecimal fractionalChange = BigDecimal.ZERO;

		if (diferenca != null && (diferenca.compareTo(BigDecimal.ZERO) != 0) && (aAmountOne.compareTo(BigDecimal.ZERO) != 0)) {
			fractionalChange = diferenca.divide(aAmountOne, new MathContext(MATH_CONTEXT));
		}
		return arredondar(fractionalChange.multiply(HUNDRED)).abs();
	}

	public static BigDecimal getValorDescontadoPercentual(BigDecimal valor, BigDecimal percdesconto) {
		BigDecimal valorDescontado = multiplicar(valor, percdesconto).divide(HUNDRED);
		return arredondar(subtrair(valor, valorDescontado));
	}

	public static BigDecimal getPercentualValor(BigDecimal valorTotal, BigDecimal valorPercentual) {
		if (valorTotal != null && valorPercentual != null) {
			return dividir(dividir(multiplicar(valorTotal, valorPercentual), HUNDRED), HUNDRED);
		}
		return BigDecimal.ZERO;
	}

	/**
	 * Converte uma string no formato de moeda em um {@link BigDecimal}
	 * 
	 * @param valor
	 * @return
	 */
	public static BigDecimal getValor(String valor) {
		try {
			if (StringUtils.isNotBlank(valor)) {
				NumberFormat nf = DecimalFormat.getCurrencyInstance(Locale.getDefault());
				nf.setMinimumFractionDigits(DECIMALS);
				nf.setMaximumFractionDigits(DECIMALS);
				return arredondar(nf.parse(valor).floatValue());
			}
		} catch (ParseException e) {
			log.error(e.getMessage(), e);
		}
		return null;
	}

	public static String getValor(BigDecimal valor) {
		NumberFormat nf = NumberFormat.getInstance(Locale.getDefault());
		return nf.format(valor);
	}

	public static BigDecimal arredondar(BigDecimal aNumber, int customScale) {
		return aNumber.setScale(customScale, ROUNDING_MODE);
	}

}
