Revert "Calculator display changes"

This reverts commit b3cc081f47.
This commit is contained in:
serso
2012-09-21 10:26:45 +04:00
parent b3cc081f47
commit cca775c2ac
12 changed files with 1485 additions and 1528 deletions

View File

@@ -1,30 +1,25 @@
package org.solovyev.android.calculator;
import jscl.NumeralBase;
import jscl.math.Generic;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.solovyev.android.calculator.jscl.JsclOperation;
import org.solovyev.common.msg.MessageRegistry;
/**
* User: Solovyev_S
* Date: 20.09.12
* Time: 16:38
*/
public interface Calculator extends CalculatorEventContainer {
@NotNull
CalculatorEventDataId createFirstEventDataId();
void evaluate(@NotNull JsclOperation operation,
@NotNull String expression);
@NotNull
CalculatorEventDataId evaluate(@NotNull JsclOperation operation,
@NotNull String expression,
@Nullable MessageRegistry mr);
@NotNull
CalculatorEventDataId convert(@NotNull Generic generic, @NotNull NumeralBase to);
}
package org.solovyev.android.calculator;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.solovyev.android.calculator.jscl.JsclOperation;
import org.solovyev.common.msg.MessageRegistry;
/**
* User: Solovyev_S
* Date: 20.09.12
* Time: 16:38
*/
public interface Calculator extends CalculatorEventContainer {
@NotNull
CalculatorEventDataId createFirstEventDataId();
void evaluate(@NotNull JsclOperation operation,
@NotNull String expression);
@NotNull
CalculatorEventDataId evaluate(@NotNull JsclOperation operation,
@NotNull String expression,
@Nullable MessageRegistry mr);
}

View File

@@ -1,58 +1,58 @@
package org.solovyev.android.calculator;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.solovyev.android.calculator.jscl.JsclOperation;
/**
* User: serso
* Date: 9/20/12
* Time: 10:01 PM
*/
public class CalculatorEvaluationEventDataImpl implements CalculatorEvaluationEventData {
@NotNull
private final CalculatorEventData calculatorEventData;
@NotNull
private final JsclOperation operation;
@NotNull
private final String expression;
public CalculatorEvaluationEventDataImpl(@NotNull CalculatorEventData calculatorEventData,
@NotNull JsclOperation operation,
@NotNull String expression) {
this.calculatorEventData = calculatorEventData;
this.operation = operation;
this.expression = expression;
}
@NotNull
@Override
public JsclOperation getOperation() {
return this.operation;
}
@NotNull
@Override
public String getExpression() {
return this.expression;
}
@Override
public long getEventId() {
return calculatorEventData.getEventId();
}
@Override
@Nullable
public Long getSequenceId() {
return calculatorEventData.getSequenceId();
}
@Override
public boolean isAfter(@NotNull CalculatorEventDataId calculatorEventDataId) {
return calculatorEventData.isAfter(calculatorEventDataId);
}
}
package org.solovyev.android.calculator;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.solovyev.android.calculator.jscl.JsclOperation;
/**
* User: serso
* Date: 9/20/12
* Time: 10:01 PM
*/
public class CalculatorEvaluationEventDataImpl implements CalculatorEvaluationEventData {
@NotNull
private final CalculatorEventData calculatorEventData;
@NotNull
private final JsclOperation operation;
@NotNull
private final String expression;
public CalculatorEvaluationEventDataImpl(@NotNull CalculatorEventData calculatorEventData,
@NotNull JsclOperation operation,
@NotNull String expression) {
this.calculatorEventData = calculatorEventData;
this.operation = operation;
this.expression = expression;
}
@NotNull
@Override
public JsclOperation getOperation() {
return this.operation;
}
@NotNull
@Override
public String getExpression() {
return this.expression;
}
@Override
public long getEventId() {
return calculatorEventData.getEventId();
}
@Override
@Nullable
public Long getCalculationId() {
return calculatorEventData.getCalculationId();
}
@Override
public boolean isAfter(@NotNull CalculatorEventDataId calculatorEventDataId) {
return calculatorEventData.isAfter(calculatorEventDataId);
}
}

