package org.iilab.pb.calculator;
import java.math.BigDecimal;
import static java.math.BigDecimal.TEN;
import static java.math.BigDecimal.ZERO;
import static java.math.MathContext.DECIMAL32;
public class CalculatorImpl {
public enum Button {
ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE, ZERO,
EQUALS, PLUS, MINUS, MULTIPLY, DIVIDE, CHAR_C, DECIMAL_POINT
}
private enum Operation { PLUS, MINUS, MULTIPLY, DIVIDE };
private boolean clearOnDigit = false, negativeNumber = false;
private boolean decimalPoint = false;
private int decimalPointPlace = 0;
private BigDecimal operand1 = null, operand2 = null;
private Operation operation = null;
public String handleButtonPress(Button button) {
switch(button) {
case ONE:
return pushDigit(1).toPlainString();
case TWO:
return pushDigit(2).toPlainString();
case THREE:
return pushDigit(3).toPlainString();
case FOUR:
return pushDigit(4).toPlainString();
case FIVE:
return pushDigit(5).toPlainString();
case SIX:
return pushDigit(6).toPlainString();
case SEVEN:
return pushDigit(7).toPlainString();
case EIGHT:
return pushDigit(8).toPlainString();
case NINE:
return pushDigit(9).toPlainString();
case ZERO:
return pushDigit(0).toPlainString();
case EQUALS:
return popResult().toPlainString();
case PLUS:
return pushOperation(Operation.PLUS) ? "+" : "0";
case MINUS:
return pushOperation(Operation.MINUS) ? "-" : "0";
case MULTIPLY:
return pushOperation(Operation.MULTIPLY) ? "\u00d7" : "0";
case DIVIDE:
return pushOperation(Operation.DIVIDE) ? "\u00f7" : "0";
case CHAR_C:
return clearDisplay().toPlainString();
case DECIMAL_POINT:
return pushDecimal().toPlainString();
default:
throw new IllegalStateException();
}
}
private BigDecimal pushDigit(int digit) {
if(clearOnDigit || operand1 == null) {
if(negativeNumber) operand1 = BigDecimal.valueOf(-digit);
else operand1 = BigDecimal.valueOf(digit);
} else {
if(!decimalPoint){
operand1 = operand1.multiply(TEN);
}
if(operand1.signum() == -1) {
if(decimalPoint){
BigDecimal temp = BigDecimal.valueOf(digit);
temp = temp.movePointLeft(decimalPointPlace);
double v = operand1.doubleValue()-temp.doubleValue();
operand1 = BigDecimal.valueOf(v);
decimalPointPlace = decimalPointPlace+1;
}else{
operand1 = operand1.subtract(BigDecimal.valueOf(digit));
}
} else {
if(decimalPoint){
BigDecimal temp = BigDecimal.valueOf(digit);
temp = temp.movePointLeft(decimalPointPlace);
double v = operand1.doubleValue()+temp.doubleValue();
operand1 = BigDecimal.valueOf(v);
decimalPointPlace = decimalPointPlace+1;
}else{
operand1 = operand1.add(BigDecimal.valueOf(digit));
}
}
}
clearOnDigit = negativeNumber = false;
return operand1;
}
private BigDecimal pushDecimal() {
if(!decimalPoint){
decimalPointPlace = 0;
if(clearOnDigit || operand1 == null) {
if(negativeNumber) operand1 = BigDecimal.valueOf(-0.);
else operand1 = BigDecimal.valueOf(0.);
}
if (operand1.signum() == -1) {
decimalPointPlace = String.valueOf(operand1.intValue())
.length() - 1;
} else {
decimalPointPlace = String.valueOf(operand1.intValue())
.length();
}
decimalPoint = true;
}
/*if (operand1 != null) {
if (!decimalPoint) {
decimalPointPlace = 0;
if (operand1.signum() == -1) {
decimalPointPlace = String.valueOf(operand1.intValue())
.length() - 1;
} else {
decimalPointPlace = String.valueOf(operand1.intValue())
.length();
}
decimalPoint = true;
}
return operand1;
}else{
decimalPointPlace = 0;
if(clearOnDigit || operand1 == null) {
if(negativeNumber) operand1 = BigDecimal.valueOf(-0.);
else operand1 = BigDecimal.valueOf(0.);
}
if (operand1.signum() == -1) {
decimalPointPlace = String.valueOf(operand1.intValue())
.length() - 1;
} else {
decimalPointPlace = String.valueOf(operand1.intValue())
.length();
}
decimalPoint = true;
return operand1;
}
*/
return operand1;
}
private boolean pushOperation(Operation o) {
decimalPoint=false;
if(operand1 == null) {
if(o == Operation.MINUS && !negativeNumber) {
negativeNumber = true;
return true;
}
clear();
return false;
}
if(operand2 == null) {
clearOnDigit = negativeNumber = false;
operand2 = operand1;
operand1 = null;
operation = o;
return true;
}
clearOnDigit = negativeNumber = false;
operand2 = popResult();
operand1 = null;
operation = o;
return true;
}
private void clear() {
clearOnDigit = negativeNumber = false;
operand1 = operand2 = null;
operation = null;
decimalPoint=false;
}
private BigDecimal clearDisplay(){
clear();
return ZERO;
}
private BigDecimal popResult() {
if(operand1 == null || operand2 == null || operation == null) {
clear();
return ZERO;
}
BigDecimal result = null;
switch(operation) {
case PLUS:
result = operand2.add(operand1);
break;
case MINUS:
result = operand2.subtract(operand1);
break;
case MULTIPLY:
result = operand2.multiply(operand1);
break;
case DIVIDE:
try {
result = operand2.divide(operand1, DECIMAL32);
} catch(ArithmeticException e) {
result = ZERO;
}
break;
default:
throw new IllegalStateException();
}
clearOnDigit = true;
negativeNumber = false;
operand1 = result;
operand2 = null;
operation = null;
decimalPoint=false;
return result;
}
}