You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
187 lines
6.5 KiB
187 lines
6.5 KiB
using NCalc; |
|
using System; |
|
using System.Collections.Generic; |
|
using System.Linq; |
|
using System.Text; |
|
using FormsKey = System.Windows.Forms.Keys; |
|
|
|
namespace Calculator |
|
{ |
|
public class Calc |
|
{ |
|
private const int Precision = 3; |
|
private readonly List<CalculationElement> calculation; |
|
private bool FirstKeyPressed = true; |
|
|
|
public Calc() |
|
{ |
|
calculation = new List<CalculationElement>(); |
|
} |
|
|
|
public CalculationResponse KeyPressed(FormsKey key) |
|
{ |
|
switch (key) |
|
{ |
|
case FormsKey.Enter: |
|
return Calculate(); |
|
|
|
case FormsKey.Delete: |
|
return Delete(); |
|
|
|
case FormsKey.NumPad0: |
|
return AddCalculationElement(new NumberElement(0)); |
|
|
|
case FormsKey.NumPad1: |
|
return AddCalculationElement(new NumberElement(1)); |
|
|
|
case FormsKey.NumPad2: |
|
return AddCalculationElement(new NumberElement(2)); |
|
|
|
case FormsKey.NumPad3: |
|
return AddCalculationElement(new NumberElement(3)); |
|
|
|
case FormsKey.NumPad4: |
|
return AddCalculationElement(new NumberElement(4)); |
|
|
|
case FormsKey.NumPad5: |
|
return AddCalculationElement(new NumberElement(5)); |
|
|
|
case FormsKey.NumPad6: |
|
return AddCalculationElement(new NumberElement(6)); |
|
|
|
case FormsKey.NumPad7: |
|
return AddCalculationElement(new NumberElement(7)); |
|
|
|
case FormsKey.NumPad8: |
|
return AddCalculationElement(new NumberElement(8)); |
|
|
|
case FormsKey.NumPad9: |
|
return AddCalculationElement(new NumberElement(9)); |
|
|
|
case FormsKey.Add: |
|
return AddCalculationElement(new OperationElement(Operation.Add)); |
|
|
|
case FormsKey.Subtract: |
|
return AddCalculationElement(new OperationElement(Operation.Subtract)); |
|
|
|
case FormsKey.Multiply: |
|
return AddCalculationElement(new OperationElement(Operation.Muliply)); |
|
|
|
case FormsKey.Divide: |
|
return AddCalculationElement(new OperationElement(Operation.Divide)); |
|
|
|
case FormsKey.Decimal: |
|
return AddCalculationElement(new DecimalElement()); |
|
|
|
default: |
|
return CalculationResponse.WrongInput; |
|
} |
|
} |
|
|
|
private CalculationResponse Delete() |
|
{ |
|
calculation.Clear(); |
|
return CalculationResponse.ClearedMemory; |
|
} |
|
|
|
private bool CheckIfOperationIsAllowed(CalculationElement element) |
|
{ |
|
if (calculation.Count == 0 && (element as OperationElement).Operation != Operation.Subtract) |
|
return false; |
|
if (calculation.LastOrDefault() is OperationElement) |
|
return false; |
|
return true; |
|
} |
|
|
|
private bool CheckIfNumberIsAlreadyDecimal() |
|
{ |
|
bool decimalFound = false; |
|
foreach (CalculationElement item in calculation) |
|
{ |
|
if (decimalFound) |
|
{ |
|
if (item is OperationElement) |
|
decimalFound = false; |
|
} |
|
else |
|
if (item is DecimalElement) |
|
decimalFound = true; |
|
} |
|
return decimalFound; |
|
} |
|
|
|
private bool CheckIfDecimalIsAllowed() |
|
{ |
|
if (FirstKeyPressed) |
|
{ |
|
calculation.Clear(); |
|
FirstKeyPressed = false; |
|
calculation.Add(new NumberElement(0)); |
|
return true; |
|
} |
|
CalculationElement last = calculation.LastOrDefault(); |
|
if (last is DecimalElement) |
|
return false; |
|
else if (last is NumberElement) |
|
{ //check if another decimal exists before we encounter an OperationElement |
|
if (CheckIfNumberIsAlreadyDecimal()) return false; |
|
} |
|
else if (last == null || last is OperationElement) |
|
calculation.Add(new NumberElement(0)); |
|
return true; |
|
} |
|
|
|
private CalculationResponse AddCalculationElement(CalculationElement element) |
|
{ |
|
if (element is OperationElement) |
|
if (!CheckIfOperationIsAllowed(element)) |
|
return CalculationResponse.WrongInput; |
|
if (element is DecimalElement) |
|
if (!CheckIfDecimalIsAllowed()) |
|
return CalculationResponse.WrongInput; |
|
if (element is NumberElement && FirstKeyPressed) |
|
calculation.Clear(); |
|
FirstKeyPressed = false; |
|
calculation.Add(element); |
|
return CalculationResponse.Ok; |
|
} |
|
|
|
private CalculationResponse Calculate() |
|
{ |
|
if (calculation.Count == 0) return new CalculationResponse(Response.Result, "0"); |
|
StringBuilder calcString = new StringBuilder(); |
|
calculation.ForEach(element => calcString.Append(element.ToString())); |
|
Expression e = new Expression(calcString.ToString().TrimEnd('.', '/', '*', '-', '+')); |
|
double solution = Convert.ToDouble(e.Evaluate()); |
|
ClearCalculation(); |
|
string result = solution.ToString(string.Format("F{0}", Precision)); //Region Specific!! |
|
result = result.TrimEnd('0', ','); |
|
AddResultToCalculation(result); |
|
return new CalculationResponse(Response.Result, result); |
|
} |
|
|
|
private void ClearCalculation() |
|
{ |
|
calculation.Clear(); |
|
FirstKeyPressed = true; |
|
} |
|
|
|
private string DecimalsZero() |
|
{ |
|
return ',' + new string('0', Precision); |
|
} |
|
|
|
private void AddResultToCalculation(string result) |
|
{ |
|
for (int i = 0; i < result.Length; i++) |
|
{ |
|
if (result[i] == ',') |
|
calculation.Add(new DecimalElement()); |
|
else if (result[i] == '-') |
|
calculation.Add(new OperationElement(Operation.Subtract)); |
|
else |
|
calculation.Add(new NumberElement((byte)char.GetNumericValue(result[i]))); |
|
} |
|
} |
|
} |
|
} |