View File

@@ -1,21 +1,20 @@
package org.solovyev.android.calculator;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* User: Solovyev_S
* Date: 20.09.12
* Time: 18:18
*/
public interface CalculatorEventDataId {
// the higher id => the later event
long getEventId();
// the higher id => the later event
@Nullable
Long getSequenceId();
boolean isAfter(@NotNull CalculatorEventDataId calculatorEventDataId);
}
package org.solovyev.android.calculator;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* User: Solovyev_S
* Date: 20.09.12
* Time: 18:18
*/
public interface CalculatorEventDataId {
// the higher id => the later event
long getEventId();
@Nullable
Long getCalculationId();
boolean isAfter(@NotNull CalculatorEventDataId calculatorEventDataId);
}

View File

@@ -1,64 +1,66 @@
package org.solovyev.android.calculator;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* User: Solovyev_S
* Date: 20.09.12
* Time: 18:18
*/
class CalculatorEventDataIdImpl implements CalculatorEventDataId {
private final long eventId;
@Nullable
private final Long sequenceId;
private CalculatorEventDataIdImpl(long id, @Nullable Long sequenceId) {
this.eventId = id;
this.sequenceId = sequenceId;
}
@NotNull
static CalculatorEventDataId newInstance(long id, @Nullable Long sequenceId) {
return new CalculatorEventDataIdImpl(id, sequenceId);
}
@Override
public long getEventId() {
return this.eventId;
}
@Nullable
@Override
public Long getSequenceId() {
return this.sequenceId;
}
@Override
public boolean isAfter(@NotNull CalculatorEventDataId calculatorEventDataId) {
return this.eventId > calculatorEventDataId.getEventId();
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof CalculatorEventDataIdImpl)) return false;
CalculatorEventDataIdImpl that = (CalculatorEventDataIdImpl) o;
if (eventId != that.eventId) return false;
if (sequenceId != null ? !sequenceId.equals(that.sequenceId) : that.sequenceId != null)
return false;
return true;
}
@Override
public int hashCode() {
int result = (int) (eventId ^ (eventId >>> 32));
result = 31 * result + (sequenceId != null ? sequenceId.hashCode() : 0);
return result;
}
}
package org.solovyev.android.calculator;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* User: Solovyev_S
* Date: 20.09.12
* Time: 18:18
*/
class CalculatorEventDataIdImpl implements CalculatorEventDataId {
private final long eventId;
@Nullable
private final Long calculationId;
private CalculatorEventDataIdImpl(long id,
@Nullable Long calculationId) {
this.eventId = id;
this.calculationId = calculationId;
}
@NotNull
static CalculatorEventDataId newInstance(long id,
@Nullable Long calculationId) {
return new CalculatorEventDataIdImpl(id, calculationId);
}
@Override
public long getEventId() {
return this.eventId;
}
@Nullable
@Override
public Long getCalculationId() {
return this.calculationId;
}
@Override
public boolean isAfter(@NotNull CalculatorEventDataId calculatorEventDataId) {
return this.eventId > calculatorEventDataId.getEventId();
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof CalculatorEventDataIdImpl)) return false;
CalculatorEventDataIdImpl that = (CalculatorEventDataIdImpl) o;
if (eventId != that.eventId) return false;
if (calculationId != null ? !calculationId.equals(that.calculationId) : that.calculationId != null)
return false;
return true;
}
@Override
public int hashCode() {
int result = (int) (eventId ^ (eventId >>> 32));
result = 31 * result + (calculationId != null ? calculationId.hashCode() : 0);
return result;
}
}

View File

