package com.mdraco.calculator.data;
import com.mdraco.calculator.Operation;
import java.util.Stack;
/**
* Simple calculator that can parse input and calculate output.
* Works only on integers.
* User: mateusz
* Date: 14.04.2013
* Time: 10:14
* Created with IntelliJ IDEA.
*/
public class SimpleCalculator {
private final Stack<Operation> operations;
private final Stack<Integer> values;
private SimpleCalculator subCalculator;
/**
* Clean constructor. Does nothing and waits for operations and values.
*/
public SimpleCalculator() {
this.operations = new Stack<Operation>();
this.values = new Stack<Integer>();
}
/**
* Constructor that parses input string.
* @param s string that will be parsed
*/
public SimpleCalculator(String s) {
this();
parseString(s);
}
/**
* Adds a value to constructor.
* @param value new value
*/
public void add(int value) {
if (subCalculator != null)
subCalculator.add(value);
else {
if (!operations.isEmpty() && operations.peek() == Operation.Subtract) {
operations.pop();
value *= -1;
if (!operations.isEmpty() || !values.isEmpty()) {
operations.push(Operation.Add);
}
}
values.push(value);
}
}
/**
* Adds new operation.
* @param operation new operation
*/
public void add(Operation operation) {
if (operation == Operation.BlockEnd) {
if (subCalculator == null)
throw new UnsupportedOperationException("missing opening bracket");
if (subCalculator.subCalculator != null)
subCalculator.add(operation);
else {
int val = subCalculator.calculate();
subCalculator = null;
add(val);
}
}
else if (subCalculator != null) {
subCalculator.add(operation);
}
else if (operation == Operation.BlockBegin)
this.subCalculator = new SimpleCalculator();
else
{
while (!this.operations.isEmpty() && this.operations.peek().getSignificance() > operation.getSignificance())
{
add(this.operations.pop().calculate(this.values.pop(), this.values.pop()));
}
this.operations.push(operation);
}
}
/**
* Calculates result.
* @return integer result
* @throws UnsupportedOperationException when there is wrong number of operations or any other problem application throws exception
*/
public int calculate() throws UnsupportedOperationException {
if (subCalculator != null)
throw new UnsupportedOperationException("missing closing bracket");
int result = 0;
if (!values.isEmpty()) {
result = values.pop();
while (!values.isEmpty()) {
if (operations.isEmpty())
throw new UnsupportedOperationException("missing operation");
if (values.isEmpty())
throw new UnsupportedOperationException("missing value");
Operation operation = operations.pop();
result = operation.calculate(values.pop(), result);
}
}
if (!operations.isEmpty())
throw new UnsupportedOperationException("wrong number of arguments");
return result;
}
/**
* Clears all the input, parse string and add any number or operator found in input string.
* @param text proper input string
* @return self
*/
public SimpleCalculator parseString(String text)
{
clear();
String current = "";
for (Character c : text.toCharArray())
{
if (Character.isWhitespace(c))
continue;
if (Character.isDigit(c))
{
current += c;
}
else
{
if (!current.isEmpty())
{
add(Integer.parseInt(current, 10));
current = "";
}
add(Operation.parseChar(c));
}
}
if (!current.isEmpty())
add(Integer.parseInt(current, 10));
return this;
}
/**
* Clear all input.
*/
public void clear() {
this.operations.clear();
this.values.clear();
}
}