diff --git a/Calculator.ShPet1304/Calculator.slnx b/Calculator.ShPet1304/Calculator.slnx
new file mode 100644
index 00000000..93365242
--- /dev/null
+++ b/Calculator.ShPet1304/Calculator.slnx
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/Calculator.ShPet1304/Calculator/Calculator.csproj b/Calculator.ShPet1304/Calculator/Calculator.csproj
new file mode 100644
index 00000000..2d7613dc
--- /dev/null
+++ b/Calculator.ShPet1304/Calculator/Calculator.csproj
@@ -0,0 +1,18 @@
+
+
+
+ Exe
+ net10.0
+ enable
+ enable
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Calculator.ShPet1304/Calculator/CalculatorFunctions.cs b/Calculator.ShPet1304/Calculator/CalculatorFunctions.cs
new file mode 100644
index 00000000..4738dca6
--- /dev/null
+++ b/Calculator.ShPet1304/Calculator/CalculatorFunctions.cs
@@ -0,0 +1,116 @@
+using CalculatorLibrary;
+using CalculatorMenu;
+using Spectre.Console;
+
+
+namespace CalculatorProgram
+{
+ public class CalculatorFunctions
+ {
+ public bool reusedResult = false;
+ public double reusedNumber = 0;
+
+ public void Function()
+ {
+ bool endApp = false;
+
+ Console.WriteLine("Console Calculator in C#\r");
+ Console.WriteLine("------------------------\n");
+
+ CalculatorLibrary.Calculator calculator = Calculator.Instance;
+
+ while (!endApp)
+ {
+ string? numInput1 = "";
+ string? numInput2 = "";
+ double result = 0;
+ double cleanNum1 = 0;
+ double cleanNum2 = 0;
+
+ var menu = new Menu();
+ string op = menu.ShowOperationsMenu();
+
+ if (op == "Square Root" || op == "10x" || op == "Trigonometric function (sin)" || op == "Trigonometric function (cos)" || op == "Trigonometric function (tan)")
+ {
+ if (cleanNum1 == 0 && !reusedResult)
+ {
+ Console.Write("Type a number, and then press Enter: ");
+ numInput1 = Console.ReadLine();
+
+ while (!double.TryParse(numInput1, out cleanNum1))
+ {
+ Console.Write("This is not valid input. Please enter a numeric value: ");
+ numInput1 = Console.ReadLine();
+ }
+ ;
+ }
+ else if (reusedResult)
+ {
+ cleanNum1 = reusedNumber;
+ reusedResult = false;
+ Console.WriteLine("Reusing the previous result: {0}\n", cleanNum1);
+ }
+ try
+ {
+ result = calculator.DoOperation(cleanNum1, 0, op);
+ if (double.IsNaN(result))
+ {
+ Console.WriteLine("This operation will result in a mathematical error.\n");
+ }
+ else
+ Console.WriteLine("Your result: {0:0.##}\n", result);
+ }
+ catch (Exception e)
+ {
+ Console.WriteLine("Oh no! An exception occurred trying to do the math.\n - Details: " + e.Message);
+ }
+ }
+ else if (cleanNum1 == 0 && !reusedResult)
+ {
+ Console.Write("Type a number, and then press Enter: ");
+ numInput1 = Console.ReadLine();
+ while (!double.TryParse(numInput1, out cleanNum1))
+ {
+ Console.Write("This is not valid input. Please enter a numeric value: ");
+ numInput1 = Console.ReadLine();
+ }
+ }
+
+ else if (reusedResult)
+ {
+ cleanNum1 = reusedNumber;
+ reusedResult = false;
+ Console.WriteLine("Reusing the previous result: {0}\n", cleanNum1);
+ }
+ Console.Write("Type another number, and then press Enter: ");
+ numInput2 = Console.ReadLine();
+
+ while (!double.TryParse(numInput2, out cleanNum2))
+ {
+ Console.Write("This is not valid input. Please enter a numeric value: ");
+ numInput2 = Console.ReadLine();
+ }
+ try
+ {
+ result = calculator.DoOperation(cleanNum1, cleanNum2, op);
+ if (double.IsNaN(result))
+ {
+ Console.WriteLine("This operation will result in a mathematical error.\n");
+ }
+ else Console.WriteLine("Your result: {0:0.##}\n", result);
+ }
+ catch (Exception e)
+ {
+ Console.WriteLine("Oh no! An exception occurred trying to do the math.\n - Details: " + e.Message);
+ }
+ Console.WriteLine("------------------------\n");
+ AnsiConsole.MarkupLine("\nPress [grey]Enter[/] to return to menu...");
+ Console.ReadKey();
+ break;
+ }
+ }
+ }
+}
+
+
+
diff --git a/Calculator.ShPet1304/Calculator/Menu.cs b/Calculator.ShPet1304/Calculator/Menu.cs
new file mode 100644
index 00000000..baf36524
--- /dev/null
+++ b/Calculator.ShPet1304/Calculator/Menu.cs
@@ -0,0 +1,63 @@
+using CalculatorLibrary;
+using CalculatorProgram;
+using Spectre.Console;
+
+namespace CalculatorMenu
+{
+ public class Menu
+ {
+ private static Calculator calcLib = Calculator.Instance;
+ private static CalculatorFunctions func = new CalculatorFunctions();
+
+ public string ShowMainMenu()
+ {
+ AnsiConsole.Clear();
+ AnsiConsole.Write(
+ new FigletText("Calculator")
+ .Color(Color.Blue));
+
+ var choice = AnsiConsole.Prompt(
+ new SelectionPrompt()
+ .Title("[green]What would you like to do[/]?")
+ .PageSize(10)
+ .MoreChoicesText("[grey](Move up and down to reveal more options)[/]")
+ .AddChoices(new[] {
+ "New Calculation", "View Result History", "Use Previous Result", "View Calculator Usage Count", "Clear History", "Exit"
+ }));
+ return choice;
+ }
+
+ public string ShowOperationsMenu()
+ {
+ AnsiConsole.Clear();
+ var op = AnsiConsole.Prompt(
+ new SelectionPrompt()
+ .Title("[green]What would you like to do[/]?")
+ .PageSize(10)
+ .MoreChoicesText("[grey](Move up and down to reveal more options)[/]")
+ .AddChoices(new[] {
+ "addition", "subtraction","multiplication", "division", "Square Root", "Taking the power", "10x", "Trigonometric function (sin)", "Trigonometric function (cos)", "Trigonometric function (tan)"
+ }));
+ return op;
+ }
+
+ public void ShowHistoryMenu()
+ {
+ AnsiConsole.Clear();
+ List options = calcLib.PreviousResult();
+ if (options.Count == 0)
+ {
+ AnsiConsole.MarkupLine("[red]No history found.[/]");
+ return;
+ }
+ double selectedNum = AnsiConsole.Prompt(
+ new SelectionPrompt()
+ .Title("Select a [green]previous result[/]:")
+ .AddChoices(options)
+ );
+ func.reusedNumber = selectedNum;
+ func.reusedResult = true;
+ func.Function();
+ }
+ }
+}
\ No newline at end of file
diff --git a/Calculator.ShPet1304/Calculator/Program.cs b/Calculator.ShPet1304/Calculator/Program.cs
new file mode 100644
index 00000000..a3b8b592
--- /dev/null
+++ b/Calculator.ShPet1304/Calculator/Program.cs
@@ -0,0 +1,56 @@
+using CalculatorLibrary;
+using CalculatorMenu;
+
+
+namespace CalculatorProgram
+{
+ public class Program
+ {
+ private static Calculator calcLib = Calculator.Instance;
+ private static CalculatorFunctions calculatorFunctions = new CalculatorFunctions();
+
+ public static void Main(string[] args)
+ {
+ Programme();
+ }
+
+ static void Programme()
+ {
+ var menu = new Menu();
+ bool running = true;
+
+ while (running)
+ {
+ string selected = menu.ShowMainMenu();
+
+ switch (selected)
+ {
+ case "New Calculation":
+ calculatorFunctions.Function();
+ break;
+
+ case "View Result History":
+ calcLib.GetLastResult();
+ break;
+
+ case "Use Previous Result":
+ menu.ShowHistoryMenu();
+ break;
+
+ case "View Calculator Usage Count":
+ calcLib.GetUsageCount();
+ break;
+
+ case "Clear History":
+ calcLib.ClearHistory();
+ break;
+
+ case "Exit":
+ calcLib.Finish();
+ running = false;
+ break;
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Calculator.ShPet1304/CalculatorLibrary/CalculatorLibrary.cs b/Calculator.ShPet1304/CalculatorLibrary/CalculatorLibrary.cs
new file mode 100644
index 00000000..100a95a1
--- /dev/null
+++ b/Calculator.ShPet1304/CalculatorLibrary/CalculatorLibrary.cs
@@ -0,0 +1,206 @@
+using Newtonsoft.Json;
+
+namespace CalculatorLibrary
+{
+ public class Calculator
+ {
+ private static Calculator? _instance;
+ private static List<(double num1, double num2, double result)> history = new();
+ private JsonWriter writer;
+ private StreamWriter logFile;
+
+ public static Calculator Instance
+ {
+ get
+ {
+ _instance ??= new Calculator();
+ return _instance;
+ }
+ }
+
+ private Calculator()
+ {
+ logFile = File.CreateText("calculatorlog.json");
+ logFile.AutoFlush = true;
+ writer = new JsonTextWriter(logFile);
+ writer.Formatting = Formatting.Indented;
+ writer.WriteStartObject();
+ writer.WritePropertyName("Operations");
+ writer.WriteStartArray();
+ }
+
+ public double DoOperation(double num1 = 0, double num2 = 0, string op = "")
+ {
+ double result = double.NaN;
+
+ writer.WriteStartObject();
+ writer.WritePropertyName("Operand1");
+ writer.WriteValue(num1);
+ writer.WritePropertyName("Operand2");
+ writer.WriteValue(num2);
+ writer.WritePropertyName("Operation");
+
+ switch (op)
+ {
+ case "addition":
+ result = num1 + num2;
+ writer.WriteValue("Add");
+ history.Add(((double)num1, (double)num2, (double)result));
+ break;
+
+ case "subtraction":
+ result = num1 - num2;
+ writer.WriteValue("Subtract");
+ history.Add(((double)num1, (double)num2, (double)result));
+ break;
+
+ case "multiplication":
+ result = num1 * num2;
+ writer.WriteValue("Multiply");
+ history.Add(((double)num1, (double)num2, (double)result));
+ break;
+
+ case "division":
+ if (num2 != 0)
+ {
+ result = num1 / num2;
+ }
+ writer.WriteValue("Divide");
+ history.Add(((double)num1, (double)num2, (double)result));
+ break;
+
+ case "Square Root":
+ result = Math.Sqrt(num1);
+ writer.WriteValue("Square Root");
+ history.Add(((double)num1, (double)num2, (double)result));
+ break;
+
+ case "Taking the power":
+ result = Math.Pow(num1, num2);
+ writer.WriteValue("Taking the power");
+ history.Add(((double)num1, (double)num2, (double)result));
+ break;
+
+ case "10x":
+ result = Math.Pow(10, num1);
+ writer.WriteValue("10x");
+ history.Add(((double)num1, (double)num2, (double)result));
+
+ break;
+
+ case "Trigonometric function (sin)":
+ double radians = num1 * (Math.PI / 180);
+ result = Math.Sin(radians);
+ writer.WriteValue("Sine");
+ history.Add(((double)num1, (double)num2, (double)result));
+ break;
+
+ case "Trigonometric function (cos)":
+ double radiansCos = num1 * (Math.PI / 180);
+ result = Math.Cos(radiansCos);
+ writer.WriteValue("Cosine");
+ history.Add(((double)num1, (double)num2, (double)result));
+ break;
+
+ case "Trigonometric function (tan)":
+ double radiansTan = num1 * (Math.PI / 180);
+ result = Math.Tan(radiansTan);
+ writer.WriteValue("Tangent");
+ history.Add(((double)num1, (double)num2, (double)result));
+ break;
+
+ default:
+ break;
+ }
+ writer.WritePropertyName("Result");
+ writer.WriteValue(result);
+ writer.WriteEndObject();
+
+ return result;
+ }
+
+
+ public void Finish()
+ {
+ writer.WriteEndArray();
+ writer.WriteEndObject();
+ writer.Close();
+ }
+
+ public void GetLastResult()
+ {
+ if (history == null || history.Count == 0)
+ {
+ Console.WriteLine("No history found.");
+ }
+ else
+ {
+ foreach (var entry in history)
+ {
+ Console.WriteLine($"{entry.result}");
+ }
+ }
+ Console.WriteLine("Press any key to continue...");
+ Console.ReadKey();
+ }
+
+ public List PreviousResult()
+ {
+ var previousResultList = new List();
+ if (history == null || history.Count == 0)
+ {
+ return previousResultList;
+ }
+ else
+ {
+ foreach (var entry in history)
+ {
+ previousResultList.Add(entry.result);
+ }
+ return previousResultList;
+ }
+ }
+
+ public void GetUsageCount()
+ {
+ int historyCount = 0;
+ int count = 0;
+ if (history == null || history.Count == 0)
+ {
+ Console.WriteLine("No history count found.");
+ }
+ else
+ {
+ foreach (var entry in history)
+ {
+ count++;
+ }
+ Console.WriteLine($"Calculator Used: {historyCount += count} times");
+ }
+ Console.WriteLine("Press any key to continue...");
+ Console.ReadKey();
+ }
+
+ public void ClearHistory()
+ {
+ try
+ {
+ if (Calculator.history == null)
+ {
+ Console.WriteLine("Error: History list was never initialized!");
+ return;
+ }
+ Calculator.history.Clear();
+ Console.WriteLine($"History count is now: {Calculator.history.Count}");
+ Console.WriteLine("History Cleared. Press any key to continue...");
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"An error occurred: {ex.Message}");
+ }
+ Console.ReadKey();
+ }
+ }
+}
+
+
diff --git a/Calculator.ShPet1304/CalculatorLibrary/CalculatorLibrary.csproj b/Calculator.ShPet1304/CalculatorLibrary/CalculatorLibrary.csproj
new file mode 100644
index 00000000..22badd14
--- /dev/null
+++ b/Calculator.ShPet1304/CalculatorLibrary/CalculatorLibrary.csproj
@@ -0,0 +1,13 @@
+
+
+
+ net10.0
+ enable
+ enable
+
+
+
+
+
+
+
diff --git a/Calculator.ShPet1304/README.md b/Calculator.ShPet1304/README.md
new file mode 100644
index 00000000..e48d6b22
--- /dev/null
+++ b/Calculator.ShPet1304/README.md
@@ -0,0 +1,42 @@
+# C# Console Calculator
+A professional-grade CLI calculator built with C# and .NET. This project began as a foundational Microsoft tutorial and was extended into a multi-project solution featuring advanced mathematics, persistent logging, and a modern interactive interface.
+
+## Features
+- Interactive Menu: Utilizes Spectre.Console for a rich, user-friendly terminal experience with arrow-key navigation.
+
+- Advanced Mathematics: Supports basic arithmetic plus Square Roots, Powers, and Trigonometric functions (Sin, Cos, Tan).
+
+- Result History: Automatically stores calculations in a session history. Users can view previous results or "inject" a past result back into a new calculation.
+
+- JSON Logging: Every operation is logged to a calculatorlog.json file using Newtonsoft.Json for audit and debugging purposes.
+
+- Defensive Programming: Robust input validation using TryParse to handle edge cases and prevent crashes from invalid user input.
+
+## Technical Implementation
+
+### Architecture
+The project is split into a Multi-Project Solution to maintain a clean separation of concerns:
+- CalculatorLibrary: A class library containing the "Engine." It implements the Singleton Pattern to ensure a single, consistent state for history and logging across the app.
+- CalculatorProgram: The UI layer that manages user flow and input orchestration.
+
+### Design Patterns
+- Singleton Pattern: Used for the Calculator instance to manage shared resources like the JSON writer and history list.
+- State Management: Implemented logic to flag and store "reused" numbers, allowing for complex multi-step calculations.
+
+
+## Requirements & Libraries
+- .NET 8.0 SDK (or newer)
+- Spectre.Console: For the interactive CLI.
+- Newtonsoft.Json: For data persistence and logging.
+
+## How to Run
+1. Clone the repository.
+2. Open the solution in Visual Studio or VS Code.
+3. Run dotnet restore to install the dependencies.
+4. Press F5 or run dotnet run --project Calculator to start the app.
+
+
+
+
+
+##### This project represents my transition from IT Support to Application Development. It highlights my focus on building tools that are not only functional but also robust, logged, and easy for the end-user to navigate.