Add the Calculator App (#145)
author유리나/Common Platform Lab(SR)/Staff Engineer/삼성전자 <rina6350.you@samsung.com>
Thu, 6 Feb 2020 08:06:56 +0000 (17:06 +0900)
committerGitHub Enterprise <noreply-CODE@samsung.com>
Thu, 6 Feb 2020 08:06:56 +0000 (17:06 +0900)
* Add the Calculator App

* Modify sln file

46 files changed:
Test/Calculator/Calculator.sln [new file with mode: 0644]
Test/Calculator/Calculator/Calculator.cs [new file with mode: 0644]
Test/Calculator/Calculator/Calculator.csproj [new file with mode: 0644]
Test/Calculator/Calculator/CalculatorApp.cs [new file with mode: 0644]
Test/Calculator/Calculator/Controls/ImageButton.xaml [new file with mode: 0644]
Test/Calculator/Calculator/Controls/ImageButton.xaml.cs [new file with mode: 0644]
Test/Calculator/Calculator/Impl/CalculatorImpl.cs [new file with mode: 0644]
Test/Calculator/Calculator/Impl/Formatter.cs [new file with mode: 0644]
Test/Calculator/Calculator/Impl/InputParser.cs [new file with mode: 0644]
Test/Calculator/Calculator/Models/AddingElementResult.cs [new file with mode: 0644]
Test/Calculator/Calculator/Models/CalculationResult.cs [new file with mode: 0644]
Test/Calculator/Calculator/Models/IBinaryOperator.cs [new file with mode: 0644]
Test/Calculator/Calculator/Models/INullary.cs [new file with mode: 0644]
Test/Calculator/Calculator/Models/IOperator.cs [new file with mode: 0644]
Test/Calculator/Calculator/Models/IUnaryOperator.cs [new file with mode: 0644]
Test/Calculator/Calculator/Models/InputElement.cs [new file with mode: 0644]
Test/Calculator/Calculator/Models/Literal.cs [new file with mode: 0644]
Test/Calculator/Calculator/Models/Operators.cs [new file with mode: 0644]
Test/Calculator/Calculator/Renderers/ImageButtonRenderer.cs [new file with mode: 0644]
Test/Calculator/Calculator/ViewModels/MainPageViewModel.cs [new file with mode: 0644]
Test/Calculator/Calculator/Views/CalculatorMainPage.xaml [new file with mode: 0644]
Test/Calculator/Calculator/Views/CalculatorMainPage.xaml.cs [new file with mode: 0644]
Test/Calculator/Calculator/res/btn_delete.png [new file with mode: 0644]
Test/Calculator/Calculator/res/calculator_button_l_01.png [new file with mode: 0644]
Test/Calculator/Calculator/res/calculator_button_l_02.png [new file with mode: 0644]
Test/Calculator/Calculator/res/calculator_button_l_03.png [new file with mode: 0644]
Test/Calculator/Calculator/res/calculator_button_l_04.png [new file with mode: 0644]
Test/Calculator/Calculator/res/calculator_button_l_05.png [new file with mode: 0644]
Test/Calculator/Calculator/res/calculator_button_l_06.png [new file with mode: 0644]
Test/Calculator/Calculator/res/calculator_button_l_07.png [new file with mode: 0644]
Test/Calculator/Calculator/res/calculator_button_l_08.png [new file with mode: 0644]
Test/Calculator/Calculator/res/calculator_button_p_number_0.png [new file with mode: 0644]
Test/Calculator/Calculator/res/calculator_button_p_number_1.png [new file with mode: 0644]
Test/Calculator/Calculator/res/calculator_button_p_number_10.png [new file with mode: 0644]
Test/Calculator/Calculator/res/calculator_button_p_number_11.png [new file with mode: 0644]
Test/Calculator/Calculator/res/calculator_button_p_number_2.png [new file with mode: 0644]
Test/Calculator/Calculator/res/calculator_button_p_number_3.png [new file with mode: 0644]
Test/Calculator/Calculator/res/calculator_button_p_number_4.png [new file with mode: 0644]
Test/Calculator/Calculator/res/calculator_button_p_number_5.png [new file with mode: 0644]
Test/Calculator/Calculator/res/calculator_button_p_number_6.png [new file with mode: 0644]
Test/Calculator/Calculator/res/calculator_button_p_number_7.png [new file with mode: 0644]
Test/Calculator/Calculator/res/calculator_button_p_number_8.png [new file with mode: 0644]
Test/Calculator/Calculator/res/calculator_button_p_number_9.png [new file with mode: 0644]
Test/Calculator/Calculator/shared/res/Calculator.png [new file with mode: 0644]
Test/Calculator/Calculator/tizen-manifest.xml [new file with mode: 0644]
XSF.sln

diff --git a/Test/Calculator/Calculator.sln b/Test/Calculator/Calculator.sln
new file mode 100644 (file)
index 0000000..bc9279b
--- /dev/null
@@ -0,0 +1,25 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 15
+VisualStudioVersion = 15.0.27703.2042
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Calculator", "Calculator\Calculator.csproj", "{BEFE0E16-9184-4AEE-9793-AF374BFDA5E7}"
+EndProject
+Global
+       GlobalSection(SolutionConfigurationPlatforms) = preSolution
+               Debug|Any CPU = Debug|Any CPU
+               Release|Any CPU = Release|Any CPU
+       EndGlobalSection
+       GlobalSection(ProjectConfigurationPlatforms) = postSolution
+               {BEFE0E16-9184-4AEE-9793-AF374BFDA5E7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+               {BEFE0E16-9184-4AEE-9793-AF374BFDA5E7}.Debug|Any CPU.Build.0 = Debug|Any CPU
+               {BEFE0E16-9184-4AEE-9793-AF374BFDA5E7}.Release|Any CPU.ActiveCfg = Release|Any CPU
+               {BEFE0E16-9184-4AEE-9793-AF374BFDA5E7}.Release|Any CPU.Build.0 = Release|Any CPU
+       EndGlobalSection
+       GlobalSection(SolutionProperties) = preSolution
+               HideSolutionNode = FALSE
+       EndGlobalSection
+       GlobalSection(ExtensibilityGlobals) = postSolution
+               SolutionGuid = {332903D4-E06B-475C-ACDB-C5F7AF481E20}
+       EndGlobalSection
+EndGlobal
diff --git a/Test/Calculator/Calculator/Calculator.cs b/Test/Calculator/Calculator/Calculator.cs
new file mode 100644 (file)
index 0000000..48f9507
--- /dev/null
@@ -0,0 +1,76 @@
+
+//Copyright 2018 Samsung Electronics Co., Ltd
+//
+//Licensed under the Apache License, Version 2.0 (the "License");
+//you may not use this file except in compliance with the License.
+//You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+//Unless required by applicable law or agreed to in writing, software
+//distributed under the License is distributed on an "AS IS" BASIS,
+//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//See the License for the specific language governing permissions and
+//limitations under the License.
+using System;
+using System.Collections.Generic;
+using Tizen.Wearable.CircularUI.Forms;
+using Tizen.Wearable.CircularUI.Forms.Renderer;
+using Xamarin.Forms;
+using Xamarin.Forms.Platform.Tizen;
+
+namespace Calculator
+{
+       /// <summary>
+       /// Calculator application entry point.
+       /// </summary>
+    class Program : global::Xamarin.Forms.Platform.Tizen.ApplicationLifecycle
+    {
+        /// <summary>
+        /// An AppResourcePath which is used to get full path of the app resources.
+        /// </summary>
+        public static string AppResourcePath
+        {
+            get;
+            private set;
+        }
+
+        /// <summary>
+        /// This function is called when the application is created
+        /// </summary>
+        protected override void OnCreate()
+        {
+            base.OnCreate();
+
+            AppResourcePath = FormsApplication.DirectoryInfo.Resource;
+            FormsApplication.LoadApplication(new CalculatorApp());
+        }
+
+        /// <summary>
+        /// The entry point of the application
+        /// </summary>
+        /// <param name="args">Arguments</param>
+        static void Main(string[] args)
+        {
+            var app = new Program();
+            // define your custom handlers
+            var customRenderers = new Dictionary<Type, Func<IRegisterable>>()
+            {
+                { typeof(CirclePage), ()=> new CirclePageRenderer() },
+                { typeof(global:: Tizen.Wearable.CircularUI.Forms.CircleListView), () => new CircleListViewRenderer() },
+                { typeof(Calculator.Controls.ImageButton), () => new  Calculator.Renderers.ImageButtonRenderer() }
+            };
+
+            var option = new InitializationOptions(app);
+            option.UseStaticRegistrar(StaticRegistrarStrategy.StaticRegistrarOnly, customRenderers, true);
+            option.UseMessagingCenter = false;
+            option.UseStyle = false;
+            option.UseVisual = false;
+            option.UseShell = false;
+            Forms.Init(option);
+
+            global::Tizen.Wearable.CircularUI.Forms.Renderer.FormsCircularUI.Init();
+            app.FormsApplication.Run(args);
+               }
+       }
+}
diff --git a/Test/Calculator/Calculator/Calculator.csproj b/Test/Calculator/Calculator/Calculator.csproj
new file mode 100644 (file)
index 0000000..06c865e
--- /dev/null
@@ -0,0 +1,43 @@
+<Project Sdk="Tizen.NET.Sdk/1.0.8">
+
+  <PropertyGroup>
+    <OutputType>Exe</OutputType>
+    <TargetFramework>tizen40</TargetFramework>
+  </PropertyGroup>
+
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugType>portable</DebugType>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>None</DebugType>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <ProjectReference Include="..\..\..\Tizen.CircularUI\Tizen.Wearable.CircularUI.Forms.Renderer\XSF.CircularUI.Forms.Renderer.csproj" />
+    <ProjectReference Include="..\..\..\Tizen.CircularUI\Tizen.Wearable.CircularUI.Forms\XSF.CircularUI.Forms.csproj" />
+    <ProjectReference Include="..\..\..\Xamarin.Forms\Xamarin.Forms.Core\XSF.Core.csproj" />
+    <ProjectReference Include="..\..\..\Xamarin.Forms\Xamarin.Forms.Platform.Tizen\XSF.Platform.Tizen.csproj" />
+    <ProjectReference Include="..\..\..\Xamarin.Forms\Xamarin.Forms.Platform\XSF.Platform.csproj" />
+    <ProjectReference Include="..\..\..\Xamarin.Forms\Xamarin.Forms.Xaml\XSF.Xaml.csproj" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <Compile Update="Views\CalculatorMainPage.xaml.cs">
+      <DependentUpon>CalculatorMainPage.xaml</DependentUpon>
+    </Compile>
+  </ItemGroup>
+
+  <ItemGroup>
+    <EmbeddedResource Update="Controls\ImageButton.xaml">
+      <Generator>MSBuild:UpdateDesignTimeXaml</Generator>
+    </EmbeddedResource>
+    <EmbeddedResource Update="Views\CalculatorMainPage.xaml">
+      <Generator>MSBuild:UpdateDesignTimeXaml</Generator>
+    </EmbeddedResource>
+  </ItemGroup>
+
+  <ItemGroup>
+    <Folder Include="Impl\" />
+  </ItemGroup>
+
+</Project>
diff --git a/Test/Calculator/Calculator/CalculatorApp.cs b/Test/Calculator/Calculator/CalculatorApp.cs
new file mode 100644 (file)
index 0000000..c59b5da
--- /dev/null
@@ -0,0 +1,75 @@
+
+//Copyright 2018 Samsung Electronics Co., Ltd
+//
+//Licensed under the Apache License, Version 2.0 (the "License");
+//you may not use this file except in compliance with the License.
+//You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+//Unless required by applicable law or agreed to in writing, software
+//distributed under the License is distributed on an "AS IS" BASIS,
+//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//See the License for the specific language governing permissions and
+//limitations under the License.
+
+using System;
+
+using Xamarin.Forms;
+using Calculator.Views;
+using Calculator.Impl;
+
+namespace Calculator
+{
+    public class CalculatorApp : Application
+    {
+        /// <summary>
+        /// InputParser class instance.
+        /// The InputParser checks user input and validates calculated expression.
+        /// </summary>
+        /// <seealso cref="global::Calculator.Impl.InputParser">
+        private static readonly Lazy<InputParser> inputParser = new Lazy<InputParser>(() => new InputParser());
+
+        static public InputParser InputParserInstance
+        {
+            get
+            {
+                return inputParser.Value;
+            }
+        }
+
+        /// <summary>
+        /// A Formatter class instance.
+        /// The Formatter class provides formatting for displaying text from validated expression.
+        /// </summary>
+        /// <seealso cref="global::Calculator.Impl.Formatter">
+        private static readonly Lazy<Formatter> formatter = new Lazy<Formatter>(() => new Formatter());
+        static public Formatter FormatterInstance
+        {
+            get
+            {
+                return formatter.Value;
+            }
+        }
+
+        /// <summary>
+        /// A CalculatorImpl class instance.
+        /// The CalculatorImpl class calculates validated expression and provides result value.
+        /// </summary>
+        /// <seealso cref="global::Calculator.Impl.CalculatorImpl">
+        private static readonly Lazy<CalculatorImpl> calculator = new Lazy<CalculatorImpl>(() => new CalculatorImpl());
+        static public CalculatorImpl CalculatorInstance
+        {
+            get
+            {
+                return calculator.Value;
+            }
+        }
+
+        public CalculatorApp()
+        {
+            // The root page of the application
+            MainPage = new CalculatorMainPage();
+        }
+    }
+}
diff --git a/Test/Calculator/Calculator/Controls/ImageButton.xaml b/Test/Calculator/Calculator/Controls/ImageButton.xaml
new file mode 100644 (file)
index 0000000..ed50faf
--- /dev/null
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Image xmlns="http://xamarin.com/schemas/2014/forms" 
+             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
+             x:Class="Calculator.Controls.ImageButton">
+</Image>
\ No newline at end of file
diff --git a/Test/Calculator/Calculator/Controls/ImageButton.xaml.cs b/Test/Calculator/Calculator/Controls/ImageButton.xaml.cs
new file mode 100644 (file)
index 0000000..ef370f4
--- /dev/null
@@ -0,0 +1,56 @@
+
+//Copyright 2018 Samsung Electronics Co., Ltd
+//
+//Licensed under the Apache License, Version 2.0 (the "License");
+//you may not use this file except in compliance with the License.
+//You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+//Unless required by applicable law or agreed to in writing, software
+//distributed under the License is distributed on an "AS IS" BASIS,
+//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//See the License for the specific language governing permissions and
+//limitations under the License.
+
+using System;
+
+using System.Windows.Input;
+using Xamarin.Forms;
+
+namespace Calculator.Controls
+{
+    /// <summary>
+    /// A command button which is implemented with a custom renderer based on a native image. 
+    /// </summary>
+    public partial class ImageButton : Image
+    {
+        public static readonly BindableProperty CommandProperty =
+           BindableProperty.Create(nameof(Command), typeof(ICommand), typeof(ImageButton), null, BindingMode.TwoWay);
+
+        /// <summary>
+        /// A command that will be executed if the button is touched. 
+        /// </summary>
+        public ICommand Command
+        {
+            get { return (ICommand)GetValue(CommandProperty); }
+            set { SetValue(CommandProperty, value); }
+        }
+
+        /// <summary>
+        /// A command parameter that will be passed when the Command is executed. 
+        /// </summary>
+        /// <see cref="ImageButton.Command"/>
+        public String CommandParameter
+        {
+            get;
+            set;
+        }
+
+        public ImageButton()
+        {
+            CommandParameter = "";
+            InitializeComponent();
+        }
+    }
+}
diff --git a/Test/Calculator/Calculator/Impl/CalculatorImpl.cs b/Test/Calculator/Calculator/Impl/CalculatorImpl.cs
new file mode 100644 (file)
index 0000000..a0be517
--- /dev/null
@@ -0,0 +1,345 @@
+
+//Copyright 2018 Samsung Electronics Co., Ltd
+//
+//Licensed under the Apache License, Version 2.0 (the "License");
+//you may not use this file except in compliance with the License.
+//You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+//Unless required by applicable law or agreed to in writing, software
+//distributed under the License is distributed on an "AS IS" BASIS,
+//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//See the License for the specific language governing permissions and
+//limitations under the License.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+using Calculator.Models;
+using Tizen;
+
+namespace Calculator.Impl
+{
+    /// <summary>
+    /// A Calculator Implementation class that calculates result for given expression.
+    /// </summary>
+    /// <remarks>
+    /// The CalculatorImpl requires InputElement class based infix notation expression list.
+    /// </remarks>
+    public sealed class CalculatorImpl
+    {
+        /// <summary>
+        /// An enum value representing Calculator working status.
+        /// </summary>
+        public enum WorkingStatus
+        {
+            WORKING,
+            ERROR,
+        }
+
+        /// <summary>
+        /// Calculator working status.
+        /// Status is set to ERROR if last calculation failed.
+        /// </summary>
+        public WorkingStatus Status
+        {
+            get;
+            private set;
+        }
+
+        /// <summary>
+        /// All operators that can be used in calculation.
+        /// </summary>
+        private IReadOnlyDictionary<String, IOperator> OperatorDescriptions;
+
+        /// <summary>
+        /// Last used operand.
+        /// This operand is used in repeated calculation.
+        /// </summary>
+        private Literal LastOperand;
+
+        /// <summary>
+        /// Last used operator.
+        /// This operator is used in repeated calculation.
+        /// </summary>
+        private IOperator LastOperator;
+
+        /// <summary>
+        /// A flag value shows if the last pressed button is equal key.
+        /// </summary>
+        private bool IsEqualUsed;
+
+        /// <summary>
+        /// Last calculated result value.
+        /// </summary>
+        public double Result
+        {
+            get;
+            private set;
+        }
+
+        /// <summary>
+        /// The CalculatorImpl's constructor which initializes calculator
+        /// and sets default calculation operators.
+        /// </summary>
+        public CalculatorImpl()
+        {
+            Status = WorkingStatus.WORKING;
+            OperatorDescriptions = Operators.OperatorMap;
+        }
+
+        /// <summary>
+        /// The method which calculates given expression.
+        /// </summary>
+        /// <param name="separatedInfixNotation"> An expression list in infix notation </param>
+        /// <returns> Calculation result status </returns>
+        public CalculationResult SetExpression(IEnumerable<InputElement> separatedInfixNotation)
+        {
+            IsEqualUsed = false;
+            return Calculate(separatedInfixNotation);
+        }
+
+        /// <summary>
+        /// This method is handling equal key press.
+        /// If the equal key is pressed once, just provides a result,
+        /// but if the equal key is pressed repeatedly, calculator calculates with lastly used operand and operator
+        /// </summary>
+        /// <param name="separated"> Expression list in infix notation </param>
+        /// <returns> Calculation result status </returns>
+        public CalculationResult Equal(IEnumerable<InputElement> separated)
+        {
+            CalculationResult res;
+
+            if (IsEqualUsed == false)
+            {
+                res = Calculate(separated);
+                if (res is CalculationSuccessful)
+                {
+                    IsEqualUsed = true;
+                    return res;
+                }
+
+                LastOperand = null;
+                LastOperator = null;
+                return res;
+            }
+
+            if (separated.Count() < 1 ||
+                LastOperator == null ||
+                LastOperand == null)
+            {
+                return new CalculationFailed();
+            }
+
+            List<InputElement> tempList = new List<InputElement>(separated);
+            tempList.Add(LastOperator as InputElement);
+            tempList.Add(LastOperand);
+
+            return Calculate(tempList);
+        }
+
+        /// <summary>
+        /// The method calculates result for given expression.
+        /// </summary>
+        /// <param name="separated"> InputElement list in infix notation</param>
+        /// <returns> Calculation result status </returns>
+        private CalculationResult Calculate(IEnumerable<InputElement> separated)
+        {
+            Status = WorkingStatus.ERROR;
+
+            if (!separated.Any())
+            {
+                Result = 0;
+                Status = WorkingStatus.WORKING;
+                return new CalculationSuccessful();
+            }
+
+            if (separated.Last() is Point)
+            {
+                return new CalculationFailed();
+            }
+
+            IList<InputElement> temp = new List<InputElement>(separated);
+            // This section adds missing closing brackets
+            {
+                int depth = 0;
+                foreach (var item in temp)
+                {
+                    if (item.CompareTo("(") == 0)
+                    {
+                        depth += 1;
+                    }
+                    else if (item.CompareTo(")") == 0)
+                    {
+                        depth -= 1;
+                    }
+                }
+
+                for (int i = 0; i < depth; i++)
+                {
+                    temp.Add(new CloseBracket());
+                }
+            }
+
+
+            Queue<InputElement> postfix;
+            if (!ChangeToPostfix(temp, out postfix))
+            {
+                return new CantCalculateInvalidFormat();
+            }
+            
+            Stack<string> operand = new Stack<string>();
+            try
+            {
+                foreach(var token in postfix)
+                {
+                    if (token is Literal)
+                    {
+                        operand.Push(token.GetElement);
+                    }
+                    else
+                    {
+                        IOperator op = OperatorDescriptions[token];
+                        string op1;
+                        string op2;
+                        double _op1 = 0;
+                        double _op2 = 0;
+
+                        // This section retrieves arguments needed by operator
+                        if (op is IBinaryOperator)
+                        {
+                            op2 = operand.Pop();
+                            op1 = operand.Pop();
+
+                            if (!GetDoubleValue(op2, out _op2) || !GetDoubleValue(op1, out _op1))
+                            {
+                                return new CantCalculateInvalidFormat();
+                            }
+
+                            if ((op is Models.Point) == false)
+                            {
+                                LastOperand = new Literal(op2);
+                                LastOperator = op;
+                            }
+                        }
+                        else if (op is IUnaryOperator)
+                        {
+                            op1 = operand.Pop();
+
+                            if (!GetDoubleValue(op1, out _op1))
+                            {
+                                return new CantCalculateInvalidFormat();
+                            }
+                        }
+
+                        op.GetResult(_op1, _op2, out double result);
+
+                        if (Double.IsInfinity(result) || Double.IsNaN(result))
+                        {
+                            return new CantCalculateTooBigNumber();
+                        }
+
+                        operand.Push(result.ToString());
+                    }
+                }
+            }
+            catch (DivideByZeroException)
+            {
+                return new CantDivideByZero();
+            }
+            catch (InvalidOperationException)
+            {
+                return new CantCalculateInvalidFormat();
+            }
+            catch (Exception e)
+            {
+                System.Diagnostics.Debug.WriteLine(e.Message);
+                return new CalculationFailed();
+            }
+
+            double ret;
+            if (operand.Count == 0 || Double.TryParse(operand.Peek(), out ret) == false)
+            {
+                return new CalculationFailed();
+            }
+
+            Result = ret;
+            Status = WorkingStatus.WORKING;
+            return new CalculationSuccessful();
+        }
+
+        /// <summary>
+        /// The method changes expression format from infix to postfix.
+        /// </summary>
+        /// <param name="separated"> InputElement list in infix notation </param>
+        /// <param name="ret"> InputElement queue in postfix notation </param>
+        /// <returns> Result status of expression's reorder </returns>
+        private bool ChangeToPostfix(IEnumerable<InputElement> separated, out Queue<InputElement> ret)
+        {
+            Queue<InputElement> postfix = new Queue<InputElement>();
+            Stack<InputElement> operators = new Stack<InputElement>();
+
+            try
+            {
+                foreach (InputElement token in separated)
+                {
+                    if (token is Literal)
+                    {
+                        postfix.Enqueue(token);
+                    }
+                    else if (token.CompareTo("(") == 0)
+                    {
+                        operators.Push(token);
+                    }
+                    else if (token.CompareTo(")") == 0)
+                    {
+                        InputElement topToken = operators.Pop();
+                        while (topToken.CompareTo("(") != 0)
+                        {
+                            postfix.Enqueue(topToken);
+                            topToken = operators.Pop();
+                        }
+                    }
+                    else
+                    {
+                        while ((operators.Count > 0) &&
+                            (OperatorDescriptions[operators.Peek()].Priority >= OperatorDescriptions[token].Priority))
+                        {
+                            postfix.Enqueue(operators.Pop());
+                        }
+
+                        operators.Push(token);
+                    }
+                }
+
+                while (operators.Count > 0)
+                {
+                    postfix.Enqueue(operators.Pop());
+                }
+            }
+            catch (Exception)
+            {
+                postfix.Clear();
+                ret = postfix;
+                return false;
+            }
+
+            ret = postfix;
+            return true;
+        }
+
+        private bool GetDoubleValue(string literal, out double value)
+        {
+            string strValue = literal;
+
+            if (literal.StartsWith("0") && literal.Contains(".") == false)
+            {
+                strValue = ("0." + literal);
+            }
+
+            return Double.TryParse(strValue, out value);
+        }
+    }
+}
diff --git a/Test/Calculator/Calculator/Impl/Formatter.cs b/Test/Calculator/Calculator/Impl/Formatter.cs
new file mode 100644 (file)
index 0000000..81a5386
--- /dev/null
@@ -0,0 +1,163 @@
+
+//Copyright 2018 Samsung Electronics Co., Ltd
+//
+//Licensed under the Apache License, Version 2.0 (the "License");
+//you may not use this file except in compliance with the License.
+//You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+//Unless required by applicable law or agreed to in writing, software
+//distributed under the License is distributed on an "AS IS" BASIS,
+//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//See the License for the specific language governing permissions and
+//limitations under the License.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Xamarin.Forms;
+
+using Calculator.Models;
+
+namespace Calculator.Impl
+{
+    /// <summary>
+    /// A Formatter class that provides formatted displayable text.</summary>
+    public sealed class Formatter
+    {
+        private const double displayMax = 9999999999D;
+        private static readonly Color literalColor = Color.White;
+        private static readonly Color operatorColor = Color.Pink;
+
+        /// <summary>
+        /// The method provides formatted text for a number. 
+        /// </summary>
+        /// <param name="value"> A number value </param>
+        /// <returns> A formatted number text </returns>
+        private String GetNumberText(Double value)
+        {
+            if (Math.Abs(value) > displayMax)
+            {
+                return String.Format("{0:0.########E+000}", value);
+            }
+
+            return String.Format("{0:#,##0.##########}", value);
+        }
+
+        /// <summary>
+        /// The method provides formatted expression text for given expression. 
+        /// </summary>
+        /// <param name="separatedExpression"> An expression consist of InputElement list </param>
+        /// <returns> A formatted expression text </returns>
+        public FormattedString GetFormattedExpressionText(IEnumerable<InputElement> separatedExpression)
+        {
+            var result = new FormattedString();
+            int oneLineLengthCount = 0;
+
+            for (int i = 0; i < separatedExpression.Count(); i++)
+            {
+                InputElement s = separatedExpression.ElementAt(i);
+                string element = s.GetDisplayElement;
+
+                if (s is Literal)
+                {
+                    double value;
+                    string displayNumberText = element;
+                    if (Double.TryParse(element, out value))
+                    {
+                        displayNumberText = GetNumberText(value);
+                    }
+
+                    result.Spans.Add(new Span
+                    {
+                        Text = displayNumberText,
+                        ForegroundColor = literalColor,
+                    });
+                }
+                else if (s is Reverse)
+                {
+                    result.Spans.Add(new Span
+                    {
+                        Text = element,
+                        ForegroundColor = literalColor,
+                    });
+                }
+                else if (s is Models.Point && i < (separatedExpression.Count() - 1))
+                {
+                    if (separatedExpression.ElementAt(i + 1) is Literal)
+                    {
+                        string last = result.Spans.Last().Text;
+                        string stringValue = last;
+                        string next = separatedExpression.ElementAt(i + 1);
+                        stringValue = last + "." + next;
+                        double value;
+
+                        if (Double.TryParse(stringValue, out value))
+                        {
+                            result.Spans.RemoveAt(result.Spans.Count - 1);
+                            result.Spans.Add(new Span
+                            {
+                                Text = stringValue,
+                                ForegroundColor = literalColor,
+                            });
+                            i += 1;
+                        }
+                    }
+                }
+                else
+                {
+                    result.Spans.Add(new Span
+                    {
+                        Text = element,
+                        ForegroundColor = operatorColor,
+                    });
+
+                }
+
+
+                oneLineLengthCount += result.Spans.Last().Text.Length;
+            }
+
+            return result;
+        }
+
+        /// <summary>
+        /// The method provides formatted text for the calculated result. </summary>
+        /// <param name="outputText"> A result text </param>
+        /// <returns> A formatted result text </returns>
+        public FormattedString GetFormattedOutputText(String outputText)
+        {
+            string displayNumber;
+
+            double value;
+            if (Double.TryParse(outputText, out value) == false)
+            {
+                return new FormattedString();
+            }
+
+            // Exceptional Case : 0.00000 => 0.00000 (0), 0.0 (X)
+            if (value == 0 &&
+                outputText.Length > 1)
+            {
+                displayNumber = outputText;
+            }
+
+            else
+            {
+                displayNumber = "=" + GetNumberText(value);
+            }
+
+            return new FormattedString()
+            {
+                Spans =
+                {
+                    new Span
+                    {
+                        Text = displayNumber,
+                    },
+                }
+            };
+        }
+    }
+}
diff --git a/Test/Calculator/Calculator/Impl/InputParser.cs b/Test/Calculator/Calculator/Impl/InputParser.cs
new file mode 100644 (file)
index 0000000..9ca594a
--- /dev/null
@@ -0,0 +1,470 @@
+
+//Copyright 2018 Samsung Electronics Co., Ltd
+//
+//Licensed under the Apache License, Version 2.0 (the "License");
+//you may not use this file except in compliance with the License.
+//You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+//Unless required by applicable law or agreed to in writing, software
+//distributed under the License is distributed on an "AS IS" BASIS,
+//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//See the License for the specific language governing permissions and
+//limitations under the License.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+using Calculator.Models;
+
+namespace Calculator.Impl
+{
+    /// <summary>
+    /// InputParser class which validates inputted elements(Operator, Operand)
+    /// and provides separated elements list for the Formatter and the CalculatorImpl.
+    /// This class keeps the inputted expression further use for validate purpose.
+    /// </summary>
+    public sealed class InputParser
+    {
+        private List<InputElement> expressionElements = new List<InputElement>();
+
+        /// <summary>
+        /// InputElement list contains lastly validated expression. </summary>
+        public IEnumerable<InputElement> ExpressionElements
+        {
+            get
+            {
+                return expressionElements;
+            }
+        }
+
+        /// <summary>
+        /// A flag represents whether the input elements is empty or not. </summary>
+        public bool IsEmptyInputElements
+        {
+            get
+            {
+                return (expressionElements.Count == 0);
+            }
+        }
+
+        /// <summary>
+        /// A flag represents whether the last inputted element is the Literal or not. </summary>
+        private bool IsLastElementLiteral
+        {
+            get
+            {
+                if (expressionElements.Count > 0 &&
+                    expressionElements.Last() is Literal)
+                {
+                    return true;
+                }
+
+                return false;
+            }
+        }
+
+        /// <summary>
+        /// A flag represents whether the last inputted element is the Operator or not. </summary>
+        private bool IsLastElementOperator
+        {
+            get
+            {
+                if (expressionElements.Count > 0 &&
+                    expressionElements.Last() is IOperator)
+                {
+                    return true;
+                }
+
+                return false;
+            }
+        }
+
+        /// <summary>
+        /// A flag indicates last validation status. </summary>
+        private bool HasLastValidationSucceeded;
+        /// <summary>
+        /// A flag represents whether equal key is pressed or not last time. </summary>
+        private bool IsEqualUsed;
+
+        public InputParser()
+        {
+
+        }
+
+        /// <summary>
+        /// The method adds inputted element to existing expression and validates it. </summary>
+        /// <param name="input"> An inputted element </param>
+        /// <param name="separated"> An infix notation expression InputElement list </param>
+        /// <returns> An element adding result status </returns>
+        public AddingElementResult GetSeparatedPlainText(string input, out IEnumerable<InputElement> separated)
+        {
+            double inputNumber;
+            separated = expressionElements;
+
+            if (input.Length < 1)
+            {
+                HasLastValidationSucceeded = false;
+                return new InvalidFormatUsed();
+            }
+
+            if (Double.TryParse(input, out inputNumber))
+            {
+                Literal inputLiteral = new Literal(input);
+
+                if (IsEmptyInputElements)
+                {
+                    expressionElements.Add(inputLiteral);
+                    IsEqualUsed = false;
+                    HasLastValidationSucceeded = true;
+                    return new AddingPossible();
+                }
+                else
+                {
+                    AddingElementResult res = expressionElements.Last().CheckPossibilityAddingElement(ref expressionElements,
+                        ref IsEqualUsed, ref HasLastValidationSucceeded, inputLiteral);
+                    IsEqualUsed = false;
+                    if (res is AddingPossible)
+                    {
+                        HasLastValidationSucceeded = true;
+                    }
+                    else
+                    {
+                        HasLastValidationSucceeded = false;
+                    }
+
+                    return res;
+                }
+            }
+
+            InputElement inputElem = Operators.GetOperatorAsInputElement(input);
+            IOperator inputOper = inputElem as IOperator;
+            if (inputOper == null)
+            {
+                HasLastValidationSucceeded = false;
+                return new InvalidFormatUsed();
+            }
+
+            if (IsEmptyInputElements)
+            {
+                if (OperandType.LEFT == inputOper.OperandType ||
+                    OperandType.BOTH == inputOper.OperandType)
+                {
+                    // Exceptional Case : '.' => '0.'
+                    if (inputOper is Point)
+                    {
+                        expressionElements.Add(new Literal("0"));
+                    }
+
+                    else
+                    {
+                        return new InvalidFormatUsed();
+                    }
+                }
+
+                expressionElements.Add(inputElem);
+                Operators.GetOperatorAsInputElement(input)?.PostAddingWork(ref expressionElements);
+                IsEqualUsed = false;
+
+                HasLastValidationSucceeded = true;
+                return new AddingPossible();
+            }
+
+            if (inputElem.AlternativeWork(ref expressionElements, ref IsEqualUsed, ref HasLastValidationSucceeded))
+            {
+                IsEqualUsed = false;
+                HasLastValidationSucceeded = true;
+                return new AddingPossible();
+            }
+
+            // Exceptional case : Only one '.'
+            if (input.CompareTo(".") == 0)
+            {
+                if (CheckDotExist())
+                {
+                    separated = expressionElements;
+                    HasLastValidationSucceeded = true;
+                    return new AddingImpossible();
+                }
+            }
+            else if (input.CompareTo("R") == 0)
+            {
+                if (ReverseSign(out separated))
+                {
+                    return new AddingPossible();
+                }
+
+                return new InvalidFormatUsed();
+            }
+
+            expressionElements.Last().CheckPossibilityAddingElement(ref expressionElements, ref IsEqualUsed, ref HasLastValidationSucceeded, inputOper as InputElement);
+            IsEqualUsed = false;
+
+            HasLastValidationSucceeded = true;
+            return new AddingPossible();
+        }
+
+        /// <summary>
+        /// The method provides status indicates that there is '.' exists or not </summary>
+        /// <returns> A existence of '.' </returns>
+        private bool CheckDotExist()
+        {
+            for (int i = expressionElements.Count - 1; i >= 0; i--)
+            {
+                if (expressionElements[i].CompareTo(".") == 0)
+                {
+                    return true;
+                }
+
+                if (expressionElements[i] is IOperator)
+                {
+                    break;
+                }
+
+            }
+
+            return false;
+        }
+
+        /// <summary>
+        /// The method resets the InputParser to the initial status. </summary>
+        public void Clear()
+        {
+            expressionElements.Clear();
+            HasLastValidationSucceeded = false;
+            IsEqualUsed = false;
+        }
+
+        /// <summary>
+        /// The method removes last inputted element from current expression. </summary>
+        /// <param name="separated"> Current expression InputElement list </param>
+        /// <returns> Flag informing whether last element has been successfully removed. </returns>
+        public bool DeleteLast(out IEnumerable<InputElement> separated)
+        {
+            separated = new List<InputElement>();
+
+            if (expressionElements.Count == 0)
+            {
+                return false;
+            }
+
+            if (expressionElements.Last() is Literal &&
+                expressionElements.Last().GetElement.Length > 1)
+            {
+                Literal literal = expressionElements.Last() as Literal;
+
+                expressionElements[expressionElements.Count - 1] =
+                    new Literal(literal.GetElement.Substring(0, literal.GetElement.Length - 1));
+            }
+            else
+            {
+                expressionElements.RemoveAt(expressionElements.Count - 1);
+            }
+
+            separated = expressionElements;
+            return true;
+        }
+
+        /// <summary>
+        /// The method adds a reverse sign or replace last inputted reverse sign. </summary>
+        /// <param name="separated"> A current expression InputElement list </param>
+        /// <returns> An element adding reverse sign </returns>
+        public bool ReverseSign(out IEnumerable<InputElement> separated)
+        {
+            double lastNumber;
+
+            separated = expressionElements;
+            if (IsEmptyInputElements)
+            {
+                expressionElements.Add(new OpenBracket());
+                expressionElements.Add(new Reverse());
+                return true;
+            }
+
+            if (expressionElements.Last() is Point)
+            {
+                expressionElements.RemoveAt(expressionElements.Count - 1);
+            }
+
+            if (IsEmptyInputElements)
+            {
+                expressionElements.Add(new OpenBracket());
+                expressionElements.Add(new Reverse());
+                return true;
+            }
+
+            // (3 + R => ((-
+            // ((-3 + R => (3
+            // 1+-3 + R => 1+3
+            // 1.1 + R => (-1.1
+
+            if (Double.TryParse(expressionElements.Last(), out lastNumber))
+            {
+                if (lastNumber < 0)
+                {
+                    if (expressionElements.Count >= 2 &&
+                        expressionElements[expressionElements.Count - 2] is OpenBracket)
+                    {
+                        expressionElements.RemoveAt(expressionElements.Count - 1);
+                        expressionElements.RemoveAt(expressionElements.Count - 1);
+                        expressionElements.Add(new Literal(lastNumber * -1));
+                    }
+                    else
+                    {
+                        expressionElements.RemoveAt(expressionElements.Count - 1);
+                        expressionElements.Add(new Literal(lastNumber * -1));
+                    }
+                }
+                else
+                {
+                    if (expressionElements.Count > 2)
+                    {
+                        if (expressionElements[expressionElements.Count - 2] is IOperator)
+                        {
+                            if (expressionElements[expressionElements.Count - 2] is Point)
+                            {
+                                Double postPoint;
+                                if (Double.TryParse(expressionElements[expressionElements.Count - 3], out postPoint) == false)
+                                {
+                                    return false;
+                                }
+
+                                expressionElements.RemoveAt(expressionElements.Count - 1);
+                                expressionElements.RemoveAt(expressionElements.Count - 1);
+                                expressionElements.RemoveAt(expressionElements.Count - 1);
+
+                                while (expressionElements.Count > 0 &&
+                                    expressionElements.Last() is IOperator)
+                                {
+                                    if (expressionElements.Last() is OpenBracket)
+                                    {
+                                        if (postPoint < 0)
+                                        {
+                                            expressionElements.RemoveAt(expressionElements.Count - 1);
+                                        }
+
+                                        break;
+                                    }
+                                    else if (expressionElements.Last() is Reverse)
+                                    {
+                                        expressionElements.RemoveAt(expressionElements.Count - 1);
+                                        postPoint = postPoint * -1;
+                                    }
+                                    else
+                                    {
+                                        break;
+                                    }
+                                }
+
+                                if ((postPoint * -1) < 0)
+                                {
+                                    expressionElements.Add(new OpenBracket());
+                                }
+
+                                expressionElements.Add(new Literal(postPoint * -1));
+                                expressionElements.Add(new Point());
+                                expressionElements.Add(new Literal(lastNumber));
+                                return true;
+                            }
+                            else if (expressionElements[expressionElements.Count - 2] is OpenBracket)
+                            {
+                                expressionElements.RemoveAt(expressionElements.Count - 1);
+                                expressionElements.Add(new OpenBracket());
+                                expressionElements.Add(new Literal(lastNumber * -1));
+                            }
+                            else
+                            {
+                                expressionElements.RemoveAt(expressionElements.Count - 1);
+                                Operators.GetOperatorAsInputElement(expressionElements.Last())?.CheckPossibilityAddingElement(
+                                    ref expressionElements, ref IsEqualUsed, ref HasLastValidationSucceeded, new OpenBracket());
+                                expressionElements.Add(new Literal(lastNumber * -1));
+                            }
+
+                        }
+                        else
+                        {
+                            return false;
+                        }
+
+                    }
+                    else
+                    {
+                        expressionElements.RemoveAt(expressionElements.Count - 1);
+                        expressionElements.Add(new OpenBracket());
+                        expressionElements.Add(new Literal(lastNumber * -1));
+                    }
+                }
+
+                return true;
+            }
+
+            // ( + R => ((-
+            // ((R + R => (
+
+            if (expressionElements.Count > 0 &&
+                expressionElements[expressionElements.Count - 1].CompareTo("R") == 0)
+            {
+                if (expressionElements.Count > 1 &&
+                expressionElements[expressionElements.Count - 2].CompareTo("(") == 0)
+                {
+                    expressionElements.RemoveAt(expressionElements.Count - 1);
+                    expressionElements.RemoveAt(expressionElements.Count - 1);
+                }
+                else
+                {
+                    expressionElements.RemoveAt(expressionElements.Count - 1);
+                }
+            }
+            else
+            {
+                if ((expressionElements.Last().CheckPossibilityAddingElement(ref expressionElements,
+                        ref IsEqualUsed,
+                        ref HasLastValidationSucceeded,
+                        new OpenBracket())
+                    is AddingPossible) == false)
+                {
+                    return false;
+                }
+
+                expressionElements.Add(new Reverse());
+            }
+
+            return true;
+        }
+
+        /// <summary>
+        /// The method manages equal key operation. </summary>
+        /// <param name="separated"> A current expression InputElement list </param>
+        /// <returns> A status of equal key operation </returns>
+        public bool Equal(out IEnumerable<InputElement> separated)
+        {
+            List<InputElement> tempList = new List<InputElement>(expressionElements);
+            separated = tempList;
+
+            if (IsEqualUsed == false)
+            {
+                IsEqualUsed = true;
+                return true;
+            }
+
+            if (HasLastValidationSucceeded == false)
+            {
+                return false;
+            }
+
+            return true;
+        }
+
+        /// <summary>
+        /// The method sets Calculated result as expression.
+        /// Usually this is used after equal key pressed situation. </summary>
+        /// <param name="result"> A calculated result value </param>
+        public void Set(string result)
+        {
+            expressionElements.Clear();
+            expressionElements.Add(new Literal(result));
+        }
+    }
+}
diff --git a/Test/Calculator/Calculator/Models/AddingElementResult.cs b/Test/Calculator/Calculator/Models/AddingElementResult.cs
new file mode 100644 (file)
index 0000000..85ad49d
--- /dev/null
@@ -0,0 +1,89 @@
+
+//Copyright 2018 Samsung Electronics Co., Ltd
+//
+//Licensed under the Apache License, Version 2.0 (the "License");
+//you may not use this file except in compliance with the License.
+//You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+//Unless required by applicable law or agreed to in writing, software
+//distributed under the License is distributed on an "AS IS" BASIS,
+//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//See the License for the specific language governing permissions and
+//limitations under the License.
+
+using System;
+
+namespace Calculator.Models
+{
+    /// <summary>
+    /// AddingElementResult base class to notify of element submit. 
+    /// </summary>
+    public class AddingElementResult
+    {
+        /// <summary>
+        /// Message to be displayed in error pop up.
+        /// </summary>
+        public virtual String Message
+        {
+            get { return string.Empty; }
+        }
+    }
+
+    /// <summary>
+    /// Class used to inform that adding element is possible. 
+    /// </summary>
+    public class AddingPossible : AddingElementResult
+    {
+    }
+
+    /// <summary>
+    /// Class used to inform that  adding element is impossible.
+    /// </summary>
+    public class AddingImpossible : AddingElementResult
+    {
+    }
+
+    /// <summary>
+    /// Class used to inform that adding element is impossible due to invalid expression format. 
+    /// </summary>
+    public class InvalidFormatUsed : AddingElementResult
+    {
+        /// <summary>
+        /// Message to be displayed in error pop up.
+        /// </summary>
+        public override String Message
+        {
+            get { return "Invalid format used."; }
+        }
+    }
+
+    /// <summary>
+    /// Class used to inform that adding element is impossible due to a 15 digits exceeding number. 
+    /// </summary>
+    public class CantMoreThan15Digit : AddingElementResult
+    {
+        /// <summary>
+        /// Message to be displayed in error pop up.
+        /// </summary>
+        public override String Message
+        {
+            get { return "Can't enter more than 15 digits."; }
+        }
+    }
+
+    /// <summary>
+    /// Class used to inform that adding element is impossible because number contains more than 10 digits after decimal point. 
+    /// </summary>
+    public class CantMoreThan10Decimal : AddingElementResult
+    {
+        /// <summary>
+        /// Message to be displayed in error pop up.
+        /// </summary>
+        public override String Message
+        {
+            get { return "Can't enter more than 10 decimal places."; }
+        }
+    }
+}
diff --git a/Test/Calculator/Calculator/Models/CalculationResult.cs b/Test/Calculator/Calculator/Models/CalculationResult.cs
new file mode 100644 (file)
index 0000000..c849505
--- /dev/null
@@ -0,0 +1,82 @@
+
+//Copyright 2018 Samsung Electronics Co., Ltd
+//
+//Licensed under the Apache License, Version 2.0 (the "License");
+//you may not use this file except in compliance with the License.
+//You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+//Unless required by applicable law or agreed to in writing, software
+//distributed under the License is distributed on an "AS IS" BASIS,
+//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//See the License for the specific language governing permissions and
+//limitations under the License.
+
+using System;
+
+namespace Calculator.Models
+{
+    /// <summary>
+    /// CalculateResult base class to notify the calculate result. </summary>
+    public class CalculationResult
+    {
+        /// <summary>
+        /// A message will be displayed in error pop up . </summary>
+        public virtual String Message
+        {
+            get { return string.Empty; }
+        }
+    }
+
+    /// <summary>
+    /// A CalculateResult class describes calculating is completed without error. </summary>
+    public class CalculationSuccessful : CalculationResult
+    {
+    }
+
+    /// <summary>
+    /// A CalculateFailed class describes calculating is failed. </summary>
+    public class CalculationFailed : CalculationResult
+    {
+    }
+
+    /// <summary>
+    /// A CalculateResult class describes calculating is failed
+    /// due to invalid expression format. </summary>
+    public class CantCalculateInvalidFormat : CalculationResult
+    {
+        /// <summary>
+        /// A message will be displayed in error pop up . </summary>
+        public override String Message
+        {
+            get { return "Invalid format used."; }
+        }
+    }
+
+    /// <summary>
+    /// A CalculateResult class describes calculating is failed
+    /// due to big number. </summary>
+    public class CantCalculateTooBigNumber : CalculationResult
+    {
+        /// <summary>
+        /// A message will be displayed in error pop up . </summary>
+        public override String Message
+        {
+            get { return "Couldn't display entire result. Result too long."; }
+        }
+    }
+
+    /// <summary>
+    /// A CalculateResult class describes calculating is failed
+    /// due to dividing by zero. </summary>
+    public class CantDivideByZero : CalculationResult
+    {
+        /// <summary>
+        /// A message will be displayed in error pop up . </summary>
+        public override String Message
+        {
+            get { return "Can't divide by zero."; }
+        }
+    }
+}
diff --git a/Test/Calculator/Calculator/Models/IBinaryOperator.cs b/Test/Calculator/Calculator/Models/IBinaryOperator.cs
new file mode 100644 (file)
index 0000000..4099649
--- /dev/null
@@ -0,0 +1,24 @@
+
+//Copyright 2018 Samsung Electronics Co., Ltd
+//
+//Licensed under the Apache License, Version 2.0 (the "License");
+//you may not use this file except in compliance with the License.
+//You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+//Unless required by applicable law or agreed to in writing, software
+//distributed under the License is distributed on an "AS IS" BASIS,
+//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//See the License for the specific language governing permissions and
+//limitations under the License.
+
+namespace Calculator.Models
+{
+    /// <summary>
+    /// Interface for the BinaryOperator.
+    /// </summary>
+    public interface IBinaryOperator : IOperator
+    {
+    }
+}
diff --git a/Test/Calculator/Calculator/Models/INullary.cs b/Test/Calculator/Calculator/Models/INullary.cs
new file mode 100644 (file)
index 0000000..05382c9
--- /dev/null
@@ -0,0 +1,24 @@
+
+//Copyright 2018 Samsung Electronics Co., Ltd
+//
+//Licensed under the Apache License, Version 2.0 (the "License");
+//you may not use this file except in compliance with the License.
+//You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+//Unless required by applicable law or agreed to in writing, software
+//distributed under the License is distributed on an "AS IS" BASIS,
+//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//See the License for the specific language governing permissions and
+//limitations under the License.
+
+namespace Calculator.Models
+{
+    /// <summary>
+    /// An interface for the Nullary.
+    /// </summary>
+    public interface INullary : IOperator
+    {
+    }
+}
diff --git a/Test/Calculator/Calculator/Models/IOperator.cs b/Test/Calculator/Calculator/Models/IOperator.cs
new file mode 100644 (file)
index 0000000..efa75a3
--- /dev/null
@@ -0,0 +1,58 @@
+
+//Copyright 2018 Samsung Electronics Co., Ltd
+//
+//Licensed under the Apache License, Version 2.0 (the "License");
+//you may not use this file except in compliance with the License.
+//You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+//Unless required by applicable law or agreed to in writing, software
+//distributed under the License is distributed on an "AS IS" BASIS,
+//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//See the License for the specific language governing permissions and
+//limitations under the License.
+
+namespace Calculator.Models
+{
+    /// <summary>
+    /// A operand placing type of the operator
+    /// LEFT : Operand is placed on Left side only
+    /// RIGHT : Operand is placed on Right side only
+    /// BOTH : Operand is placed on Both side
+    /// NONE : Operand is placed on Both side
+    /// </summary>
+    public enum OperandType
+    {
+        LEFT,   // Operand is placed on Left side only
+        RIGHT,  // Operand is placed on Right side only
+        BOTH,   // Operand is placed on Both side
+        NONE,   // Operand is placed on Both side
+    };
+
+    /// <summary>
+    /// An interface for the Operator</summary>
+    public interface IOperator
+    {
+        /// <summary>
+        /// Operator priority 
+        /// </summary>
+        int Priority { get; }
+
+        /// <summary>
+        /// An operator's operand type 
+        /// </summary>
+        /// <seealso cref="OperandType">
+        /// Operand type. 
+        /// </seealso>
+        OperandType OperandType { get; }
+
+        /// <summary>
+        /// The method provides result of operator 
+        /// </summary>
+        /// <param name="left"> Left side element. </param>
+        /// <param name="right"> Light side element. </param>
+        /// <param name="result"> Operator's calculation result. </param>
+        void GetResult(double left, double right, out double result);
+    }
+}
diff --git a/Test/Calculator/Calculator/Models/IUnaryOperator.cs b/Test/Calculator/Calculator/Models/IUnaryOperator.cs
new file mode 100644 (file)
index 0000000..c491701
--- /dev/null
@@ -0,0 +1,23 @@
+
+//Copyright 2018 Samsung Electronics Co., Ltd
+//
+//Licensed under the Apache License, Version 2.0 (the "License");
+//you may not use this file except in compliance with the License.
+//You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+//Unless required by applicable law or agreed to in writing, software
+//distributed under the License is distributed on an "AS IS" BASIS,
+//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//See the License for the specific language governing permissions and
+//limitations under the License.
+
+namespace Calculator.Models
+{
+    /// <summary>
+    /// An interface for the UnaryOperator. </summary>
+    public interface IUnaryOperator : IOperator
+    {
+    }
+}
diff --git a/Test/Calculator/Calculator/Models/InputElement.cs b/Test/Calculator/Calculator/Models/InputElement.cs
new file mode 100644 (file)
index 0000000..bda25f9
--- /dev/null
@@ -0,0 +1,87 @@
+
+//Copyright 2018 Samsung Electronics Co., Ltd
+//
+//Licensed under the Apache License, Version 2.0 (the "License");
+//you may not use this file except in compliance with the License.
+//You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+//Unless required by applicable law or agreed to in writing, software
+//distributed under the License is distributed on an "AS IS" BASIS,
+//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//See the License for the specific language governing permissions and
+//limitations under the License.
+
+using System;
+using System.Collections.Generic;
+
+namespace Calculator.Models
+{
+    /// <summary>
+    /// A base class for the calculating elements(Number, Operators).
+    /// The InputElemet can be a Literal and any other operators that inherit the InputElement and IOperator. </summary>
+    public abstract class InputElement : IComparable<string>
+    {
+        /// <summary>
+        /// A property provides element string.
+        /// This property is used for validation and calculation </summary>
+        public abstract string GetElement { get; }
+
+        /// <summary>
+        /// A property provides displaying element string.
+        /// This property is used for building formatted string. </summary>
+        public abstract string GetDisplayElement { get; }
+
+        /// <summary>
+        /// The method provides whether it is possible to add followingElement after this InputElement(is placed at the end of expressionElements).
+        /// This method can modify current expression by adding new element or removing last element. </summary>
+        /// <param name="expressionElements"> Current expression, an InputElement list </param>
+        /// <param name="isEqualUsed"> A flag value whether equal key is pressed or not </param>
+        /// <param name="isLastValidationSucceed"> A flag value whether last calculation is succeed or not </param>
+        /// <param name="followingElement"> An input element will be added after this element. </param>
+        /// <returns> A status of adding element to exist expression </returns>
+        /// <seealso cref="AlternativeWork(ref List{InputElement}, ref bool, ref bool)"/>
+        public abstract AddingElementResult CheckPossibilityAddingElement(ref List<InputElement> expressionElements,
+            ref bool isEqualUsed,
+            ref bool isLastValidationSucceed,
+            InputElement followingElement);
+
+        /// <summary>
+        /// The method doing some exceptional or an independent work instead of adding this InputElement.
+        /// If this methods return true, calculator do not call the CheckPossibilityAddingElement method.</summary>
+        /// <param name="expressionElements"> Current expression, an InputElement list </param>
+        /// <param name="IsEqualUsed"> A flag value whether equal key is pressed or not </param>
+        /// <param name="IsLastValidationSucceed"> A flag value whether last calculation is succeed or not </param>
+        /// <returns> A status of operator's alternative work  </returns>
+        /// <seealso cref="AddingElementResult"/>
+        public virtual bool AlternativeWork(ref List<InputElement> expressionElements,
+            ref bool IsEqualUsed,
+            ref bool IsLastValidationSucceed)
+        {
+            return false;
+        }
+
+        /// <summary>
+        /// The method doing additional work after added as followingElement.</summary>
+        /// <param name="expressionElements"> Current expression, an InputElement list </param>
+        public virtual void PostAddingWork(ref List<InputElement> expressionElements)
+        {
+        }
+
+        public static implicit operator string(InputElement ie)
+        {
+            return ie.GetElement;
+        }
+
+        public override string ToString()
+        {
+            return GetElement;
+        }
+
+        public int CompareTo(string other)
+        {
+            return other.CompareTo(GetElement);
+        }
+    }
+}
diff --git a/Test/Calculator/Calculator/Models/Literal.cs b/Test/Calculator/Calculator/Models/Literal.cs
new file mode 100644 (file)
index 0000000..8187786
--- /dev/null
@@ -0,0 +1,157 @@
+
+//Copyright 2018 Samsung Electronics Co., Ltd
+//
+//Licensed under the Apache License, Version 2.0 (the "License");
+//you may not use this file except in compliance with the License.
+//You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+//Unless required by applicable law or agreed to in writing, software
+//distributed under the License is distributed on an "AS IS" BASIS,
+//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//See the License for the specific language governing permissions and
+//limitations under the License.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Calculator.Models
+{
+    /// <summary>
+    /// This class represents numbers. 
+    /// </summary>
+    public class Literal : InputElement
+    {
+        /// <summary>
+        /// Number value 
+        /// </summary>
+        private string literal;
+
+        /// <summary>
+        /// Literal constructor for a text formatted number. 
+        /// </summary>
+        /// <param name="value"> A number value string </param>
+        public Literal(string value)
+        {
+            literal = value ?? string.Empty;
+        }
+
+        /// <summary>
+        /// Literal constructor for a number. 
+        /// </summary>
+        /// <param name="value"> A number value </param>
+        public Literal(double value)
+        {
+            literal = value.ToString();
+        }
+
+        /// <summary>
+        /// A property provides element string.
+        /// This element string is using for validation and calculation.
+        /// </summary>
+        public override string GetElement
+        {
+            get
+            {
+                return literal;
+            }
+        }
+
+        /// <summary>
+        /// A property provides displaying element string.
+        /// This displaying element is used for making formatted string.
+        /// </summary>
+        public override string GetDisplayElement
+        {
+            get
+            {
+                return literal;
+            }
+        }
+
+        /// <summary>
+        /// The method provides possibility of adding followingElement after this Literal.
+        /// This method can modify current expression by adding additional element or removing last element. </summary>
+        /// <param name="expressionElements"> Current expression, an InputElement list </param>
+        /// <param name="IsEqualUsed"> A flag value whether equal key is pressed or not </param>
+        /// <param name="IsLastValidationSucceed"> A flag value whether last calculation is succeed or not </param>
+        /// <param name="right"> An input element will be added after this element. </param>
+        /// <returns> A status of adding element to current expression. </returns>
+        public override AddingElementResult CheckPossibilityAddingElement(ref List<InputElement> expressionElements,
+            ref bool IsEqualUsed,
+            ref bool IsLastValidationSucceed,
+            InputElement right)
+        {
+            if (right is Literal)
+            {
+                Literal lastLiteral = expressionElements.Last() as Literal;
+
+                if (IsEqualUsed &&
+                    IsLastValidationSucceed)
+                {
+                    expressionElements.Clear();
+                    expressionElements.Add(right);
+                }
+                else
+                {
+                    // Exceptional case, prohibit 15 digits
+                    if (lastLiteral.GetElement.Length > 14)
+                    {
+                        return new CantMoreThan15Digit();
+                    }
+
+                    // Exceptional case, prohibit 10 decimal places,
+                    // OK - 0.0000000000 (10)
+                    // NO - 0.00000000000 (11)
+                    if (expressionElements.Count > 2 &&
+                        lastLiteral.GetElement.Length == 10 &&
+                        expressionElements[expressionElements.Count - 2] is Point)
+                    {
+                        return new CantMoreThan10Decimal();
+                    }
+
+                    if (lastLiteral.Append(right))
+                    {
+                        return new AddingPossible();
+                    }
+
+                    return new InvalidFormatUsed();
+                }
+            }
+            else
+            {
+                IOperator rightOper = right as IOperator;
+
+                if (right is INullary ||
+                OperandType.RIGHT == rightOper.OperandType)
+                {
+                    expressionElements.Add(new Multiplication());
+                }
+
+                expressionElements.Add(right);
+
+                right.PostAddingWork(ref expressionElements);
+            }
+
+            return new AddingPossible();
+        }
+
+        /// <summary>
+        /// The methods appends a given literal.</summary>
+        /// <param name="value"> A InputElement(Literal) </param>
+        /// <returns> Result status of appending </returns>
+        public bool Append(InputElement value)
+        {
+            double number;
+            if (Double.TryParse(value.GetElement, out number) == false)
+            {
+                return false;
+            }
+
+            literal += value.GetElement;
+            return true;
+        }
+    }
+}
diff --git a/Test/Calculator/Calculator/Models/Operators.cs b/Test/Calculator/Calculator/Models/Operators.cs
new file mode 100644 (file)
index 0000000..7b4431f
--- /dev/null
@@ -0,0 +1,958 @@
+
+//Copyright 2018 Samsung Electronics Co., Ltd
+//
+//Licensed under the Apache License, Version 2.0 (the "License");
+//you may not use this file except in compliance with the License.
+//You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+//Unless required by applicable law or agreed to in writing, software
+//distributed under the License is distributed on an "AS IS" BASIS,
+//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//See the License for the specific language governing permissions and
+//limitations under the License.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Tizen;
+
+namespace Calculator.Models
+{
+    /// <summary>
+    /// This class includes all possible operators for the InputParser and the CalculatorImpl.
+    /// Also this class includes helper methods for the input elements </summary>
+    public static class Operators
+    {
+        /// <summary>
+        /// Dictionary of the all possible operators 
+        /// </summary>
+        private static IReadOnlyDictionary<String, IOperator> operators = new Dictionary<string, IOperator>()
+        {
+            { Plus.Operator, new Plus() },
+            { Minus.Operator, new Minus() },
+            { Multiplication.Operator, new Multiplication() },
+            { Division.Operator, new Division() },
+            { OpenBracket.Operator, new OpenBracket() },
+            { CloseBracket.Operator, new CloseBracket() },
+            { Point.Operator, new Point() },
+            { Reverse.Operator, new Reverse() },
+        };
+
+        /// <summary>
+        /// The property returns operator dictionary.
+        /// </summary>
+        public static IReadOnlyDictionary<String, IOperator> OperatorMap
+        {
+            get => operators;
+        }
+
+        /// <summary>
+        /// The method provides matched Operator's instance </summary>
+        /// <param name="oper"> A operator's string. </param>
+        /// <returns> Matched operator's instance.
+        /// But NULL will be returned if there is no matched operator. </returns>
+        public static IOperator GetOperator(string oper)
+        {
+            if (OperatorMap.ContainsKey(oper))
+            {
+                return OperatorMap[oper];
+            }
+
+            return null;
+        }
+
+        /// <summary>
+        /// The method provides matched Operator's instance as InputElement type </summary>
+        /// <param name="oper"> A operator's string. </param>
+        /// <returns> Matched operator's InputElement type instance.
+        /// But NULL will be returned if there is no matched operator. </returns>
+        public static InputElement GetOperatorAsInputElement(string oper)
+        {
+            if (OperatorMap.ContainsKey(oper))
+            {
+                return OperatorMap[oper] as InputElement;
+            }
+
+            return null;
+        }
+
+        /// <summary>
+        /// The method checks addingElement can be following of left argument receiving operator </summary>
+        /// <param name="addingElement"> A adding InputElementthat can be a Literal or a Operator </param>
+        /// /// <param name="isMultiplyOperatorRequired"> A flag indicates '*' is required to following addingElement if following is possible </param>
+        /// <returns> A possibility of following </returns>
+        internal static bool IsPossibleCombineWithOperatorLeft(InputElement addingElement, out bool isMultiplyOperatorRequired)
+        {
+            IOperator addingElementOper = null;
+
+            isMultiplyOperatorRequired = false;
+            if ((addingElementOper = addingElement as IOperator) == null ||
+                addingElement is INullary)
+            {
+                isMultiplyOperatorRequired = true;
+                return true;
+            }
+
+            if (OperandType.LEFT == addingElementOper.OperandType || OperandType.BOTH == addingElementOper.OperandType)
+            {
+                return false;
+            }
+
+            else if (OperandType.RIGHT == addingElementOper.OperandType)
+            {
+                isMultiplyOperatorRequired = true;
+                return true;
+            }
+
+            return false;
+        }
+
+        /// <summary>
+        /// The method checks addingElement can be following of both side argument receiving operator </summary>
+        /// <param name="addingElement"> A adding InputElementthat can be a Literal or a Operator </param>
+        /// <param name="isMultiplyOperatorRequired"> A flag indicates '*' is required to following addingElement if following is possible </param>
+        /// <returns> A possibility of following </returns>
+        internal static bool IsPossibleCombineWithOperatorRightBoth(InputElement addingElement, out bool isMultiplyOperatorRequired)
+        {
+            IOperator addingElementOper = null;
+
+            isMultiplyOperatorRequired = false;
+
+            if ((addingElementOper = addingElement as IOperator) == null ||
+                addingElement is INullary)
+            {
+                return true;
+            }
+
+            if (addingElementOper is IUnaryOperator &&
+                OperandType.RIGHT == addingElementOper.OperandType)
+            {
+                return true;
+            }
+
+            return false;
+        }
+
+        /// <summary>
+        /// The method checks addingElement can be following of left argument receiving operand type operator </summary>
+        /// <param name="addingElement"> A adding InputElementthat can be a Literal or a Operator </param>
+        /// <param name="isMultiplyOperatorRequired"> A flag indicates '*' is required to following addingElement if following is possible </param>
+        /// <returns> A possibility of following </returns>
+        internal static bool IsPossibleCombineWithOperandOperatorLeft(InputElement addingElement, out bool isMultiplyOperatorRequired)
+        {
+            IOperator addingElementOper = null;
+
+            isMultiplyOperatorRequired = false;
+
+            if ((addingElementOper = addingElement as IOperator) == null ||
+                addingElement is INullary)
+            {
+                isMultiplyOperatorRequired = true;
+                return true;
+            }
+
+            if (OperandType.LEFT == addingElementOper.OperandType || OperandType.BOTH == addingElementOper.OperandType)
+            {
+                return true;   // ex ))
+            }
+
+            else if (OperandType.RIGHT == addingElementOper.OperandType)
+            {
+                isMultiplyOperatorRequired = true;
+                return true;
+            }
+
+            return false;
+        }
+
+        /// <summary>
+        /// The method checks addingElement can be following of both side argument receiving operand type operator </summary>
+        /// <param name="addingElement"> A adding InputElementthat can be a Literal or a Operator </param>
+        /// <param name="isMultiplyOperatorRequired"> A flag indicates '*' is required to following addingElement if following is possible </param>
+        /// <returns> A possibility of following </returns>
+        internal static bool IsPossibleCombineWithOperandOperatorRightBoth(InputElement addingElement, out bool isMultiplyOperatorRequired)
+        {
+            IOperator addingElementOper = null;
+
+            isMultiplyOperatorRequired = false;
+
+            if ((addingElementOper = addingElement as IOperator) == null ||
+                addingElement is INullary)
+            {
+                return true;
+            }
+
+            if (addingElementOper is IUnaryOperator &&
+                OperandType.RIGHT == addingElementOper.OperandType)
+            {
+                return true;
+            }
+
+            return false;
+        }
+
+        /// <summary>
+        /// The method checks addingElement can be following of no argument receiving operand type operator </summary>
+        /// <param name="addingElement"> A adding InputElementthat can be a Literal or a Operator </param>
+        /// <param name="isMultiplyOperatorRequired"> A flag indicates '*' is required to following addingElement if following is possible </param>
+        /// <returns> A possibility of following </returns>
+        internal static bool IsPossibleCombineOperandOperatorWithNone(InputElement addingElement, out bool isMultiplyOperatorRequired)
+        {
+            IOperator addingElementOper = null;
+
+            isMultiplyOperatorRequired = false;
+            if ((addingElementOper = addingElement as IOperator) == null ||
+                addingElement is INullary ||
+                OperandType.RIGHT == addingElementOper.OperandType)
+            {
+                isMultiplyOperatorRequired = true;
+                return true;
+            }
+
+            return true;
+        }
+
+        /// <summary>
+        /// The method checks whether addingElement can be following to current expression or
+        /// add '*' if the addingElement is required</summary>
+        /// <param name="expressionElements"> Current expression, an InputElement list </param>
+        /// <param name="isEqualUsed"> A flag value whether equal key is pressed or not </param>
+        /// <param name="isLastValidationSucceed"> A flag value whether last calculation is succeed or not </param>
+        /// <param name="addingElement"> A InputElement will be added after this element. </param>
+        /// <returns> A status of adding element to exist expression </returns>
+        private static bool PreInsertingWork(ref List<InputElement> expressionElements,
+                                             ref bool isEqualUsed, 
+                                             ref bool isLastValidationSucceed,
+                                             InputElement addingElement)
+        {
+            if (expressionElements.Count == 0)
+            {
+                throw new Exception("This function should not be called if there is no inputed element");
+            }
+
+            if (expressionElements.Last() is Literal &&
+                addingElement is IOperator)
+            {
+                IOperator inputOper = Operators.GetOperator(addingElement);
+                if (inputOper is INullary ||
+                    OperandType.RIGHT == inputOper?.OperandType)
+                {
+                    expressionElements.Add(new Multiplication());
+                }
+
+                return true;
+            }
+
+            IOperator lastOper = expressionElements.Last() as IOperator;
+            bool isMultiplyRequird = false;
+            bool res = false;
+
+            if (lastOper is Point &&
+                addingElement is IOperator)
+            {
+                IOperator inputOper = Operators.GetOperator(addingElement);
+                expressionElements.RemoveAt(expressionElements.Count - 1);
+                if (OperandType.RIGHT == inputOper.OperandType ||
+                    OperandType.NONE == inputOper.OperandType)
+                {
+                    expressionElements.Add(new Multiplication());
+                }
+
+                return true;
+            }
+
+            if (OperandType.RIGHT == lastOper.OperandType ||
+            OperandType.BOTH == lastOper.OperandType)
+            {
+                if (lastOper is IUnaryOperator)
+                {
+                    res = Operators.IsPossibleCombineWithOperandOperatorRightBoth(addingElement, out isMultiplyRequird);
+                }
+
+                else
+                {
+                    res = Operators.IsPossibleCombineWithOperatorRightBoth(addingElement, out isMultiplyRequird);
+                }
+            }
+            else if (OperandType.LEFT == lastOper.OperandType)
+            {
+                if (lastOper is IUnaryOperator)
+                {
+                    res = Operators.IsPossibleCombineWithOperandOperatorLeft(addingElement, out isMultiplyRequird);
+                }
+
+                else
+                {
+                    res = Operators.IsPossibleCombineWithOperatorLeft(addingElement, out isMultiplyRequird);
+                }
+            }
+            else if (OperandType.NONE == lastOper.OperandType)
+            {
+                res = Operators.IsPossibleCombineOperandOperatorWithNone(addingElement, out isMultiplyRequird);
+            }
+
+            if (isMultiplyRequird)
+            {
+                expressionElements.Add(new Multiplication());
+            }
+
+            return res;
+        }
+
+        /// <summary>
+        /// The methods insert addingElement to current expression(expressionElements)</summary>
+        /// <param name="expressionElements"> Current expression, an InputElement list </param>
+        /// <param name="isEqualUsed"> A flag value whether equal key is pressed or not </param>
+        /// <param name="isLastValidationSucceed"> A flag value whether last calculation is succeed or not </param>
+        /// <param name="addingElement"> A InputElement will be added after this element. </param>
+        /// <returns> A status of adding element to exist expression </returns>
+        /// <seealso cref="PreInsertingWork(ref List{InputElement}, ref bool, ref bool, InputElement)"/>
+        internal static bool InsertingWork(ref List<InputElement> expressionElements, 
+                                           ref bool isEqualUsed,
+                                           ref bool isLastValidationSucceed,
+                                           InputElement addingElement)
+        {
+            IOperator inputOper = Operators.GetOperator(addingElement);
+
+
+            if (PreInsertingWork(ref expressionElements, ref isEqualUsed, ref isLastValidationSucceed, addingElement) == false)
+            {
+                if (addingElement is IOperator &&
+                    inputOper == null)
+                {
+                    return isLastValidationSucceed = false;
+                }
+
+                IOperator lastOper = expressionElements.Last() as IOperator;
+                if (lastOper == null)
+                {
+                    return isLastValidationSucceed = false;
+                }
+
+                if (OperandType.BOTH == lastOper.OperandType &&
+                           OperandType.BOTH == inputOper?.OperandType)
+                {
+                    expressionElements.RemoveAt(expressionElements.Count - 1);
+                    expressionElements.Add(addingElement);
+                    return true;
+                }
+
+                return isLastValidationSucceed = false;
+            }
+
+            expressionElements.Add(addingElement);
+
+            addingElement.PostAddingWork(ref expressionElements);
+            return true;
+        }
+    }
+
+    /// <summary>
+    /// A plus operator. </summary>
+    public class Plus : InputElement, IBinaryOperator
+    {
+        public static string Operator = "+";
+        /// <summary>
+        /// A property provides element string.
+        /// This element string is using for validation and calculation. </summary>
+        public override string GetElement
+        {
+            get => Operator;
+        }
+
+        /// <summary>
+        /// A property provides displaying element string.
+        /// This displaying element is using for making formatted string. </summary>
+        public override string GetDisplayElement
+        {
+            get => "+";
+        }
+
+        /// <summary>
+        /// A operator priority </summary>
+        public int Priority
+        {
+            get => 2;
+        }
+
+        /// <summary>
+        /// A operator's operand type </summary>
+        /// <seealso cref="OperandType">
+        /// A operand type. </seealso>
+        public OperandType OperandType
+        {
+            get => OperandType.BOTH;
+        }
+
+        /// <summary>
+        /// The method provides possibility of that is it possible adding addingElement after this InputElement.
+        /// This method can modify current expression by adding additional element or removing last element. </summary>
+        /// <param name="expressionElements"> Current expression, an InputElement list </param>
+        /// <param name="isEqualUsed"> A flag value whether equal key is pressed or not </param>
+        /// <param name="isLastValidationSucceed"> A flag value whether last calculation is succeed or not </param>
+        /// <param name="addingElement"> A InputElement will be added after this element. </param>
+        /// <returns> A status of adding element to exist expression </returns>
+        public override AddingElementResult CheckPossibilityAddingElement(ref List<InputElement> expressionElements,
+            ref bool isEqualUsed,
+            ref bool isLastValidationSucceed,
+            InputElement addingElement)
+        {
+            if (Operators.InsertingWork(ref expressionElements, ref isEqualUsed, ref isLastValidationSucceed, addingElement))
+            {
+                return new AddingPossible();
+            }
+
+            return new InvalidFormatUsed();
+        }
+
+        /// <summary>
+        /// The method provides result of operator </summary>
+        /// <param name="left"> A left side element. </param>
+        /// <param name="right"> A rightside element. </param>
+        /// <param name="result"> Calculation result. </param>
+        public void GetResult(double left, double right, out double result)
+        {
+            result = left + right;
+        }
+    }
+
+    /// <summary>
+    /// A minus operator </summary>
+    public class Minus : InputElement, IBinaryOperator
+    {
+        public static string Operator = "-";
+        /// <summary>
+        /// A property provides element string.
+        /// This element string is using for validation and calculation. </summary>
+        public override string GetElement
+        {
+            get => Operator;
+        }
+
+        /// <summary>
+        /// A property provides displaying element string.
+        /// This displaying element is using for making formatted string. </summary>
+        public override string GetDisplayElement
+        {
+            get => "-";
+        }
+
+        /// <summary>
+        /// A operator priority </summary>
+        public int Priority
+        {
+            get => 2;
+        }
+
+        /// <summary>
+        /// A operator's operand type </summary>
+        /// <seealso cref="OperandType">
+        /// A operand type. </seealso>
+        public OperandType OperandType
+        {
+            get => OperandType.BOTH;
+        }
+
+        /// <summary>
+        /// The method provides possibility of that is it possible adding addingElement after this InputElement.
+        /// This method can modify current expression by adding additional element or removing last element. </summary>
+        /// <param name="expressionElements"> Current expression, an InputElement list </param>
+        /// <param name="isEqualUsed"> A flag value whether equal key is pressed or not </param>
+        /// <param name="isLastValidationSucceed"> A flag value whether last calculation is succeed or not </param>
+        /// <param name="addingElement"> A InputElement will be added after this element. </param>
+        /// <returns> A status of adding element to exist expression </returns>
+        public override AddingElementResult CheckPossibilityAddingElement(ref List<InputElement> expressionElements,
+            ref bool isEqualUsed,
+            ref bool isLastValidationSucceed,
+            InputElement addingElement)
+        {
+            if (Operators.InsertingWork(ref expressionElements, ref isEqualUsed, ref isLastValidationSucceed, addingElement))
+            {
+                return new AddingPossible();
+            }
+
+            return new InvalidFormatUsed();
+        }
+
+        /// <summary>
+        /// The method provides result of operator </summary>
+        /// <param name="left"> A left side element. </param>
+        /// <param name="right"> A rightside element. </param>
+        /// <param name="result"> Calculation result. </param>
+        public void GetResult(double left, double addingElement, out double result)
+        {
+            result = left - addingElement;
+        }
+    }
+
+    /// <summary>
+    /// A multiplication operator </summary>
+    public class Multiplication : InputElement, IBinaryOperator
+    {
+        public static string Operator = "*";
+        /// <summary>
+        /// A property provides element string.
+        /// This element string is using for validation and calculation. </summary>
+        public override string GetElement
+        {
+            get => Operator;
+        }
+
+        /// <summary>
+        /// A property provides displaying element string.
+        /// This displaying element is using for making formatted string. </summary>
+        public override string GetDisplayElement
+        {
+            get =>"×";
+        }
+
+        /// <summary>
+        /// A operator priority </summary>
+        public int Priority
+        {
+            get => 3;
+        }
+
+        /// <summary>
+        /// A operator's operand type </summary>
+        /// <seealso cref="OperandType">
+        /// A operand type. </seealso>
+        public OperandType OperandType
+        {
+            get => OperandType.BOTH;
+        }
+
+        /// <summary>
+        /// The method provides possibility of that is it possible adding addingElement after this InputElement.
+        /// This method can modify current expression by adding additional element or removing last element. </summary>
+        /// <param name="expressionElements"> Current expression, an InputElement list </param>
+        /// <param name="isEqualUsed"> A flag value whether equal key is pressed or not </param>
+        /// <param name="isLastValidationSucceed"> A flag value whether last calculation is succeed or not </param>
+        /// <param name="addingElement"> A InputElement will be added after this element. </param>
+        /// <returns> A status of adding element to exist expression </returns>
+        public override AddingElementResult CheckPossibilityAddingElement(ref List<InputElement> expressionElements,
+            ref bool isEqualUsed,
+            ref bool isLastValidationSucceed,
+            InputElement addingElement)
+        {
+            if (Operators.InsertingWork(ref expressionElements, ref isEqualUsed, ref isLastValidationSucceed, addingElement))
+            {
+                return new AddingPossible();
+            }
+
+            return new InvalidFormatUsed();
+        }
+
+        /// <summary>
+        /// The method provides result of operator </summary>
+        /// <param name="left"> A left side element. </param>
+        /// <param name="right"> A rightside element. </param>
+        /// <param name="result"> Calculation result. </param>
+        public void GetResult(double left, double right, out double result)
+        {
+            result = left * right;
+        }
+    }
+
+    /// <summary>
+    /// A division operator </summary>
+    public class Division : InputElement, IBinaryOperator
+    {
+        public static string Operator = "/";
+        /// <summary>
+        /// A property provides element string.
+        /// This element string is using for validation and calculation. </summary>
+        public override string GetElement
+        {
+            get => Operator;
+        }
+
+        /// <summary>
+        /// A property provides displaying element string.
+        /// This displaying element is using for making formatted string. </summary>
+        public override string GetDisplayElement
+        {
+            get => "÷";
+        }
+
+        /// <summary>
+        /// A operator priority </summary>
+        public int Priority
+        {
+            get => 3;
+        }
+
+        /// <summary>
+        /// A operator's operand type </summary>
+        /// <seealso cref="OperandType">
+        /// A operand type. </seealso>
+        public OperandType OperandType
+        {
+            get => OperandType.BOTH;
+        }
+
+        /// <summary>
+        /// The method provides possibility of that is it possible adding addingElement after this InputElement.
+        /// This method can modify current expression by adding additional element or removing last element. </summary>
+        /// <param name="expressionElements"> Current expression, an InputElement list </param>
+        /// <param name="isEqualUsed"> A flag value whether equal key is pressed or not </param>
+        /// <param name="isLastValidationSucceed"> A flag value whether last calculation is succeed or not </param>
+        /// <param name="addingElement"> A InputElement will be added after this element. </param>
+        /// <returns> A status of adding element to exist expression </returns>
+        public override AddingElementResult CheckPossibilityAddingElement(ref List<InputElement> expressionElements,
+            ref bool isEqualUsed,
+            ref bool isLastValidationSucceed,
+            InputElement addingElement)
+        {
+            if (Operators.InsertingWork(ref expressionElements, ref isEqualUsed, ref isLastValidationSucceed, addingElement))
+            {
+                return new AddingPossible();
+            }
+
+            return new InvalidFormatUsed();
+        }
+
+        /// <summary>
+        /// The method provides result of operator </summary>
+        /// <param name="left"> A left side element. </param>
+        /// <param name="right"> A rightside element. </param>
+        /// <param name="result"> Calculation result. </param>
+        public void GetResult(double left, double right, out double result)
+        {
+            result = 0;
+            if (right == 0)
+            {
+                throw new DivideByZeroException();
+            }
+
+            result = left / right;
+        }
+    }
+
+    /// <summary>
+    /// A opening parenthesis operator </summary>
+    public class OpenBracket : InputElement, IUnaryOperator
+    {
+        public static string Operator = "(";
+        /// <summary>
+        /// A property provides element string.
+        /// This element string is using for validation and calculation. </summary>
+        public override string GetElement
+        {
+            get => Operator;
+        }
+
+        /// <summary>
+        /// A property provides displaying element string.
+        /// This displaying element is using for making formatted string. </summary>
+        public override string GetDisplayElement
+        {
+            get => "(";
+        }
+
+        /// <summary>
+        /// A operator priority </summary>
+        public int Priority
+        {
+            get => 1;
+        }
+
+        /// <summary>
+        /// A operator's operand type </summary>
+        /// <seealso cref="OperandType">
+        /// A operand type. </seealso>
+        public OperandType OperandType
+        {
+            get => OperandType.RIGHT;
+        }
+
+        /// <summary>
+        /// The method provides possibility of that is it possible adding addingElement after this InputElement.
+        /// This method can modify current expression by adding additional element or removing last element. </summary>
+        /// <param name="expressionElements"> Current expression, an InputElement list </param>
+        /// <param name="isEqualUsed"> A flag value whether equal key is pressed or not </param>
+        /// <param name="isLastValidationSucceed"> A flag value whether last calculation is succeed or not </param>
+        /// <param name="addingElement"> A InputElement will be added after this element. </param>
+        /// <returns> A status of adding element to exist expression </returns>
+        public override AddingElementResult CheckPossibilityAddingElement(ref List<InputElement> expressionElements,
+            ref bool isEqualUsed,
+            ref bool isLastValidationSucceed,
+            InputElement addingElement)
+        {
+            if (Operators.InsertingWork(ref expressionElements, ref isEqualUsed, ref isLastValidationSucceed, addingElement))
+            {
+                return new AddingPossible();
+            }
+
+            return new InvalidFormatUsed();
+        }
+
+        public override bool AlternativeWork(ref List<InputElement> expressionElements,
+            ref bool isEqualUsed,
+            ref bool isLastValidationSucceed)
+        {
+            if (GetNumberOfOpenedBracket(expressionElements) > 0)
+            {
+                return Operators.InsertingWork(ref expressionElements, ref isEqualUsed, ref isLastValidationSucceed, new CloseBracket());
+            }
+
+            return Operators.InsertingWork(ref expressionElements, ref isEqualUsed, ref isLastValidationSucceed, new OpenBracket());
+        }
+
+        /// <summary>
+        /// The method provides result of operator </summary>
+        /// <param name="left"> A left side element. </param>
+        /// <param name="right"> A right side element. </param>
+        /// <param name="result"> Calculation result. </param>
+        public void GetResult(double left, double right, out double result)
+        {
+            throw new Exception();
+        }
+
+        /// <summary>
+        /// Return a number of unclosed parenthesis </summary>
+        /// <param name="expressionElements"> An expression. </param>
+        /// <returns> A number of unclosed parenthesizes </returns>
+        private int GetNumberOfOpenedBracket(List<InputElement> expressionElements)
+        {
+            int res = 0;
+            foreach (var item in expressionElements)
+            {
+                if (item.CompareTo("(") == 0)
+                {
+                    res += 1;
+                }
+
+                else if (item.CompareTo(")") == 0)
+                {
+                    res -= 1;
+                }
+            }
+
+            return res;
+        }
+    }
+
+
+    /// <summary>
+    /// A closing parenthesis operator </summary>
+    public class CloseBracket : InputElement, IUnaryOperator
+    {
+        public static string Operator = ")";
+        /// <summary>
+        /// A property provides element string.
+        /// This element string is using for validation and calculation. </summary>
+        public override string GetElement
+        {
+            get => Operator;
+        }
+
+        /// <summary>
+        /// A property provides displaying element string.
+        /// This displaying element is using for making formatted string. </summary>
+        public override string GetDisplayElement
+        {
+            get => ")";
+        }
+
+        /// <summary>
+        /// A operator priority </summary>
+        public int Priority
+        {
+            get => 1;
+        }
+
+        /// <summary>
+        /// A operator's operand type </summary>
+        /// <seealso cref="OperandType">
+        /// A operand type. </seealso>
+        public OperandType OperandType
+        {
+            get => OperandType.LEFT;
+        }
+
+        /// <summary>
+        /// The method provides possibility of that is it possible adding addingElement after this InputElement.
+        /// This method can modify current expression by adding additional element or removing last element. </summary>
+        /// <param name="expressionElements"> Current expression, an InputElement list </param>
+        /// <param name="isEqualUsed"> A flag value whether equal key is pressed or not </param>
+        /// <param name="isLastValidationSucceed"> A flag value whether last calculation is succeed or not </param>
+        /// <param name="addingElement"> A InputElement will be added after this element. </param>
+        /// <returns> A status of adding element to exist expression </returns>
+        public override AddingElementResult CheckPossibilityAddingElement(ref List<InputElement> expressionElements,
+            ref bool isEqualUsed,
+            ref bool isLastValidationSucceed,
+            InputElement addingElement)
+        {
+            if (Operators.InsertingWork(ref expressionElements, ref isEqualUsed, ref isLastValidationSucceed, addingElement))
+            {
+                return new AddingPossible();
+            }
+
+            return new InvalidFormatUsed();
+        }
+
+        /// <summary>
+        /// The method provides result of operator </summary>
+        /// <param name="left"> A left side element. </param>
+        /// <param name="right"> A right side element. </param>
+        /// <param name="result"> Calculation result. </param>
+        public void GetResult(double left, double right, out double result)
+        {
+            throw new Exception();
+        }
+    }
+
+    /// <summary>
+    /// A point adding operator </summary>
+    public class Point : InputElement, IBinaryOperator
+    {
+        public static string Operator = ".";
+        /// <summary>
+        /// A property provides element string.
+        /// This element string is using for validation and calculation. </summary>
+        public override string GetElement
+        {
+            get => Operator;
+        }
+
+        /// <summary>
+        /// A property provides displaying element string.
+        /// This displaying element is using for making formatted string. </summary>
+        public override string GetDisplayElement
+        {
+            get => ".";
+        }
+
+        /// <summary>
+        /// A operator priority </summary>
+        public int Priority
+        {
+            get => 4;
+        }
+
+        /// <summary>
+        /// A operator's operand type </summary>
+        /// <seealso cref="OperandType">
+        /// A operand type. </seealso>
+        public OperandType OperandType
+        {
+            get => OperandType.BOTH;
+        }
+
+        /// <summary>
+        /// The method provides possibility of that is it possible adding addingElement after this InputElement.
+        /// This method can modify current expression by adding additional element or removing last element. </summary>
+        /// <param name="expressionElements"> Current expression, an InputElement list </param>
+        /// <param name="isEqualUsed"> A flag value whether equal key is pressed or not </param>
+        /// <param name="isLastValidationSucceed"> A flag value whether last calculation is succeed or not </param>
+        /// <param name="addingElement"> A InputElement will be added after this element. </param>
+        /// <returns> A status of adding element to exist expression </returns>
+        public override AddingElementResult CheckPossibilityAddingElement(ref List<InputElement> expressionElements,
+            ref bool isEqualUsed,
+            ref bool isLastValidationSucceed,
+            InputElement addingElement)
+        {
+            if (Operators.InsertingWork(ref expressionElements, ref isEqualUsed, ref isLastValidationSucceed, addingElement))
+            {
+                return new AddingPossible();
+            }
+
+            return new InvalidFormatUsed();
+        }
+
+        /// <summary>
+        /// The method provides result of operator </summary>
+        /// <param name="left"> A left side element. </param>
+        /// <param name="right"> A rightside element. </param>
+        /// <param name="result"> Calculation result. </param>
+        public void GetResult(double left, double right, out double result)
+        {
+            double decimalPlace = right;
+            while (decimalPlace >= 1)
+            {
+                decimalPlace = decimalPlace / 10;
+            }
+
+            if (left < 0)
+                result = left - decimalPlace;
+            else
+                result = left + decimalPlace;
+        }
+    }
+
+    /// <summary>
+    /// A reverse sign operator </summary>
+    public class Reverse : InputElement, IUnaryOperator
+    {
+        public static string Operator = "R";
+        /// <summary>
+        /// A property provides element string.
+        /// This element string is using for validation and calculation. </summary>
+        public override string GetElement
+        {
+            get => Operator;
+        }
+
+        /// <summary>
+        /// A property provides displaying element string.
+        /// This displaying element is using for making formatted string. </summary>
+        public override string GetDisplayElement
+        {
+            get => "-";
+        }
+
+        /// <summary>
+        /// A operator priority </summary>
+        public int Priority
+        {
+            get => 4;
+        }
+
+        /// <summary>
+        /// A operator's operand type </summary>
+        /// <seealso cref="OperandType">
+        /// A operand type. </seealso>
+        public OperandType OperandType
+        {
+            get => OperandType.RIGHT;
+        }
+
+        /// <summary>
+        /// The method provides possibility of that is it possible adding addingElement after this InputElement.
+        /// This method can modify current expression by adding additional element or removing last element. </summary>
+        /// <param name="expressionElements"> Current expression, an InputElement list </param>
+        /// <param name="isEqualUsed"> A flag value whether equal key is pressed or not </param>
+        /// <param name="isLastValidationSucceed"> A flag value whether last calculation is succeed or not </param>
+        /// <param name="addingElement"> A InputElement will be added after this element. </param>
+        /// <returns> A status of adding element to exist expression </returns>
+        public override AddingElementResult CheckPossibilityAddingElement(ref List<InputElement> expressionElements,
+            ref bool isEqualUsed,
+            ref bool isLastValidationSucceed,
+            InputElement addingElement)
+        {
+            if (Operators.InsertingWork(ref expressionElements, ref isEqualUsed, ref isLastValidationSucceed, addingElement))
+            {
+                return new AddingPossible();
+            }
+
+            return new InvalidFormatUsed();
+
+        }
+
+        /// <summary>
+        /// The method provides result of operator </summary>
+        /// <param name="left"> A left side element. </param>
+        /// <param name="right"> A rightside element. </param>
+        /// <param name="result"> Calculation result. </param>
+        public void GetResult(double left, double right, out double result)
+        {
+            result = left * -1;
+        }
+    }
+
+    
+}
+
diff --git a/Test/Calculator/Calculator/Renderers/ImageButtonRenderer.cs b/Test/Calculator/Calculator/Renderers/ImageButtonRenderer.cs
new file mode 100644 (file)
index 0000000..330db7c
--- /dev/null
@@ -0,0 +1,126 @@
+
+//Copyright 2018 Samsung Electronics Co., Ltd
+//
+//Licensed under the Apache License, Version 2.0 (the "License");
+//you may not use this file except in compliance with the License.
+//You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+//Unless required by applicable law or agreed to in writing, software
+//distributed under the License is distributed on an "AS IS" BASIS,
+//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//See the License for the specific language governing permissions and
+//limitations under the License.
+
+using ElmSharp;
+using System;
+using Xamarin.Forms;
+using Xamarin.Forms.Platform.Tizen;
+using TizenColor = ElmSharp.Color;
+using ImageButtonRenderer = Calculator.Renderers.ImageButtonRenderer;
+
+[assembly: ExportRenderer(typeof(Calculator.Controls.ImageButton), typeof(ImageButtonRenderer))]
+namespace Calculator.Renderers
+{
+    /// <summary>
+    /// Calculator command button custom renderer
+    /// Actually to implement command button, A image is used instead a button to display as a calculator button.
+    /// </summary>
+    /// <remarks>
+    /// Please refer to Xamarin.Forms Custom Renderer
+    /// https://developer.xamarin.com/guides/xamarin-forms/custom-renderer/
+    /// </remarks>
+    class ImageButtonRenderer : ImageRenderer
+    {
+
+        /// <summary>
+        /// Tizen's gesture recognizer for Tap gesture, Long Tap gesture, Line gesture and so on.
+        /// </summary>
+        private ElmSharp.GestureLayer GestureRecognizer;
+
+        /// <summary>
+        /// Resource directory path
+        /// </summary>
+        private readonly String ResourceDirectory = Program.AppResourcePath;
+
+        /// <summary>
+        /// Command button's color
+        /// </summary>
+        private static readonly TizenColor RegularColor = ElmSharp.Color.White;
+
+        /// <summary>
+        /// Command button's color if it is touched.
+        /// </summary>
+        private static readonly TizenColor PressedColor = new TizenColor(200, 200, 200);
+
+        /// <summary>
+        /// Register touch event callback for the Tap, the Long Tap and the Line behavior.
+        /// </summary>
+        /// <param name="args"> A Image element changed event's argument </param>
+        protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.Image> args)
+        {
+            base.OnElementChanged(args);
+
+            if (Control == null || Element == null)
+            {
+                return;
+            }
+
+            if (GestureRecognizer == null)
+            {
+                GestureRecognizer = new ElmSharp.GestureLayer(Control);
+                GestureRecognizer.Attach(Control);
+            }
+
+            if (args.NewElement == null)
+            {
+                GestureRecognizer.ClearCallbacks();
+                return;
+            }
+
+            Control.Color = RegularColor;
+
+            GestureRecognizer.SetTapCallback(GestureLayer.GestureType.Tap, GestureLayer.GestureState.Start, x => KeyDown() );
+            GestureRecognizer.SetTapCallback(GestureLayer.GestureType.Tap, GestureLayer.GestureState.End, x => ExecuteTapCommand() );
+            GestureRecognizer.SetTapCallback(GestureLayer.GestureType.LongTap, GestureLayer.GestureState.End, x => KeyUp() );
+            GestureRecognizer.SetTapCallback(GestureLayer.GestureType.LongTap, GestureLayer.GestureState.Abort, x => KeyUp() );
+            GestureRecognizer.SetLineCallback(GestureLayer.GestureState.Move, x => KeyUp() );
+        }
+
+        /// <summary>
+        /// Set button image's blending color.
+        /// It's right time after updating the button image source.
+        /// </summary>
+        protected override void UpdateAfterLoading(bool initialize)
+        {
+            base.UpdateAfterLoading(initialize);
+            Control.Color = RegularColor;
+        }
+
+        /// <summary>
+        /// Revert the button's color
+        /// </summary>
+        private void KeyUp()
+        {
+            Control.Color = RegularColor;
+        }
+
+        /// <summary>
+        /// A Action delegate which is restore button image as default
+        /// and execute button's Command with CommandParameter. </summary>
+        private void ExecuteTapCommand()
+        {
+            Calculator.Controls.ImageButton BtnCommand = Element as Calculator.Controls.ImageButton;
+            BtnCommand?.Command?.Execute(BtnCommand.CommandParameter);
+            KeyUp();
+        }
+
+        /// <summary>
+        /// A Action delegate which is restore button image as pressed situation. </summary>
+        private void KeyDown()
+        {
+            Control.Color = PressedColor;
+        }
+    }
+}
\ No newline at end of file
diff --git a/Test/Calculator/Calculator/ViewModels/MainPageViewModel.cs b/Test/Calculator/Calculator/ViewModels/MainPageViewModel.cs
new file mode 100644 (file)
index 0000000..bf53076
--- /dev/null
@@ -0,0 +1,353 @@
+
+//Copyright 2018 Samsung Electronics Co., Ltd
+//
+//Licensed under the Apache License, Version 2.0 (the "License");
+//you may not use this file except in compliance with the License.
+//You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+//Unless required by applicable law or agreed to in writing, software
+//distributed under the License is distributed on an "AS IS" BASIS,
+//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//See the License for the specific language governing permissions and
+//limitations under the License.
+
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Windows.Input;
+using Xamarin.Forms;
+
+using Calculator.Impl;
+using Calculator.Models;
+using System.Globalization;
+using System.Runtime.CompilerServices;
+
+namespace Calculator.ViewModels
+{
+    /// <summary>
+    /// A String to Color converter class.
+    /// </summary>
+    /// <remarks>
+    /// Please refer to Xamarin Custom Renderer
+    /// https://developer.xamarin.com/guides/xamarin-forms/custom-renderer/
+    /// </remarks>
+    public class StringToColorConverter : IValueConverter
+    {
+        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
+        {
+            return Color.FromHex(value.ToString());
+        }
+
+        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
+        {
+            return null;
+        }
+    }
+
+    /// <summary>
+    /// A Calculator ViewModel class which manages bindings and sending notifications.
+    /// </summary>
+    /// <seealso cref="Views.CalculatorMainPage">
+    public class MainPageViewModel : INotifyPropertyChanged
+    {
+        /// <summary>
+        /// Instance of MainPageViewModel which is wrapped in lazy<T> type.
+        /// </summary>
+        private static readonly Lazy<MainPageViewModel> lazy =
+                new Lazy<MainPageViewModel>(() => new MainPageViewModel());
+
+        /// <summary>
+        /// This property provides MainPageViewModel instance.
+        /// </summary>
+        public static MainPageViewModel Instance => lazy.Value;
+        
+        public event PropertyChangedEventHandler PropertyChanged;
+
+        /// <summary>
+        /// This property provides formatted expression text. 
+        /// </summary>
+        public FormattedString ExpressionText
+        {
+            get;
+            private set;
+        }
+
+        /// <summary>
+        /// A calculating result text.
+        /// </summary>
+        public FormattedString ResultText
+        {
+            get;
+            private set;
+        }
+
+        private static readonly String ResultRegularColor = "#7F000000";
+        private static readonly String ResultSoloColor = "#59C03A";
+
+        /// <summary>
+        /// Calculation result text color.
+        /// </summary>
+        public String ResultColor
+        {
+            get;
+            private set;
+        }
+        
+        /// <summary>
+        /// An element button's command 
+        /// </summary>
+        public ICommand PressButton { protected set; get; }
+        /// <summary>
+        /// A clear command button's command 
+        /// </summary>
+        public ICommand Clear { protected set; get; }
+        /// <summary>
+        /// A remove last button's command 
+        /// </summary>
+        public ICommand RemoveLast { protected set; get; }
+        /// <summary>
+        /// A = command button's command 
+        /// </summary>
+        public ICommand Calculate { protected set; get; }
+        /// <summary>
+        /// A +/- operator button's command 
+        /// </summary>
+        public ICommand Reverse { protected set; get; }
+
+        /// <summary>
+        /// MainPageViewModel constructor.
+        /// In this constructor, view initialization and commands bindings are completed. 
+        /// </summary>
+        private MainPageViewModel()
+        {
+            SetDisplayEmpty();
+
+            if (CalculatorApp.InputParserInstance.IsEmptyInputElements == false)
+            {
+                IEnumerable<InputElement> plainTexts = CalculatorApp.InputParserInstance.ExpressionElements;
+                FormattedString result;
+                FormattedString expression;
+                GetCalculatedResult(plainTexts, false, out expression, out result);
+                ResultText = result;
+
+                ExpressionText = expression;
+                UpdateDisplay();
+            }
+
+            this.PressButton = new Command((value) =>
+            {
+                string input = value.ToString();
+
+                IEnumerable<InputElement> plainTexts;
+                AddingElementResult res = CalculatorApp.InputParserInstance.GetSeparatedPlainText(input, out plainTexts);
+                if ((res is AddingPossible) == false)
+                {
+                    DisplayError(res.Message);
+                    return;
+                }
+
+                FormattedString result;
+                FormattedString expression;
+                GetCalculatedResult(plainTexts, false, out expression, out result);
+
+                ExpressionText = expression;
+                ResultText = result;
+                UpdateDisplay();
+            });
+
+            this.Clear = new Command(() =>
+            {
+                SetDisplayEmpty();
+                CalculatorApp.InputParserInstance.Clear();
+            });
+
+            this.RemoveLast = new Command(() =>
+            {
+                IEnumerable<InputElement> plainTexts;
+                if (CalculatorApp.InputParserInstance.DeleteLast(out plainTexts) == false)
+                {
+                    return;
+                }
+
+                FormattedString result;
+                FormattedString expression;
+                GetCalculatedResult(plainTexts, false, out expression, out result);
+
+                ExpressionText = expression;
+                ResultText = result;
+                UpdateDisplay();
+            });
+
+            this.Calculate = new Command(() =>
+            {
+                IEnumerable<InputElement> plainTexts;
+                if (CalculatorApp.InputParserInstance.Equal(out plainTexts) == false)
+                {
+                    return;
+                }
+
+                FormattedString result;
+                FormattedString expression;
+                if (GetEqualResult(plainTexts, out expression, out result) == false)
+                {
+                    return;
+                }
+
+                CalculatorApp.InputParserInstance.Set(CalculatorApp.CalculatorInstance.Result.ToString());
+                ResultText = result;
+
+                UpdateDisplay(true);
+            });
+
+            this.Reverse = new Command(() =>
+            {
+                IEnumerable<InputElement> plainTexts;
+                if (CalculatorApp.InputParserInstance.ReverseSign(out plainTexts) == false)
+                {
+                    DisplayError("Invalid format used.");
+                    return;
+                }
+
+                FormattedString result;
+                FormattedString expression;
+                GetCalculatedResult(plainTexts, false, out expression, out result);
+
+                ExpressionText = expression;
+                ResultText = result;
+                UpdateDisplay();
+            });
+        }
+
+        /// <summary>
+        /// The method provides calculated result and formatted expression for given expression. </summary>
+        /// <param name="inputExpression"> An expression which consist of InputElements with IEnumerable interface. </param>
+        /// <param name="isNeedCheckException"> Value indicates whether error displaying is needed. </param>
+        /// <param name="expression"> A formatted expression. </param>
+        /// <param name="result"> A formatted calculation result. </param>
+        /// <returns> A status of calculation </returns>
+        private bool GetCalculatedResult(IEnumerable<InputElement> inputExpression,
+            bool isNeedCheckException,
+            out FormattedString expression,
+            out FormattedString result)
+        {
+            expression = CalculatorApp.FormatterInstance.GetFormattedExpressionText(inputExpression);
+            result = string.Empty;
+
+            CalculationResult resCal = CalculatorApp.CalculatorInstance.SetExpression(inputExpression);
+            if ((resCal is CalculationSuccessful) == false)
+            {
+                if (isNeedCheckException)
+                {
+                    DisplayError(resCal.Message);
+                    return false;
+                }
+
+                return true;
+            }
+
+            result = CalculatorApp.FormatterInstance.GetFormattedOutputText(CalculatorApp.CalculatorInstance.Result.ToString());
+            return true;
+        }
+
+        /// <summary>
+        /// The method provides calculated result and formatted expression for given inputExpression. </summary>
+        /// <param name="inputExpression"> An expression which consist of InputElements with IEnumerable interface. </param>
+        /// <param name="expression"> A formatted expression. </param>
+        /// <param name="result"> A formatted calculation result. </param>
+        /// <returns> A result status of equal key execution </returns>
+        private bool GetEqualResult(IEnumerable<InputElement> inputExpression,
+            out FormattedString expression,
+            out FormattedString result)
+        {
+            expression = CalculatorApp.FormatterInstance.GetFormattedExpressionText(inputExpression);
+            result = string.Empty;
+
+            CalculationResult resCal = CalculatorApp.CalculatorInstance.Equal(inputExpression);
+            if ((resCal is CalculationSuccessful) == false)
+            {
+                DisplayError(resCal.Message);
+                return false;
+            }
+
+            result = CalculatorApp.FormatterInstance.GetFormattedOutputText(CalculatorApp.CalculatorInstance.Result.ToString());
+            return true;
+        }
+
+        /// <summary>
+        /// This method updates expression and result texts assuming calculation has not completed.
+        /// </summary>
+        private void UpdateDisplay()
+        {
+            UpdateDisplay(false);
+        }
+
+        /// <summary>
+        /// This method updates expression and result texts. 
+        /// </summary>
+        /// <param name="isCalculationCompleted"> Flag value indicating whether calculation has completed or not. </param>
+        private void UpdateDisplay(bool isCalculationCompleted)
+        {
+            UpdateResultTextColor(isCalculationCompleted);
+
+            OnPropertyChanged("ExpressionText");
+            OnPropertyChanged("ResultText");
+        }
+
+        /// <summary>
+        /// This method updates result text color. 
+        /// </summary>
+        /// <param name="isCalculationCompleted"> Flag value indicating whether calculation has completed or not. </param>
+        private void UpdateResultTextColor(bool isCalculationCompleted)
+        {
+            if (isCalculationCompleted)
+            {
+                if (ResultColor != ResultSoloColor)
+                {
+                    ResultColor = ResultSoloColor;
+                    OnPropertyChanged("ResultColor");
+                }
+            }
+            else
+            {
+                if (ResultColor != ResultRegularColor)
+                {
+                    ResultColor = ResultRegularColor;
+                    OnPropertyChanged("ResultColor");
+                }
+            }
+        }
+        
+
+        /// <summary>
+        /// This method clears Expression and result texts. 
+        /// </summary>
+        private void SetDisplayEmpty()
+        {
+            ExpressionText = string.Empty;
+            ResultText = string.Empty;
+            UpdateDisplay();
+        }
+
+        /// <summary>
+        /// This method displaying error message on the screen.
+        /// </summary>
+        /// <param name="message"> Message to be displayed </param>
+        private void DisplayError(String message)
+        {
+            if (message.Length > 0)
+            {
+                MessagingCenter.Send(this, "alert", message);
+            }
+        }
+
+        /// <summary>
+        /// The method is used to notify that property has changed. </summary>
+        /// <param name="propertyName"> A property name. </param>
+        protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
+        {
+            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
+        }
+    }
+}
diff --git a/Test/Calculator/Calculator/Views/CalculatorMainPage.xaml b/Test/Calculator/Calculator/Views/CalculatorMainPage.xaml
new file mode 100644 (file)
index 0000000..9b7fd15
--- /dev/null
@@ -0,0 +1,202 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
+             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
+             xmlns:local="clr-namespace:Calculator.ViewModels"
+             xmlns:control="clr-namespace:Calculator.Controls"
+             x:Class="Calculator.Views.CalculatorMainPage">
+    <ContentPage.Resources>
+        <ResourceDictionary>
+            <local:StringToColorConverter x:Key="StringToColorConverter"/>
+
+            <Style x:Key="font1" TargetType="Label" >
+                <Setter Property="FontFamily" Value="Samsung sans" />
+                <Setter Property="FontSize" Value="7" />
+                <Setter Property="HorizontalTextAlignment" Value="End" />
+                <Setter Property="VerticalTextAlignment" Value="Center" />
+            </Style>
+
+            <Style x:Key="inputString" TargetType="Label" BasedOn="{StaticResource font1}">
+                <Setter Property="LineBreakMode" Value="HeadTruncation" />
+            </Style>
+
+            <Style x:Key="sumString" TargetType="Label" BasedOn="{StaticResource font1}">
+                <Setter Property="LineBreakMode" Value="NoWrap" />
+            </Style>
+
+            <Style x:Key="alertString" TargetType="Label" >
+                <Setter Property="FontFamily" Value="Samsung sans" />
+                <Setter Property="FontSize" Value="6" />
+                <Setter Property="VerticalTextAlignment" Value="Center" />
+                <Setter Property="LineBreakMode" Value="WordWrap" />
+                <Setter Property="TextColor" Value="Black"/>
+                <Setter Property="HorizontalTextAlignment" Value="Center" />
+                <Setter Property="BackgroundColor" Value="#DDFFFFFF" />
+            </Style>
+
+        </ResourceDictionary>
+    </ContentPage.Resources>
+    
+    <ContentPage.Content>
+
+        <RelativeLayout>
+            <Grid RelativeLayout.XConstraint="{ConstraintExpression Type=RelativeToParent, Property=Width, Factor=0, Constant=0}"
+              RelativeLayout.YConstraint="{ConstraintExpression Type=RelativeToParent, Property=Height, Factor=0, Constant=0}"
+              RelativeLayout.WidthConstraint="{ConstraintExpression Type=RelativeToParent,Property=Width, Factor=1,Constant=0}"
+              RelativeLayout.HeightConstraint="{ConstraintExpression Type=RelativeToParent,Property=Height, Factor=1,Constant=0}"
+              HorizontalOptions="Fill"
+              VerticalOptions="Fill"
+              RowSpacing="1"
+              ColumnSpacing="1">
+
+                <Grid.RowDefinitions>
+                    <!-- First row is there to leave empty space on the top of the screen -->
+                    <RowDefinition Height="2*" />
+                    <RowDefinition Height="3*" />
+                    <RowDefinition Height="3*" />
+                    <RowDefinition Height="4*" />
+                    <RowDefinition Height="4*" />
+                    <RowDefinition Height="4*" />
+                    <RowDefinition Height="4*" />
+                    <RowDefinition Height="4*" />
+                    <RowDefinition Height="4*" />
+                </Grid.RowDefinitions>
+
+                <Grid.ColumnDefinitions>
+                    <ColumnDefinition Width="100*"/>
+                    <ColumnDefinition Width="100*"/>
+                    <ColumnDefinition Width="100*"/>
+                    <ColumnDefinition Width="100*"/>
+                    <ColumnDefinition Width="100*"/>
+                    <ColumnDefinition Width="100*"/>
+                    <ColumnDefinition Width="100*"/>
+                    <!-- Last column should be a little wider to avoid uneven spacing between columns -->
+                    <ColumnDefinition Width="101*"/>
+                </Grid.ColumnDefinitions>
+
+
+                <Label x:Name="ExpressionLabel" Grid.Row="1" Grid.Column="2" Grid.ColumnSpan="4"
+                       Style="{StaticResource inputString}"
+                       FormattedText="{Binding ExpressionText}"/>
+
+                <Label Grid.Row="2" Grid.Column="2" Grid.ColumnSpan="4" Style="{StaticResource sumString}"
+                           TextColor="{Binding ResultColor, Converter={StaticResource StringToColorConverter}}"
+                           FormattedText="{Binding ResultText}" />
+
+                <control:ImageButton Grid.Row="3" Grid.Column="0" Grid.ColumnSpan="2" 
+                                     Source="calculator_button_l_01.png"    
+                                     Command="{Binding Clear}"
+                                     BackgroundColor="HotPink"/>
+                <control:ImageButton Grid.Row="3" Grid.Column="2" Grid.ColumnSpan="2" 
+                                     Source="calculator_button_l_05.png"   
+                                     Command="{Binding PressButton}" 
+                                     CommandParameter="*"
+                                     BackgroundColor="HotPink"/>
+                <control:ImageButton Grid.Row="3" Grid.Column="4" Grid.ColumnSpan="2"
+                                     Source="calculator_button_l_04.png"   
+                                     Command="{Binding PressButton}" 
+                                     CommandParameter="/"
+                                     BackgroundColor="HotPink"/>
+                <control:ImageButton Grid.Row="3" Grid.Column="6" Grid.ColumnSpan="2" 
+                                     Source="btn_delete.png"    
+                                     Command="{Binding RemoveLast}"
+                                     BackgroundColor="HotPink"/>
+
+                <control:ImageButton Grid.Row="4" Grid.Column="0" Grid.ColumnSpan="2" 
+                                     Source="calculator_button_p_number_7.png"  
+                                     Command="{Binding PressButton}"
+                                     CommandParameter="7"
+                                     BackgroundColor="Gray" />
+                <control:ImageButton Grid.Row="4" Grid.Column="2" Grid.ColumnSpan="2" 
+                                     Source="calculator_button_p_number_8.png"  
+                                     Command="{Binding PressButton}"
+                                     CommandParameter="8"
+                                     BackgroundColor="Gray"/>
+                <control:ImageButton Grid.Row="4" Grid.Column="4" Grid.ColumnSpan="2" 
+                                     Source="calculator_button_p_number_9.png"  
+                                     Command="{Binding PressButton}"
+                                     CommandParameter="9"
+                                     BackgroundColor="Gray"/>
+                <control:ImageButton Grid.Row="4" Grid.Column="6" Grid.ColumnSpan="2" 
+                                     Source="calculator_button_l_07.png"  
+                                     Command="{Binding PressButton}"
+                                     CommandParameter="+"
+                                     BackgroundColor="HotPink"/>
+
+                <control:ImageButton Grid.Row="5" Grid.Column="0" Grid.ColumnSpan="2" 
+                                     Source="calculator_button_p_number_4.png"  
+                                     Command="{Binding PressButton}"
+                                     CommandParameter="4"
+                                     BackgroundColor="Gray"/>
+                <control:ImageButton Grid.Row="5" Grid.Column="2" Grid.ColumnSpan="2" 
+                                     Source="calculator_button_p_number_5.png"  
+                                     Command="{Binding PressButton}"
+                                     CommandParameter="5"
+                                     BackgroundColor="Gray"/>
+                <control:ImageButton Grid.Row="5" Grid.Column="4" Grid.ColumnSpan="2" 
+                                     Source="calculator_button_p_number_6.png"  
+                                     Command="{Binding PressButton}"
+                                     CommandParameter="6"
+                                     BackgroundColor="Gray"/>
+                <control:ImageButton Grid.Row="5" Grid.Column="6" Grid.ColumnSpan="2" 
+                                     Source="calculator_button_l_06.png"  
+                                     Command="{Binding PressButton}"
+                                     CommandParameter="-"
+                                     BackgroundColor="HotPink"/>
+
+                <control:ImageButton Grid.Row="6" Grid.Column="0" Grid.ColumnSpan="2" 
+                                     Source="calculator_button_p_number_1.png"  
+                                     Command="{Binding PressButton}"
+                                     CommandParameter="1"
+                                     BackgroundColor="Gray"/>
+                <control:ImageButton Grid.Row="6" Grid.Column="2" Grid.ColumnSpan="2" 
+                                     Source="calculator_button_p_number_2.png"  
+                                     Command="{Binding PressButton}"
+                                     CommandParameter="2"
+                                     BackgroundColor="Gray"/>
+                <control:ImageButton Grid.Row="6" Grid.Column="4" Grid.ColumnSpan="2" 
+                                     Source="calculator_button_p_number_3.png"  
+                                     Command="{Binding PressButton}"
+                                     CommandParameter="3"
+                                     BackgroundColor="Gray"/>
+                <control:ImageButton Grid.Row="6" Grid.Column="6" Grid.ColumnSpan="2" 
+                                     Source="calculator_button_l_02.png" 
+                                     Command="{Binding PressButton}"
+                                     CommandParameter="("
+                                     BackgroundColor="HotPink" />
+
+                <control:ImageButton Grid.Row="7" Grid.Column="0" Grid.ColumnSpan="3" 
+                                     Source="calculator_button_p_number_10.png"  
+                                     Command="{Binding PressButton}"
+                                     CommandParameter="."
+                                     BackgroundColor="Gray"/>
+                <control:ImageButton Grid.Row="7" Grid.Column="3" Grid.ColumnSpan="2" 
+                                     Source="calculator_button_p_number_0.png"  
+                                     Command="{Binding PressButton}"
+                                     CommandParameter="0"
+                                     BackgroundColor="Gray" />
+                <control:ImageButton Grid.Row="7" Grid.Column="5" Grid.ColumnSpan="3" 
+                                     Source="calculator_button_p_number_11.png" 
+                                     Command="{Binding Reverse}"
+                                     BackgroundColor="HotPink"/>
+
+                <control:ImageButton Grid.Row="8" Grid.Column="0" Grid.ColumnSpan="8" 
+                                     Source="calculator_button_l_08.png"    
+                                     Command="{Binding Calculate}"
+                                     BackgroundColor="DeepPink"/>
+            </Grid>
+            
+            <Label RelativeLayout.XConstraint="{ConstraintExpression Type=RelativeToParent, Property=Width, Factor=0, Constant=0}"
+                   RelativeLayout.YConstraint="{ConstraintExpression Type=RelativeToParent, Property=Height, Factor=0.16, Constant=0}"
+                   RelativeLayout.WidthConstraint="{ConstraintExpression Type=RelativeToParent,Property=Width, Factor=1,Constant=0}"
+                   RelativeLayout.HeightConstraint="{ConstraintExpression Type=RelativeToParent,Property=Height, Factor=0.1,Constant=0}"
+                   HorizontalOptions="CenterAndExpand"
+                   VerticalOptions="CenterAndExpand"
+                   x:Name="AlertToast"
+                   Style="{StaticResource alertString}"
+                   IsVisible="false"/>
+
+        </RelativeLayout>
+
+
+    </ContentPage.Content>
+</ContentPage>
\ No newline at end of file
diff --git a/Test/Calculator/Calculator/Views/CalculatorMainPage.xaml.cs b/Test/Calculator/Calculator/Views/CalculatorMainPage.xaml.cs
new file mode 100644 (file)
index 0000000..c8480ba
--- /dev/null
@@ -0,0 +1,65 @@
+
+//Copyright 2018 Samsung Electronics Co., Ltd
+//
+//Licensed under the Apache License, Version 2.0 (the "License");
+//you may not use this file except in compliance with the License.
+//You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+//Unless required by applicable law or agreed to in writing, software
+//distributed under the License is distributed on an "AS IS" BASIS,
+//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//See the License for the specific language governing permissions and
+//limitations under the License.
+
+using System.Threading;
+using System.Threading.Tasks;
+
+using Calculator.ViewModels;
+using Xamarin.Forms;
+using Xamarin.Forms.Xaml;
+
+namespace Calculator.Views
+{
+    [XamlCompilation(XamlCompilationOptions.Compile)]
+    public partial class CalculatorMainPage : ContentPage
+    {
+        private Mutex CounterMutex = new Mutex(false, "counter_mutex");
+        private int counter;
+
+        public CalculatorMainPage()
+        {
+            NavigationPage.SetHasNavigationBar(this, false);
+            InitializeComponent();
+            BindingContext = MainPageViewModel.Instance;
+
+            MessagingCenter.Subscribe<MainPageViewModel, string>(this, "alert", (sender, arg) =>
+            {
+                CounterMutex.WaitOne();
+                counter++;
+                CounterMutex.ReleaseMutex();
+
+                AlertToast.IsVisible = true;
+                AlertToast.Text = arg.ToString();
+                CloseAlertToast();
+            });
+        }
+
+        /// <summary>
+        /// This method closes alert toast after 1.5 seconds.
+        /// </summary>
+        async void CloseAlertToast()
+        {
+            await Task.Delay(1500);
+            CounterMutex.WaitOne();
+            if (--counter <= 0)
+            {
+                counter = 0;
+                AlertToast.IsVisible = false;
+            }
+
+            CounterMutex.ReleaseMutex();
+        }
+    }
+}
\ No newline at end of file
diff --git a/Test/Calculator/Calculator/res/btn_delete.png b/Test/Calculator/Calculator/res/btn_delete.png
new file mode 100644 (file)
index 0000000..a25ebfa
Binary files /dev/null and b/Test/Calculator/Calculator/res/btn_delete.png differ
diff --git a/Test/Calculator/Calculator/res/calculator_button_l_01.png b/Test/Calculator/Calculator/res/calculator_button_l_01.png
new file mode 100644 (file)
index 0000000..a634528
Binary files /dev/null and b/Test/Calculator/Calculator/res/calculator_button_l_01.png differ
diff --git a/Test/Calculator/Calculator/res/calculator_button_l_02.png b/Test/Calculator/Calculator/res/calculator_button_l_02.png
new file mode 100644 (file)
index 0000000..df740ee
Binary files /dev/null and b/Test/Calculator/Calculator/res/calculator_button_l_02.png differ
diff --git a/Test/Calculator/Calculator/res/calculator_button_l_03.png b/Test/Calculator/Calculator/res/calculator_button_l_03.png
new file mode 100644 (file)
index 0000000..c56764f
Binary files /dev/null and b/Test/Calculator/Calculator/res/calculator_button_l_03.png differ
diff --git a/Test/Calculator/Calculator/res/calculator_button_l_04.png b/Test/Calculator/Calculator/res/calculator_button_l_04.png
new file mode 100644 (file)
index 0000000..be4a25c
Binary files /dev/null and b/Test/Calculator/Calculator/res/calculator_button_l_04.png differ
diff --git a/Test/Calculator/Calculator/res/calculator_button_l_05.png b/Test/Calculator/Calculator/res/calculator_button_l_05.png
new file mode 100644 (file)
index 0000000..a013c82
Binary files /dev/null and b/Test/Calculator/Calculator/res/calculator_button_l_05.png differ
diff --git a/Test/Calculator/Calculator/res/calculator_button_l_06.png b/Test/Calculator/Calculator/res/calculator_button_l_06.png
new file mode 100644 (file)
index 0000000..45b3aea
Binary files /dev/null and b/Test/Calculator/Calculator/res/calculator_button_l_06.png differ
diff --git a/Test/Calculator/Calculator/res/calculator_button_l_07.png b/Test/Calculator/Calculator/res/calculator_button_l_07.png
new file mode 100644 (file)
index 0000000..cec682d
Binary files /dev/null and b/Test/Calculator/Calculator/res/calculator_button_l_07.png differ
diff --git a/Test/Calculator/Calculator/res/calculator_button_l_08.png b/Test/Calculator/Calculator/res/calculator_button_l_08.png
new file mode 100644 (file)
index 0000000..f895b67
Binary files /dev/null and b/Test/Calculator/Calculator/res/calculator_button_l_08.png differ
diff --git a/Test/Calculator/Calculator/res/calculator_button_p_number_0.png b/Test/Calculator/Calculator/res/calculator_button_p_number_0.png
new file mode 100644 (file)
index 0000000..beccbb5
Binary files /dev/null and b/Test/Calculator/Calculator/res/calculator_button_p_number_0.png differ
diff --git a/Test/Calculator/Calculator/res/calculator_button_p_number_1.png b/Test/Calculator/Calculator/res/calculator_button_p_number_1.png
new file mode 100644 (file)
index 0000000..4ab519c
Binary files /dev/null and b/Test/Calculator/Calculator/res/calculator_button_p_number_1.png differ
diff --git a/Test/Calculator/Calculator/res/calculator_button_p_number_10.png b/Test/Calculator/Calculator/res/calculator_button_p_number_10.png
new file mode 100644 (file)
index 0000000..edc5cff
Binary files /dev/null and b/Test/Calculator/Calculator/res/calculator_button_p_number_10.png differ
diff --git a/Test/Calculator/Calculator/res/calculator_button_p_number_11.png b/Test/Calculator/Calculator/res/calculator_button_p_number_11.png
new file mode 100644 (file)
index 0000000..ad28db9
Binary files /dev/null and b/Test/Calculator/Calculator/res/calculator_button_p_number_11.png differ
diff --git a/Test/Calculator/Calculator/res/calculator_button_p_number_2.png b/Test/Calculator/Calculator/res/calculator_button_p_number_2.png
new file mode 100644 (file)
index 0000000..8d8bf41
Binary files /dev/null and b/Test/Calculator/Calculator/res/calculator_button_p_number_2.png differ
diff --git a/Test/Calculator/Calculator/res/calculator_button_p_number_3.png b/Test/Calculator/Calculator/res/calculator_button_p_number_3.png
new file mode 100644 (file)
index 0000000..e4a149c
Binary files /dev/null and b/Test/Calculator/Calculator/res/calculator_button_p_number_3.png differ
diff --git a/Test/Calculator/Calculator/res/calculator_button_p_number_4.png b/Test/Calculator/Calculator/res/calculator_button_p_number_4.png
new file mode 100644 (file)
index 0000000..14e42d0
Binary files /dev/null and b/Test/Calculator/Calculator/res/calculator_button_p_number_4.png differ
diff --git a/Test/Calculator/Calculator/res/calculator_button_p_number_5.png b/Test/Calculator/Calculator/res/calculator_button_p_number_5.png
new file mode 100644 (file)
index 0000000..ad283c7
Binary files /dev/null and b/Test/Calculator/Calculator/res/calculator_button_p_number_5.png differ
diff --git a/Test/Calculator/Calculator/res/calculator_button_p_number_6.png b/Test/Calculator/Calculator/res/calculator_button_p_number_6.png
new file mode 100644 (file)
index 0000000..0dd9caa
Binary files /dev/null and b/Test/Calculator/Calculator/res/calculator_button_p_number_6.png differ
diff --git a/Test/Calculator/Calculator/res/calculator_button_p_number_7.png b/Test/Calculator/Calculator/res/calculator_button_p_number_7.png
new file mode 100644 (file)
index 0000000..721c907
Binary files /dev/null and b/Test/Calculator/Calculator/res/calculator_button_p_number_7.png differ
diff --git a/Test/Calculator/Calculator/res/calculator_button_p_number_8.png b/Test/Calculator/Calculator/res/calculator_button_p_number_8.png
new file mode 100644 (file)
index 0000000..80d9a32
Binary files /dev/null and b/Test/Calculator/Calculator/res/calculator_button_p_number_8.png differ
diff --git a/Test/Calculator/Calculator/res/calculator_button_p_number_9.png b/Test/Calculator/Calculator/res/calculator_button_p_number_9.png
new file mode 100644 (file)
index 0000000..56ef6a5
Binary files /dev/null and b/Test/Calculator/Calculator/res/calculator_button_p_number_9.png differ
diff --git a/Test/Calculator/Calculator/shared/res/Calculator.png b/Test/Calculator/Calculator/shared/res/Calculator.png
new file mode 100644 (file)
index 0000000..9f3cb98
Binary files /dev/null and b/Test/Calculator/Calculator/shared/res/Calculator.png differ
diff --git a/Test/Calculator/Calculator/tizen-manifest.xml b/Test/Calculator/Calculator/tizen-manifest.xml
new file mode 100644 (file)
index 0000000..c959765
--- /dev/null
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns="http://tizen.org/ns/packages" api-version="4" package="org.tizen.example.Calculator" version="1.0.0">
+       <profile name="wearable" />
+       <ui-application appid="org.tizen.example.Calculator"
+                                       exec="Calculator.dll"
+                                       type="dotnet"
+                                       multiple="false"
+                                       taskmanage="true"
+                                       nodisplay="false"
+                                       launch_mode="single">
+  <label>Calculator</label>
+       <icon>Calculator.png</icon>
+        <metadata key="http://tizen.org/metadata/prefer_dotnet_aot" value="true" />
+       </ui-application>
+</manifest>
diff --git a/XSF.sln b/XSF.sln
index 35410598fd7a7ba8f044fc70fbc328c04265d458..20d9a213d12558c3239527f29ee995c1b5f2775b 100755 (executable)
--- a/XSF.sln
+++ b/XSF.sln
@@ -45,6 +45,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Weather", "Weather", "{F167
 EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Weather", "Test\Weather\Weather\Weather.csproj", "{076A3B6E-64FE-422C-9D54-845BA6036DF7}"
 EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Calculator", "Calculator", "{43929EEC-22EC-47D3-A4BC-3CD3C3A725A0}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Calculator", "Test\Calculator\Calculator\Calculator.csproj", "{54404384-2239-4646-9C58-49AB9DDC89FE}"
+EndProject
 Global
        GlobalSection(SolutionConfigurationPlatforms) = preSolution
                Debug|Any CPU = Debug|Any CPU
@@ -91,6 +95,14 @@ Global
                {6DADDF43-87F3-43C6-822D-12DE155CCF86}.Debug|Any CPU.Build.0 = Debug|Any CPU
                {6DADDF43-87F3-43C6-822D-12DE155CCF86}.Release|Any CPU.ActiveCfg = Release|Any CPU
                {6DADDF43-87F3-43C6-822D-12DE155CCF86}.Release|Any CPU.Build.0 = Release|Any CPU
+               {076A3B6E-64FE-422C-9D54-845BA6036DF7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+               {076A3B6E-64FE-422C-9D54-845BA6036DF7}.Debug|Any CPU.Build.0 = Debug|Any CPU
+               {076A3B6E-64FE-422C-9D54-845BA6036DF7}.Release|Any CPU.ActiveCfg = Release|Any CPU
+               {076A3B6E-64FE-422C-9D54-845BA6036DF7}.Release|Any CPU.Build.0 = Release|Any CPU
+               {54404384-2239-4646-9C58-49AB9DDC89FE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+               {54404384-2239-4646-9C58-49AB9DDC89FE}.Debug|Any CPU.Build.0 = Debug|Any CPU
+               {54404384-2239-4646-9C58-49AB9DDC89FE}.Release|Any CPU.ActiveCfg = Release|Any CPU
+               {54404384-2239-4646-9C58-49AB9DDC89FE}.Release|Any CPU.Build.0 = Release|Any CPU
        EndGlobalSection
        GlobalSection(SolutionProperties) = preSolution
                HideSolutionNode = FALSE
@@ -109,6 +121,10 @@ Global
                {4653BFED-31B5-412F-8076-A609A4E5D851} = {232D191B-486D-4EC3-BCB2-F776124AF705}
                {E1BF76E2-0454-490C-964A-587E7926CA13} = {087187F9-A361-4269-88EB-47A44185FA7F}
                {6DADDF43-87F3-43C6-822D-12DE155CCF86} = {E1BF76E2-0454-490C-964A-587E7926CA13}
+               {F167380D-C156-45D1-A0BA-DB3A5AE34E98} = {087187F9-A361-4269-88EB-47A44185FA7F}
+               {076A3B6E-64FE-422C-9D54-845BA6036DF7} = {F167380D-C156-45D1-A0BA-DB3A5AE34E98}
+               {43929EEC-22EC-47D3-A4BC-3CD3C3A725A0} = {087187F9-A361-4269-88EB-47A44185FA7F}
+               {54404384-2239-4646-9C58-49AB9DDC89FE} = {43929EEC-22EC-47D3-A4BC-3CD3C3A725A0}
        EndGlobalSection
        GlobalSection(ExtensibilityGlobals) = postSolution
                SolutionGuid = {81158F7F-D003-4C6D-9937-5002C54D57EA}