diff --git a/Todo-Challenge/Todo-Challenge/CommandHandler.cs b/Todo-Challenge/Todo-Challenge/CommandHandler.cs new file mode 100644 index 0000000..8bcd8aa --- /dev/null +++ b/Todo-Challenge/Todo-Challenge/CommandHandler.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Todo_Challenge +{ + internal class CommandHandler + { + public static char GetCommandRefNum(string line) + { + return line[0]; + } + public static string GetTodoItemName(string line) + { + string lineWithoutRefNum = line.Remove(0, 1); + string name = lineWithoutRefNum.Trim(); + return name; + } + } +} diff --git a/Todo-Challenge/Todo-Challenge/Menu.cs b/Todo-Challenge/Todo-Challenge/Menu.cs new file mode 100644 index 0000000..9990bea --- /dev/null +++ b/Todo-Challenge/Todo-Challenge/Menu.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Todo_Challenge +{ + class Menu + { + public static void DisplayOptions() + { + Console.WriteLine("Your current todo list is:"); + Console.WriteLine(); + Console.WriteLine("To edit it, use the options below"); + Console.WriteLine(); + Console.WriteLine("OPTIONS"); + Console.WriteLine("input: action:"); + Console.WriteLine(" 1 -> create a new todo"); + Console.WriteLine(" 2 -> delete a todo"); + Console.WriteLine(" 3 -> toggle an item's completion status"); + Console.WriteLine(" exit -> stop running this app"); + } + } +} diff --git a/Todo-Challenge/Todo-Challenge/Program.cs b/Todo-Challenge/Todo-Challenge/Program.cs index 3751555..e6e78cf 100644 --- a/Todo-Challenge/Todo-Challenge/Program.cs +++ b/Todo-Challenge/Todo-Challenge/Program.cs @@ -1,2 +1,30 @@ -// See https://aka.ms/new-console-template for more information -Console.WriteLine("Hello, World!"); +using System.Text; +using Todo_Challenge; + +new Menu(); +Menu.DisplayOptions(); + +string? line = Console.ReadLine(); + +var list = new TodoList("Todo list"); + +while (line != "exit") +{ + if (line == null) break; + char refNum = CommandHandler.GetCommandRefNum(line); + string itemName = CommandHandler.GetTodoItemName(line); + switch (refNum) + { + case '1': + new TodoItem(itemName, list); + break; + case '2': + TodoList.DeleteItemWhereNameIs(itemName, list); + break; + case '3': + TodoList.ToggleItemCompletionStatusWhereNameIs(itemName, list); + break; + } + TodoList.View(list); + line = Console.ReadLine(); +} diff --git a/Todo-Challenge/Todo-Challenge/TodoItem.cs b/Todo-Challenge/Todo-Challenge/TodoItem.cs new file mode 100644 index 0000000..c227ad7 --- /dev/null +++ b/Todo-Challenge/Todo-Challenge/TodoItem.cs @@ -0,0 +1,48 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; + +namespace Todo_Challenge +{ + internal class TodoItem + { + public int Id { get; set; } + public string? Name { get; set; } + public bool Completed { get; set; } = false; + public TodoItem? NextTodoItem { get; set; } = null; + + private readonly TodoList _list; + + private void LinkToPreviousItem() + { + if (_list.DoesNotContainFirstTodoItem()) + { + _list.Head = this; + return; + } + if (_list.Tail != null) + { + _list.Tail.NextTodoItem = this; + } + } + + public string ReadCompletionStatus() + { + return Completed ? "done" : "to do"; + } + + public TodoItem(string name, TodoList todoList) + { + Id = todoList.NextId; + Name = name; + _list = todoList; + todoList.IncreaseNextIdByOne(); + LinkToPreviousItem(); + todoList.Tail = this; + } + } +} diff --git a/Todo-Challenge/Todo-Challenge/TodoList.cs b/Todo-Challenge/Todo-Challenge/TodoList.cs new file mode 100644 index 0000000..b208084 --- /dev/null +++ b/Todo-Challenge/Todo-Challenge/TodoList.cs @@ -0,0 +1,129 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Text; +using System.Threading.Tasks; +using System.Xml.Linq; + +namespace Todo_Challenge +{ + internal class TodoList : IEnumerable + { + public string Name; + public TodoItem? Head { get; set; } + public TodoItem? Tail { get; set; } + public TodoItem? Current { get; set; } + public int NextId { get; set; } + + IEnumerator IEnumerable.GetEnumerator() + { + Current = Head; + + while (Current != null) + { + yield return Current; + Current = Current.NextTodoItem; + } + } + + + // private retrieval operations executed prior to modifying the list + private static TodoItem? GetTodoItemByName(string name, TodoList todoList) + { + foreach (TodoItem item in todoList) + { + if (item != null && item.Name == name) + { + return item; + } + } + return null; + } + + private static TodoItem? GetPreviousTodoItemByName(string name, TodoList todoList) + { + if (todoList.Head != null && todoList.Head.Name == name) + { + return null; + } + + foreach (TodoItem item in todoList) + { + if (item != null && item.NextTodoItem != null && item.NextTodoItem.Name == name) + { + return item; + } + } + return null; + } + + // is ran upon the start of the application + public TodoList(string name) + { + Name = name; + Head = null; + Tail = null; + Current = null; + NextId = 1; + } + + // methods ran when a todo item is created + public void IncreaseNextIdByOne() + { + NextId++; + } + + public bool DoesNotContainFirstTodoItem() { return Head == null; } + + // method ran after each list modification so the user may visualise the result + public static void View(TodoList todoList) + { + Console.WriteLine(); + Console.WriteLine("TODO LIST"); + Console.WriteLine(); + + foreach (TodoItem item in todoList) + { + var isComplete = item.ReadCompletionStatus(); + Console.WriteLine(item.Name + " completion status: " + isComplete); + } + } + + // list modification operations triggered by commands + public static void DeleteItemWhereNameIs(string name, TodoList todoList) + { + var item = GetTodoItemByName(name, todoList); + if (item == null) + { + Console.WriteLine($"failed to delete ${name}, no such item found"); + return; + } + var previousItem = GetPreviousTodoItemByName(name, todoList); + if (previousItem == null) + { + todoList.Head = item.NextTodoItem; + return; + } + else + { + // if I got this right redirecting the pointer is enough to remove + // any references to said item, and set it up for garbage collection (since it becomes unreachable) + previousItem.NextTodoItem = item.NextTodoItem; + } + } + + public static void ToggleItemCompletionStatusWhereNameIs(string name, TodoList todoList) + { + var item = GetTodoItemByName(name, todoList); + if (item == null) + { + Console.WriteLine($"failed to toggle completion status of {name}, no such item found"); + return; + } + item.Completed = !item.Completed; + } + + } +}