@@ -1,57 +1,57 @@
package org.solovyev.android.calculator;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* User: Solovyev_S
* Date: 20.09.12
* Time: 16:54
*/
class CalculatorEventDataImpl implements CalculatorEventData {
@NotNull
private CalculatorEventDataId calculatorEventDataId;
private CalculatorEventDataImpl(@NotNull CalculatorEventDataId calculatorEventDataId) {
this.calculatorEventDataId = calculatorEventDataId;
}
@NotNull
public static CalculatorEventData newInstance(@NotNull CalculatorEventDataId calculatorEventDataId) {
return new CalculatorEventDataImpl(calculatorEventDataId);
}
@Override
public long getEventId() {
return calculatorEventDataId.getEventId();
}
@Override
@Nullable
public Long getSequenceId() {
return calculatorEventDataId.getSequenceId();
}
@Override
public boolean isAfter(@NotNull CalculatorEventDataId calculatorEventDataId) {
return this.calculatorEventDataId.isAfter(calculatorEventDataId);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof CalculatorEventDataImpl)) return false;
CalculatorEventDataImpl that = (CalculatorEventDataImpl) o;
if (!calculatorEventDataId.equals(that.calculatorEventDataId)) return false;
return true;
}
@Override
public int hashCode() {
return calculatorEventDataId.hashCode();
}
}
package org.solovyev.android.calculator;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* User: Solovyev_S
* Date: 20.09.12
* Time: 16:54
*/
class CalculatorEventDataImpl implements CalculatorEventData {
@NotNull
private CalculatorEventDataId calculatorEventDataId;
private CalculatorEventDataImpl(@NotNull CalculatorEventDataId calculatorEventDataId) {
this.calculatorEventDataId = calculatorEventDataId;
}
@NotNull
public static CalculatorEventData newInstance(@NotNull CalculatorEventDataId calculatorEventDataId) {
return new CalculatorEventDataImpl(calculatorEventDataId);
}
@Override
public long getEventId() {
return calculatorEventDataId.getEventId();
}
@Override
@Nullable
public Long getCalculationId() {
return calculatorEventDataId.getCalculationId();
}
@Override
public boolean isAfter(@NotNull CalculatorEventDataId calculatorEventDataId) {
return this.calculatorEventDataId.isAfter(calculatorEventDataId);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof CalculatorEventDataImpl)) return false;
CalculatorEventDataImpl that = (CalculatorEventDataImpl) o;
if (!calculatorEventDataId.equals(that.calculatorEventDataId)) return false;
return true;
}
@Override
public int hashCode() {
return calculatorEventDataId.hashCode();
}
}

View File

@@ -1,55 +1,43 @@
package org.solovyev.android.calculator;
import org.jetbrains.annotations.NotNull;
/**
* User: Solovyev_S
* Date: 20.09.12
* Time: 16:40
*/
public enum CalculatorEventType {
/*
**********************************************************************
*
* org.solovyev.android.calculator.CalculatorEvaluationEventData
*
**********************************************************************
*/
// @NotNull org.solovyev.android.calculator.CalculatorInput
calculation_started,
// @NotNull org.solovyev.android.calculator.CalculatorOutput
calculation_result,
calculation_cancelled,
calculation_finished,
// @NotNull org.solovyev.android.calculator.CalculatorFailure
calculation_failed,
/*
**********************************************************************
*
* CONVERSION
*
**********************************************************************
*/
conversion_started,
// @NotNull String conversion result
conversion_finished;
public boolean isOfType(@NotNull CalculatorEventType... types) {
for (CalculatorEventType type : types) {
if ( this == type ) {
return true;
}
}
return false;
}
}
package org.solovyev.android.calculator;
import org.jetbrains.annotations.NotNull;
/**
* User: Solovyev_S
* Date: 20.09.12
* Time: 16:40
*/
public enum CalculatorEventType {
/*
**********************************************************************
*
* org.solovyev.android.calculator.CalculatorEvaluationEventData
*
**********************************************************************
*/
// @NotNull org.solovyev.android.calculator.CalculatorInput
calculation_started,
// @NotNull org.solovyev.android.calculator.CalculatorOutput
calculation_result,
calculation_cancelled,
calculation_finished,
// @NotNull org.solovyev.android.calculator.CalculatorFailure
calculation_failed;
public boolean isOfType(@NotNull CalculatorEventType... types) {
for (CalculatorEventType type : types) {
if ( this == type ) {
return true;
}
}
return false;
}
}

View File

