import java.math.BigDecimal;
import java.util.*;
public class App {
private static final String InvalidInput = "Invalid input please try again!";
private static final String EnterIncomeLabel = "Enter Income($): ";
private static final String OutputTaxLabel = "Tax: ";
private static final String ContinueLabel = "Continue[y/n] : ";
private static final String OutputTax = "Your Tax percent is : ";
// static tax criteria for tax computation version 1
private static final List<TaxCriterion> taxCriteria = new ArrayList<>(
Arrays.asList(
new TaxCriterion(
new BigDecimal("0"),
new BigDecimal("50000"),
new BigDecimal("1")),
new TaxCriterion(
new BigDecimal("50000"),
new BigDecimal("75000"),
new BigDecimal("2")),
new TaxCriterion(
new BigDecimal("75000"),
new BigDecimal("100000"),
new BigDecimal("3")),
new TaxCriterion(
new BigDecimal("100000"),
new BigDecimal("250000"),
new BigDecimal("4")),
new TaxCriterion(
new BigDecimal("250000"),
new BigDecimal("500000"),
new BigDecimal("5")),
new TaxCriterion(
new BigDecimal("500000"),
null,
new BigDecimal("6"))));
public static void main(String[] args) {
final Scanner scanner = new Scanner(System.in);
boolean isContinue;
printer("Tax Calc start", true);
do {
// income input
final BigDecimal income = getInputBigDecimal(scanner, EnterIncomeLabel);
// computed tax
final BigDecimal tax = getTax(income);
// final BigDecimal tax = getTaxVersion2(income);
printer(OutputTaxLabel, false);
printer(tax.toPlainString(), true);
isContinue = validatedContinue(scanner);
} while (isContinue);
printer("Tax Calc end", false);
}
// tax computation version 1
public static BigDecimal getTax(BigDecimal income) {
// init computedTax
BigDecimal computedTax = new BigDecimal(0);
// loop in tax criteria
for( final TaxCriterion taxCriterion : taxCriteria) {
final int compareFrom = taxCriterion.getFrom().compareTo(income);
final Optional<Integer> compareTo = Optional.ofNullable(taxCriterion.getTo()).isPresent()
? Optional.of(taxCriterion.getTo().compareTo(income)) : Optional.empty();
// find tax by income range then compute tax by found tax percentage
if(compareFrom >= 0 || !compareTo.isPresent() || compareTo.get() >= 0) {
printer(OutputTax, false);
printer(taxCriterion.getPercentage().toPlainString(), true);
// percentage/100
final BigDecimal percentToDecimal = taxCriterion.getPercentage()
.divide(new BigDecimal("100"));
// income * (percentage/100)
computedTax = income.multiply(percentToDecimal);
break;
}
}
return computedTax;
}
// tax computation version2
public static BigDecimal getTaxVersion2(BigDecimal income) {
// init computedTax
BigDecimal computedTax = new BigDecimal(0);
printer(OutputTax, false);
// check income range to compute tax
if (new BigDecimal("0").compareTo(income) < 0 && new BigDecimal("50000").compareTo(income) >= 0) {
printer("1", true);
computedTax = income.multiply(percentageToDec(1));
} else if (new BigDecimal("50000").compareTo(income) < 0 && new BigDecimal("75000").compareTo(income) >= 0) {
printer("2", true);
computedTax = income.multiply(percentageToDec(2));
} else if (new BigDecimal("75000").compareTo(income) < 0 && new BigDecimal("100000").compareTo(income) >= 0) {
printer("3", true);
computedTax = income.multiply(percentageToDec(3));
} else if (new BigDecimal("100000").compareTo(income) < 0 && new BigDecimal("250000").compareTo(income) >= 0) {
printer("4", true);
computedTax = income.multiply(percentageToDec(4));
} else if (new BigDecimal("250000").compareTo(income) < 0 && new BigDecimal("500000").compareTo(income) >= 0) {
printer("5", true);
computedTax = income.multiply(percentageToDec(5));
} else if (new BigDecimal("500000").compareTo(income) < 0) {
printer("6", true);
computedTax = income.multiply(percentageToDec(6));
}
return computedTax;
}
private static BigDecimal percentageToDec(int percentage) {
return new BigDecimal(percentage)
.divide(new BigDecimal("100"));
}
public static void printer(final String text, final boolean newLine) {
if (newLine) {
System.out.println(text);
} else {
System.out.print(text);
}
}
private static BigDecimal getInputBigDecimal(final Scanner scanner,
final String label) {
Optional<BigDecimal> option = Optional.empty();
do {
try {
// input label
printer(label, false);
// input
option = Optional.of(new BigDecimal(scanner.nextLine()));
} catch (NullPointerException | NumberFormatException ignored) {
printer("\n", false);
printer(InvalidInput, true);
}
// re enter if entered value was invalid
} while (!option.isPresent());
return option.orElse(null);
}
private static String getInputText(final Scanner scanner,
final String label) {
Optional<String> option = Optional.empty();
do {
try {
// input label
printer(label, false);
// input
option = Optional.ofNullable(scanner.nextLine());
} catch (NullPointerException ignored) {
printer("\n", false);
printer(InvalidInput, true);
}
// re enter if entered value was invalid
} while (!option.isPresent());
return option.orElse(null);
}
private static Boolean isContinue(final String input) {
Boolean isContinue;
switch (input.toLowerCase()) {
case "y":
isContinue = true;
break;
case "n":
isContinue = false;
break;
default:
isContinue = null;
break;
}
return isContinue;
}
private static boolean validatedContinue(final Scanner scanner) {
// label and input
String option = getInputText(scanner, ContinueLabel);
// re-enter if option is null
while (isContinue(option) == null) {
printer(InvalidInput, true);
option = getInputText(scanner, ContinueLabel);
}
return isContinue(option);
}
public static class TaxCriterion {
private final BigDecimal from;
private final BigDecimal to;
private final BigDecimal percentage;
public TaxCriterion(BigDecimal from, BigDecimal to, BigDecimal percentage) {
this.from = from;
this.to = to;
this.percentage = percentage;
}
public BigDecimal getFrom() {
return from;
}
public BigDecimal getTo() {
return to;
}
public BigDecimal getPercentage() {
return percentage;
}
}
}