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

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])));
}
}
}
}