diff --git a/calculatorpp-core/pom.xml b/calculatorpp-core/pom.xml
new file mode 100644
index 00000000..17ae2ad2
--- /dev/null
+++ b/calculatorpp-core/pom.xml
@@ -0,0 +1,46 @@
+
+
+ 4.0.0
+
+
+ org.solovyev.android
+ calculatorpp-parent
+ 1.3.1
+
+
+ org.solovyev.android
+ calculatorpp-core
+ 1.3.1
+ Calculator++ Application Core
+
+ jar
+
+
+
+
+ junit
+ junit
+ test
+
+
+
+ com.intellij
+ annotations
+
+
+
+ org.solovyev
+ jscl
+
+
+
+ org.simpleframework
+ simple-xml
+
+
+
+
+
+
\ No newline at end of file
diff --git a/calculatorpp/src/main/java/org/solovyev/android/calculator/model/AbstractNumberBuilder.java b/calculatorpp-core/src/main/java/org/solovyev/android/calculator/AbstractNumberBuilder.java
similarity index 95%
rename from calculatorpp/src/main/java/org/solovyev/android/calculator/model/AbstractNumberBuilder.java
rename to calculatorpp-core/src/main/java/org/solovyev/android/calculator/AbstractNumberBuilder.java
index d4dac24b..a95e6703 100644
--- a/calculatorpp/src/main/java/org/solovyev/android/calculator/model/AbstractNumberBuilder.java
+++ b/calculatorpp-core/src/main/java/org/solovyev/android/calculator/AbstractNumberBuilder.java
@@ -1,85 +1,85 @@
-/*
- * Copyright (c) 2009-2011. Created by serso aka se.solovyev.
- * For more information, please, contact se.solovyev@gmail.com
- * or visit http://se.solovyev.org
- */
-
-package org.solovyev.android.calculator.model;
-
-import jscl.MathEngine;
-import jscl.NumeralBase;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-import org.solovyev.android.calculator.math.MathType;
-import org.solovyev.common.text.StringUtils;
-
-/**
- * User: serso
- * Date: 12/15/11
- * Time: 9:01 PM
- */
-public abstract class AbstractNumberBuilder {
-
- @NotNull
- protected final MathEngine engine;
-
- @Nullable
- protected StringBuilder numberBuilder = null;
-
- @Nullable
- protected NumeralBase nb;
-
- protected AbstractNumberBuilder(@NotNull MathEngine engine) {
- this.engine = engine;
- this.nb = engine.getNumeralBase();
- }
-
- /**
- * Method determines if we can continue to process current number
- *
- * @param mathTypeResult current math type result
- * @return true if we can continue of processing of current number, if false - new number should be constructed
- */
- protected boolean canContinue(@NotNull MathType.Result mathTypeResult) {
- boolean result = mathTypeResult.getMathType().getGroupType() == MathType.MathGroupType.number &&
- !spaceBefore(mathTypeResult) &&
- numeralBaseCheck(mathTypeResult) &&
- numeralBaseInTheStart(mathTypeResult.getMathType()) || isSignAfterE(mathTypeResult);
- return result;
- }
-
- private boolean spaceBefore(@NotNull MathType.Result mathTypeResult) {
- return numberBuilder == null && StringUtils.isEmpty(mathTypeResult.getMatch().trim());
- }
-
- private boolean numeralBaseInTheStart(@NotNull MathType mathType) {
- return mathType != MathType.numeral_base || numberBuilder == null;
- }
-
- private boolean numeralBaseCheck(@NotNull MathType.Result mathType) {
- return mathType.getMathType() != MathType.digit || getNumeralBase().getAcceptableCharacters().contains(mathType.getMatch().charAt(0));
- }
-
- private boolean isSignAfterE(@NotNull MathType.Result mathTypeResult) {
- if (!isHexMode()) {
- if ("-".equals(mathTypeResult.getMatch()) || "+".equals(mathTypeResult.getMatch())) {
- final StringBuilder localNb = numberBuilder;
- if (localNb != null && localNb.length() > 0) {
- if (localNb.charAt(localNb.length() - 1) == MathType.POWER_10) {
- return true;
- }
- }
- }
- }
- return false;
- }
-
- public boolean isHexMode() {
- return nb == NumeralBase.hex || (nb == null && engine.getNumeralBase() == NumeralBase.hex);
- }
-
- @NotNull
- protected NumeralBase getNumeralBase() {
- return nb == null ? engine.getNumeralBase() : nb;
- }
-}
+/*
+ * Copyright (c) 2009-2011. Created by serso aka se.solovyev.
+ * For more information, please, contact se.solovyev@gmail.com
+ * or visit http://se.solovyev.org
+ */
+
+package org.solovyev.android.calculator;
+
+import jscl.MathEngine;
+import jscl.NumeralBase;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.solovyev.android.calculator.math.MathType;
+import org.solovyev.common.text.StringUtils;
+
+/**
+ * User: serso
+ * Date: 12/15/11
+ * Time: 9:01 PM
+ */
+public abstract class AbstractNumberBuilder {
+
+ @NotNull
+ protected final MathEngine engine;
+
+ @Nullable
+ protected StringBuilder numberBuilder = null;
+
+ @Nullable
+ protected NumeralBase nb;
+
+ protected AbstractNumberBuilder(@NotNull MathEngine engine) {
+ this.engine = engine;
+ this.nb = engine.getNumeralBase();
+ }
+
+ /**
+ * Method determines if we can continue to process current number
+ *
+ * @param mathTypeResult current math type result
+ * @return true if we can continue of processing of current number, if false - new number should be constructed
+ */
+ protected boolean canContinue(@NotNull MathType.Result mathTypeResult) {
+ boolean result = mathTypeResult.getMathType().getGroupType() == MathType.MathGroupType.number &&
+ !spaceBefore(mathTypeResult) &&
+ numeralBaseCheck(mathTypeResult) &&
+ numeralBaseInTheStart(mathTypeResult.getMathType()) || isSignAfterE(mathTypeResult);
+ return result;
+ }
+
+ private boolean spaceBefore(@NotNull MathType.Result mathTypeResult) {
+ return numberBuilder == null && StringUtils.isEmpty(mathTypeResult.getMatch().trim());
+ }
+
+ private boolean numeralBaseInTheStart(@NotNull MathType mathType) {
+ return mathType != MathType.numeral_base || numberBuilder == null;
+ }
+
+ private boolean numeralBaseCheck(@NotNull MathType.Result mathType) {
+ return mathType.getMathType() != MathType.digit || getNumeralBase().getAcceptableCharacters().contains(mathType.getMatch().charAt(0));
+ }
+
+ private boolean isSignAfterE(@NotNull MathType.Result mathTypeResult) {
+ if (!isHexMode()) {
+ if ("-".equals(mathTypeResult.getMatch()) || "+".equals(mathTypeResult.getMatch())) {
+ final StringBuilder localNb = numberBuilder;
+ if (localNb != null && localNb.length() > 0) {
+ if (localNb.charAt(localNb.length() - 1) == MathType.POWER_10) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ public boolean isHexMode() {
+ return nb == NumeralBase.hex || (nb == null && engine.getNumeralBase() == NumeralBase.hex);
+ }
+
+ @NotNull
+ protected NumeralBase getNumeralBase() {
+ return nb == null ? engine.getNumeralBase() : nb;
+ }
+}
diff --git a/calculatorpp-core/src/main/java/org/solovyev/android/calculator/Calculator.java b/calculatorpp-core/src/main/java/org/solovyev/android/calculator/Calculator.java
new file mode 100644
index 00000000..433c2163
--- /dev/null
+++ b/calculatorpp-core/src/main/java/org/solovyev/android/calculator/Calculator.java
@@ -0,0 +1,30 @@
+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);
+}
diff --git a/calculatorpp-core/src/main/java/org/solovyev/android/calculator/CalculatorDisplay.java b/calculatorpp-core/src/main/java/org/solovyev/android/calculator/CalculatorDisplay.java
new file mode 100644
index 00000000..a68d9747
--- /dev/null
+++ b/calculatorpp-core/src/main/java/org/solovyev/android/calculator/CalculatorDisplay.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2009-2011. Created by serso aka se.solovyev.
+ * For more information, please, contact se.solovyev@gmail.com
+ * or visit http://se.solovyev.org
+ */
+
+package org.solovyev.android.calculator;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * User: serso
+ * Date: 12/17/11
+ * Time: 9:45 PM
+ */
+public interface CalculatorDisplay extends CalculatorEventListener {
+
+ void setView(@Nullable CalculatorDisplayView view);
+
+ @NotNull
+ CalculatorDisplayViewState getViewState();
+
+ void setViewState(@NotNull CalculatorDisplayViewState viewState);
+
+ @NotNull
+ CalculatorEventData getLastEventData();
+}
diff --git a/calculatorpp-core/src/main/java/org/solovyev/android/calculator/CalculatorDisplayImpl.java b/calculatorpp-core/src/main/java/org/solovyev/android/calculator/CalculatorDisplayImpl.java
new file mode 100644
index 00000000..5e794275
--- /dev/null
+++ b/calculatorpp-core/src/main/java/org/solovyev/android/calculator/CalculatorDisplayImpl.java
@@ -0,0 +1,147 @@
+package org.solovyev.android.calculator;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import static org.solovyev.android.calculator.CalculatorEventType.*;
+
+/**
+ * User: serso
+ * Date: 9/20/12
+ * Time: 8:24 PM
+ */
+public class CalculatorDisplayImpl implements CalculatorDisplay {
+
+ @NotNull
+ private CalculatorEventData lastCalculatorEventData = CalculatorEventDataImpl.newInstance(CalculatorLocatorImpl.getInstance().getCalculator().createFirstEventDataId());
+
+ @Nullable
+ private CalculatorDisplayView view;
+
+ @NotNull
+ private final Object viewLock = new Object();
+
+ @NotNull
+ private CalculatorDisplayViewState lastViewState = CalculatorDisplayViewStateImpl.newDefaultInstance();
+
+ @Override
+ public void setView(@Nullable CalculatorDisplayView view) {
+ synchronized (viewLock) {
+ this.view = view;
+
+ if (view != null) {
+ this.view.setState(lastViewState);
+ }
+ }
+ }
+
+ @NotNull
+ @Override
+ public CalculatorDisplayViewState getViewState() {
+ return this.lastViewState;
+ }
+
+ @Override
+ public void setViewState(@NotNull CalculatorDisplayViewState viewState) {
+ synchronized (viewLock) {
+ this.lastViewState = viewState;
+ if (this.view != null) {
+ this.view.setState(viewState);
+ }
+ }
+ }
+
+/* @Override
+ @Nullable
+ public CharSequence getText() {
+ synchronized (viewLock) {
+ return view != null ? view.getText() : null;
+ }
+ }
+
+ @Override
+ public void setText(@Nullable CharSequence text) {
+ synchronized (viewLock) {
+ if (view != null) {
+ view.setText(text);
+ }
+ }
+ }
+
+ @Override
+ public int getSelection() {
+ synchronized (viewLock) {
+ return view != null ? view.getSelection() : 0;
+ }
+ }
+
+ @Override
+ public void setSelection(int selection) {
+ synchronized (viewLock) {
+ if (view != null) {
+ view.setSelection(selection);
+ }
+ }
+ }*/
+
+ @Override
+ @NotNull
+ public CalculatorEventData getLastEventData() {
+ return lastCalculatorEventData;
+ }
+
+ @Override
+ public void onCalculatorEvent(@NotNull CalculatorEventData calculatorEventData,
+ @NotNull CalculatorEventType calculatorEventType,
+ @Nullable Object data) {
+ if (calculatorEventType.isOfType(calculation_result, calculation_failed, calculation_cancelled)) {
+
+ if (calculatorEventData.isAfter(lastCalculatorEventData)) {
+ lastCalculatorEventData = calculatorEventData;
+ }
+
+ switch (calculatorEventType) {
+ case calculation_result:
+ processCalculationResult((CalculatorEvaluationEventData)calculatorEventData, (CalculatorOutput) data);
+ break;
+ case calculation_cancelled:
+ processCalculationCancelled((CalculatorEvaluationEventData)calculatorEventData);
+ break;
+ case calculation_failed:
+ processCalculationFailed((CalculatorEvaluationEventData)calculatorEventData, (CalculatorFailure) data);
+ break;
+ }
+
+ }
+ }
+
+ private void processCalculationFailed(@NotNull CalculatorEvaluationEventData calculatorEventData, @NotNull CalculatorFailure data) {
+
+ final CalculatorEvalException calculatorEvalException = data.getCalculationEvalException();
+
+ final String errorMessage;
+ if (calculatorEvalException != null) {
+ errorMessage = CalculatorMessages.getBundle().getString(CalculatorMessages.syntax_error);
+ } else {
+ final CalculatorParseException calculationParseException = data.getCalculationParseException();
+ if (calculationParseException != null) {
+ errorMessage = calculationParseException.getLocalizedMessage();
+ } else {
+ errorMessage = CalculatorMessages.getBundle().getString(CalculatorMessages.syntax_error);
+ }
+ }
+
+ this.setViewState(CalculatorDisplayViewStateImpl.newErrorState(calculatorEventData.getOperation(), errorMessage));
+ }
+
+ private void processCalculationCancelled(@NotNull CalculatorEvaluationEventData calculatorEventData) {
+ final String errorMessage = CalculatorMessages.getBundle().getString(CalculatorMessages.syntax_error);
+
+ this.setViewState(CalculatorDisplayViewStateImpl.newErrorState(calculatorEventData.getOperation(), errorMessage));
+ }
+
+ private void processCalculationResult(@NotNull CalculatorEvaluationEventData calculatorEventData, @NotNull CalculatorOutput data) {
+ final String stringResult = data.getStringResult();
+ this.setViewState(CalculatorDisplayViewStateImpl.newValidState(calculatorEventData.getOperation(), data.getResult(), stringResult, 0));
+ }
+}
diff --git a/calculatorpp-core/src/main/java/org/solovyev/android/calculator/CalculatorDisplayView.java b/calculatorpp-core/src/main/java/org/solovyev/android/calculator/CalculatorDisplayView.java
new file mode 100644
index 00000000..5ddc45df
--- /dev/null
+++ b/calculatorpp-core/src/main/java/org/solovyev/android/calculator/CalculatorDisplayView.java
@@ -0,0 +1,16 @@
+package org.solovyev.android.calculator;
+
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * User: serso
+ * Date: 9/20/12
+ * Time: 8:25 PM
+ */
+public interface CalculatorDisplayView {
+
+ void setState(@NotNull CalculatorDisplayViewState state);
+
+ @NotNull
+ CalculatorDisplayViewState getState();
+}
diff --git a/calculatorpp-core/src/main/java/org/solovyev/android/calculator/CalculatorDisplayViewState.java b/calculatorpp-core/src/main/java/org/solovyev/android/calculator/CalculatorDisplayViewState.java
new file mode 100644
index 00000000..2fdc83b3
--- /dev/null
+++ b/calculatorpp-core/src/main/java/org/solovyev/android/calculator/CalculatorDisplayViewState.java
@@ -0,0 +1,33 @@
+package org.solovyev.android.calculator;
+
+import jscl.math.Generic;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.solovyev.android.calculator.jscl.JsclOperation;
+
+/**
+ * User: serso
+ * Date: 9/20/12
+ * Time: 9:50 PM
+ */
+public interface CalculatorDisplayViewState {
+
+ @NotNull
+ String getText();
+
+ int getSelection();
+
+ @Nullable
+ Generic getResult();
+
+ boolean isValid();
+
+ @Nullable
+ String getErrorMessage();
+
+ @NotNull
+ JsclOperation getOperation();
+
+ @Nullable
+ String getStringResult();
+}
diff --git a/calculatorpp-core/src/main/java/org/solovyev/android/calculator/CalculatorDisplayViewStateImpl.java b/calculatorpp-core/src/main/java/org/solovyev/android/calculator/CalculatorDisplayViewStateImpl.java
new file mode 100644
index 00000000..ac13a9bc
--- /dev/null
+++ b/calculatorpp-core/src/main/java/org/solovyev/android/calculator/CalculatorDisplayViewStateImpl.java
@@ -0,0 +1,104 @@
+package org.solovyev.android.calculator;
+
+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.text.StringUtils;
+
+/**
+ * User: serso
+ * Date: 9/20/12
+ * Time: 9:50 PM
+ */
+public class CalculatorDisplayViewStateImpl implements CalculatorDisplayViewState {
+
+ @NotNull
+ private JsclOperation operation = JsclOperation.numeric;
+
+ @Nullable
+ private Generic result;
+
+ @Nullable
+ private String stringResult = "";
+
+ private boolean valid = true;
+
+ @Nullable
+ private String errorMessage;
+
+ private int selection = 0;
+
+ private CalculatorDisplayViewStateImpl() {
+ }
+
+ @NotNull
+ public static CalculatorDisplayViewState newDefaultInstance() {
+ return new CalculatorDisplayViewStateImpl();
+ }
+
+ @NotNull
+ public static CalculatorDisplayViewState newErrorState(@NotNull JsclOperation operation,
+ @NotNull String errorMessage) {
+ final CalculatorDisplayViewStateImpl calculatorDisplayState = new CalculatorDisplayViewStateImpl();
+ calculatorDisplayState.valid = false;
+ calculatorDisplayState.errorMessage = errorMessage;
+ calculatorDisplayState.operation = operation;
+ return calculatorDisplayState;
+ }
+
+ @NotNull
+ public static CalculatorDisplayViewState newValidState(@NotNull JsclOperation operation,
+ @Nullable Generic result,
+ @NotNull String stringResult,
+ int selection) {
+ final CalculatorDisplayViewStateImpl calculatorDisplayState = new CalculatorDisplayViewStateImpl();
+ calculatorDisplayState.valid = true;
+ calculatorDisplayState.result = result;
+ calculatorDisplayState.stringResult = stringResult;
+ calculatorDisplayState.operation = operation;
+ calculatorDisplayState.selection = selection;
+
+ return calculatorDisplayState;
+ }
+
+ @NotNull
+ @Override
+ public String getText() {
+ return StringUtils.getNotEmpty(isValid() ? stringResult : errorMessage, "");
+ }
+
+ @Override
+ public int getSelection() {
+ return selection;
+ }
+
+ @Nullable
+ @Override
+ public Generic getResult() {
+ return this.result;
+ }
+
+ @Override
+ public boolean isValid() {
+ return this.valid;
+ }
+
+ @Nullable
+ @Override
+ public String getErrorMessage() {
+ return this.errorMessage;
+ }
+
+ @Override
+ @Nullable
+ public String getStringResult() {
+ return stringResult;
+ }
+
+ @NotNull
+ @Override
+ public JsclOperation getOperation() {
+ return this.operation;
+ }
+}
diff --git a/calculatorpp/src/main/java/org/solovyev/android/calculator/CalculatorEngineControl.java b/calculatorpp-core/src/main/java/org/solovyev/android/calculator/CalculatorEngineControl.java
similarity index 94%
rename from calculatorpp/src/main/java/org/solovyev/android/calculator/CalculatorEngineControl.java
rename to calculatorpp-core/src/main/java/org/solovyev/android/calculator/CalculatorEngineControl.java
index 6de56347..43e2614d 100644
--- a/calculatorpp/src/main/java/org/solovyev/android/calculator/CalculatorEngineControl.java
+++ b/calculatorpp-core/src/main/java/org/solovyev/android/calculator/CalculatorEngineControl.java
@@ -1,19 +1,19 @@
-/*
- * Copyright (c) 2009-2011. Created by serso aka se.solovyev.
- * For more information, please, contact se.solovyev@gmail.com
- * or visit http://se.solovyev.org
- */
-
-package org.solovyev.android.calculator;
-
-/**
- * User: serso
- * Date: 10/24/11
- * Time: 9:55 PM
- */
-public interface CalculatorEngineControl {
-
- void evaluate();
-
- void simplify();
-}
+/*
+ * Copyright (c) 2009-2011. Created by serso aka se.solovyev.
+ * For more information, please, contact se.solovyev@gmail.com
+ * or visit http://se.solovyev.org
+ */
+
+package org.solovyev.android.calculator;
+
+/**
+ * User: serso
+ * Date: 10/24/11
+ * Time: 9:55 PM
+ */
+public interface CalculatorEngineControl {
+
+ void evaluate();
+
+ void simplify();
+}
diff --git a/calculatorpp/src/main/java/org/solovyev/android/calculator/model/CalculatorEvalException.java b/calculatorpp-core/src/main/java/org/solovyev/android/calculator/CalculatorEvalException.java
similarity index 92%
rename from calculatorpp/src/main/java/org/solovyev/android/calculator/model/CalculatorEvalException.java
rename to calculatorpp-core/src/main/java/org/solovyev/android/calculator/CalculatorEvalException.java
index 5c4e4416..8aba31d2 100644
--- a/calculatorpp/src/main/java/org/solovyev/android/calculator/model/CalculatorEvalException.java
+++ b/calculatorpp-core/src/main/java/org/solovyev/android/calculator/CalculatorEvalException.java
@@ -1,73 +1,72 @@
-/*
- * Copyright (c) 2009-2011. Created by serso aka se.solovyev.
- * For more information, please, contact se.solovyev@gmail.com
- * or visit http://se.solovyev.org
- */
-
-package org.solovyev.android.calculator.model;
-
-import jscl.AbstractJsclArithmeticException;
-import org.jetbrains.annotations.NotNull;
-import org.solovyev.common.exceptions.SersoException;
-import org.solovyev.common.msg.Message;
-import org.solovyev.common.msg.MessageType;
-
-import java.util.List;
-import java.util.Locale;
-
-/**
- * User: serso
- * Date: 12/8/11
- * Time: 1:27 AM
- */
-public class CalculatorEvalException extends SersoException implements Message {
-
- @NotNull
- private final Message message;
-
- @NotNull
- private final String expression;
-
- public CalculatorEvalException(@NotNull Message message, @NotNull Throwable cause, String expression) {
- super(cause);
- this.message = message;
- this.expression = expression;
- }
-
-
- @NotNull
- public String getExpression() {
- return expression;
- }
-
- @NotNull
- @Override
- public String getMessageCode() {
- return this.message.getMessageCode();
- }
-
- @NotNull
- @Override
- public List