@@ -1,291 +1,209 @@
package org.solovyev.android.calculator;
import jscl.AbstractJsclArithmeticException;
import jscl.NumeralBase;
import jscl.NumeralBaseException;
import jscl.math.Generic;
import jscl.text.ParseInterruptedException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.solovyev.android.calculator.jscl.JsclOperation;
import org.solovyev.android.calculator.text.TextProcessor;
import org.solovyev.common.msg.MessageRegistry;
import org.solovyev.common.msg.MessageType;
import org.solovyev.common.text.StringUtils;
import org.solovyev.math.units.UnitConverter;
import org.solovyev.math.units.UnitImpl;
import org.solovyev.math.units.UnitType;
import java.util.List;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicLong;
/**
* User: Solovyev_S
* Date: 20.09.12
* Time: 16:42
*/
public class CalculatorImpl implements Calculator {
private static final long FIRST_ID = 0;
@NotNull
private final CalculatorEventContainer calculatorEventContainer = new ListCalculatorEventContainer();
@NotNull
private final AtomicLong counter = new AtomicLong(FIRST_ID);
@NotNull
private final Object lock = new Object();
@NotNull
private final TextProcessor<PreparedExpression, String> preprocessor = ToJsclTextProcessor.getInstance();
@NotNull
private final Executor threadPoolExecutor = Executors.newFixedThreadPool(10);
public CalculatorImpl() {
}
@NotNull
public static String doConversion(@NotNull UnitConverter<String> converter,
@Nullable String from,
@NotNull UnitType<String> fromUnitType,
@NotNull UnitType<String> toUnitType) throws ConversionException{
final String result;
if (StringUtils.isEmpty(from)) {
result = "";
} else {
String to = null;
try {
if (converter.isSupported(fromUnitType, toUnitType)) {
to = converter.convert(UnitImpl.newInstance(from, fromUnitType), toUnitType).getValue();
}
} catch (RuntimeException e) {
throw new ConversionException(e);
}
result = to;
}
return result;
}
@NotNull
private CalculatorEventDataId nextCalculatorEventDataId() {
long eventId = counter.incrementAndGet();
return CalculatorEventDataIdImpl.newInstance(eventId, eventId);
}
@NotNull
private CalculatorEventDataId nextEventDataId(@NotNull Long sequenceId) {
long eventId = counter.incrementAndGet();
return CalculatorEventDataIdImpl.newInstance(eventId, sequenceId);
}
/*
**********************************************************************
*
* CALCULATION
*
**********************************************************************
*/
@NotNull
@Override
public CalculatorEventDataId createFirstEventDataId() {
return CalculatorEventDataIdImpl.newInstance(FIRST_ID, FIRST_ID);
}
@Override
public void evaluate(@NotNull JsclOperation operation,
@NotNull String expression) {
evaluate(operation, expression, null);
}
@Override
@NotNull
public CalculatorEventDataId evaluate(@NotNull final JsclOperation operation,
@NotNull final String expression,
@Nullable final MessageRegistry mr) {
final CalculatorEventDataId eventDataId = nextCalculatorEventDataId();
threadPoolExecutor.execute(new Runnable() {
@Override
public void run() {
CalculatorImpl.this.evaluate(eventDataId.getSequenceId(), operation, expression, mr);
}
});
return eventDataId;
}
@NotNull
@Override
public CalculatorEventDataId convert(@NotNull final Generic generic,
@NotNull final NumeralBase to) {
final CalculatorEventDataId eventDataId = nextCalculatorEventDataId();
threadPoolExecutor.execute(new Runnable() {
@Override
public void run() {
final Long sequenceId = eventDataId.getSequenceId();
assert sequenceId != null;
fireCalculatorEvent(newConversionEventData(sequenceId), CalculatorEventType.conversion_started, null);
final NumeralBase from = CalculatorLocatorImpl.getInstance().getCalculatorEngine().getEngine().getNumeralBase();
if (from != to) {
String fromString = generic.toString();
if (!StringUtils.isEmpty(fromString)) {
try {
fromString = ToJsclTextProcessor.getInstance().process(fromString).getExpression();
} catch (CalculatorParseException e) {
// ok, problems while processing occurred
}
}
// todo serso: continue
//doConversion(AndroidNumeralBase.getConverter(), fromString, AndroidNumeralBase.valueOf(fromString), AndroidNumeralBase.valueOf(to));
} else {
fireCalculatorEvent(newConversionEventData(sequenceId), CalculatorEventType.conversion_finished, generic.toString());
}
}
});
return eventDataId;
}
@NotNull
private CalculatorEventData newConversionEventData(@NotNull Long sequenceId) {
return CalculatorEventDataImpl.newInstance(nextEventDataId(sequenceId));
}
private void evaluate(@NotNull Long sequenceId,
@NotNull JsclOperation operation,
@NotNull String expression,
@Nullable MessageRegistry mr) {
synchronized (lock) {
PreparedExpression preparedExpression = null;
fireCalculatorEvent(newCalculationEventData(operation, expression, sequenceId), CalculatorEventType.calculation_started, new CalculatorInputImpl(expression, operation));
try {
preparedExpression = preprocessor.process(expression);
final String jsclExpression = preparedExpression.toString();
try {
final Generic result = operation.evaluateGeneric(jsclExpression);
// NOTE: toString() method must be called here as ArithmeticOperationException may occur in it (just to avoid later check!)
result.toString();
final CalculatorOutputImpl data = new CalculatorOutputImpl(operation.getFromProcessor().process(result), operation, result);
fireCalculatorEvent(newCalculationEventData(operation, expression, sequenceId), CalculatorEventType.calculation_result, data);
} catch (AbstractJsclArithmeticException e) {
handleException(sequenceId, operation, expression, mr, new CalculatorEvalException(e, e, jsclExpression));
}
} catch (ArithmeticException e) {
handleException(sequenceId, operation, expression, mr, preparedExpression, new CalculatorParseException(expression, new CalculatorMessage(CalculatorMessages.msg_001, MessageType.error, e.getMessage())));
} catch (StackOverflowError e) {
handleException(sequenceId, operation, expression, mr, preparedExpression, new CalculatorParseException(expression, new CalculatorMessage(CalculatorMessages.msg_002, MessageType.error)));
} catch (jscl.text.ParseException e) {
handleException(sequenceId, operation, expression, mr, preparedExpression, new CalculatorParseException(e));
} catch (ParseInterruptedException e) {
// do nothing - we ourselves interrupt the calculations
fireCalculatorEvent(newCalculationEventData(operation, expression, sequenceId), CalculatorEventType.calculation_cancelled, null);
} catch (CalculatorParseException e) {
handleException(sequenceId, operation, expression, mr, preparedExpression, e);
} finally {
fireCalculatorEvent(newCalculationEventData(operation, expression, sequenceId), CalculatorEventType.calculation_finished, null);
}
}
}
@NotNull
private CalculatorEventData newCalculationEventData(@NotNull JsclOperation operation,
@NotNull String expression,
@NotNull Long calculationId) {
return new CalculatorEvaluationEventDataImpl(CalculatorEventDataImpl.newInstance(nextEventDataId(calculationId)), operation, expression);
}
private void handleException(@NotNull Long calculationId,
@NotNull JsclOperation operation,
@NotNull String expression,
@Nullable MessageRegistry mr,
@Nullable PreparedExpression preparedExpression,
@NotNull CalculatorParseException parseException) {
if (operation == JsclOperation.numeric
&& preparedExpression != null
&& preparedExpression.isExistsUndefinedVar()) {
evaluate(calculationId, JsclOperation.simplify, expression, mr);
}
fireCalculatorEvent(newCalculationEventData(operation, expression, calculationId), CalculatorEventType.calculation_failed, new CalculatorFailureImpl(parseException));
}
private void handleException(@NotNull Long calculationId,
@NotNull JsclOperation operation,
@NotNull String expression,
@Nullable MessageRegistry mr,
@NotNull CalculatorEvalException evalException) {
if (operation == JsclOperation.numeric && evalException.getCause() instanceof NumeralBaseException) {
evaluate(calculationId, JsclOperation.simplify, expression, mr);
}
fireCalculatorEvent(newCalculationEventData(operation, expression, calculationId), CalculatorEventType.calculation_failed, new CalculatorFailureImpl(evalException));
}
/*
**********************************************************************
*
* EVENTS
*
**********************************************************************
*/
@Override
public void addCalculatorEventListener(@NotNull CalculatorEventListener calculatorEventListener) {
calculatorEventContainer.addCalculatorEventListener(calculatorEventListener);
}
@Override
public void removeCalculatorEventListener(@NotNull CalculatorEventListener calculatorEventListener) {
calculatorEventContainer.removeCalculatorEventListener(calculatorEventListener);
}
@Override
public void fireCalculatorEvent(@NotNull CalculatorEventData calculatorEventData, @NotNull CalculatorEventType calculatorEventType, @Nullable Object data) {
calculatorEventContainer.fireCalculatorEvent(calculatorEventData, calculatorEventType, data);
}
@Override
public void fireCalculatorEvents(@NotNull List<CalculatorEvent> calculatorEvents) {
calculatorEventContainer.fireCalculatorEvents(calculatorEvents);
}
public static final class ConversionException extends Exception {
private ConversionException() {
}
private ConversionException(Throwable throwable) {
super(throwable);
}
}
}
package org.solovyev.android.calculator;
import jscl.AbstractJsclArithmeticException;
import jscl.NumeralBaseException;
import jscl.math.Generic;
import jscl.text.ParseInterruptedException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.solovyev.android.calculator.jscl.JsclOperation;
import org.solovyev.android.calculator.text.TextProcessor;
import org.solovyev.common.msg.MessageRegistry;
import org.solovyev.common.msg.MessageType;
import java.util.List;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicLong;
/**
* User: Solovyev_S
* Date: 20.09.12
* Time: 16:42
*/
public class CalculatorImpl implements Calculator {
private static final long FIRST_ID = 0;
@NotNull
private final CalculatorEventContainer calculatorEventContainer = new ListCalculatorEventContainer();
@NotNull
private final AtomicLong counter = new AtomicLong(FIRST_ID);
@NotNull
private final Object lock = new Object();
@NotNull
private final TextProcessor<PreparedExpression, String> preprocessor = ToJsclTextProcessor.getInstance();
@NotNull
private final Executor threadPoolExecutor = Executors.newFixedThreadPool(10);
public CalculatorImpl() {
}
@NotNull
private CalculatorEventDataId nextCalculatorEventDataId() {
long eventId = counter.incrementAndGet();
return CalculatorEventDataIdImpl.newInstance(eventId, eventId);
}
@NotNull
private CalculatorEventDataId nextEventDataId(@NotNull Long calculationId) {
long eventId = counter.incrementAndGet();
return CalculatorEventDataIdImpl.newInstance(eventId, calculationId);
}
/*
**********************************************************************
*
* CALCULATION
*
**********************************************************************
*/
@NotNull
@Override
public CalculatorEventDataId createFirstEventDataId() {
return CalculatorEventDataIdImpl.newInstance(FIRST_ID, FIRST_ID);
}
@Override
public void evaluate(@NotNull JsclOperation operation,
@NotNull String expression) {
evaluate(operation, expression, null);
}
@Override
@NotNull
public CalculatorEventDataId evaluate(@NotNull final JsclOperation operation,
@NotNull final String expression,
@Nullable final MessageRegistry mr) {
final CalculatorEventDataId eventDataId = nextCalculatorEventDataId();
threadPoolExecutor.execute(new Runnable() {
@Override
public void run() {
CalculatorImpl.this.evaluate(eventDataId.getCalculationId(), operation, expression, mr);
}
});
return eventDataId;
}
private void evaluate(@NotNull Long calculationId,
@NotNull JsclOperation operation,
@NotNull String expression,
@Nullable MessageRegistry mr) {
synchronized (lock) {
PreparedExpression preparedExpression = null;
fireCalculatorEvent(newCalculationEventData(operation, expression, calculationId), CalculatorEventType.calculation_started, new CalculatorInputImpl(expression, operation));
try {
preparedExpression = preprocessor.process(expression);
final String jsclExpression = preparedExpression.toString();
try {
final Generic result = operation.evaluateGeneric(jsclExpression);
// NOTE: toString() method must be called here as ArithmeticOperationException may occur in it (just to avoid later check!)
result.toString();
final CalculatorOutputImpl data = new CalculatorOutputImpl(operation.getFromProcessor().process(result), operation, result);
fireCalculatorEvent(newCalculationEventData(operation, expression, calculationId), CalculatorEventType.calculation_result, data);
} catch (AbstractJsclArithmeticException e) {
handleException(calculationId, operation, expression, mr, new CalculatorEvalException(e, e, jsclExpression));
}
} catch (ArithmeticException e) {
handleException(calculationId, operation, expression, mr, preparedExpression, new CalculatorParseException(expression, new CalculatorMessage(CalculatorMessages.msg_001, MessageType.error, e.getMessage())));
} catch (StackOverflowError e) {
handleException(calculationId, operation, expression, mr, preparedExpression, new CalculatorParseException(expression, new CalculatorMessage(CalculatorMessages.msg_002, MessageType.error)));
} catch (jscl.text.ParseException e) {
handleException(calculationId, operation, expression, mr, preparedExpression, new CalculatorParseException(e));
} catch (ParseInterruptedException e) {
// do nothing - we ourselves interrupt the calculations
fireCalculatorEvent(newCalculationEventData(operation, expression, calculationId), CalculatorEventType.calculation_cancelled, null);
} catch (CalculatorParseException e) {
handleException(calculationId, operation, expression, mr, preparedExpression, e);
} finally {
fireCalculatorEvent(newCalculationEventData(operation, expression, calculationId), CalculatorEventType.calculation_finished, null);
}
}
}
@NotNull
private CalculatorEventData newCalculationEventData(@NotNull JsclOperation operation,
@NotNull String expression,
@NotNull Long calculationId) {
return new CalculatorEvaluationEventDataImpl(CalculatorEventDataImpl.newInstance(nextEventDataId(calculationId)), operation, expression);
}
private void handleException(@NotNull Long calculationId,
@NotNull JsclOperation operation,
@NotNull String expression,
@Nullable MessageRegistry mr,
@Nullable PreparedExpression preparedExpression,
@NotNull CalculatorParseException parseException) {
if (operation == JsclOperation.numeric
&& preparedExpression != null
&& preparedExpression.isExistsUndefinedVar()) {
evaluate(calculationId, JsclOperation.simplify, expression, mr);
}
fireCalculatorEvent(newCalculationEventData(operation, expression, calculationId), CalculatorEventType.calculation_failed, new CalculatorFailureImpl(parseException));
}
private void handleException(@NotNull Long calculationId,
@NotNull JsclOperation operation,
@NotNull String expression,
@Nullable MessageRegistry mr,
@NotNull CalculatorEvalException evalException) {
if (operation == JsclOperation.numeric && evalException.getCause() instanceof NumeralBaseException) {
evaluate(calculationId, JsclOperation.simplify, expression, mr);
}
fireCalculatorEvent(newCalculationEventData(operation, expression, calculationId), CalculatorEventType.calculation_failed, new CalculatorFailureImpl(evalException));
}
/*
**********************************************************************
*
* EVENTS
*
**********************************************************************
*/
@Override
public void addCalculatorEventListener(@NotNull CalculatorEventListener calculatorEventListener) {
calculatorEventContainer.addCalculatorEventListener(calculatorEventListener);
}
@Override
public void removeCalculatorEventListener(@NotNull CalculatorEventListener calculatorEventListener) {
calculatorEventContainer.removeCalculatorEventListener(calculatorEventListener);
}
@Override
public void fireCalculatorEvent(@NotNull CalculatorEventData calculatorEventData, @NotNull CalculatorEventType calculatorEventType, @Nullable Object data) {
calculatorEventContainer.fireCalculatorEvent(calculatorEventData, calculatorEventType, data);
}
@Override
public void fireCalculatorEvents(@NotNull List<CalculatorEvent> calculatorEvents) {
calculatorEventContainer.fireCalculatorEvents(calculatorEvents);
}
}