diff --git a/.gitignore b/.gitignore index f69985ef1f..f2d4270f7b 100644 --- a/.gitignore +++ b/.gitignore @@ -14,4 +14,4 @@ src/main/resources/docs/ bin/ /text-ui-test/ACTUAL.txt -text-ui-test/EXPECTED-UNIX.TXT +text-ui-test/EXPECTED.TXT diff --git a/data/duke.txt b/data/duke.txt new file mode 100644 index 0000000000..5ac06b2bf1 --- /dev/null +++ b/data/duke.txt @@ -0,0 +1,3 @@ +[D][✘] d2 (by: Year.2015, Month.FEBRUARY, Day.20, Time: h.6, m.30) +[D][✘] e1 (by: Year.2015, Month.FEBRUARY, Day.20, Time: h.6, m.30) +[T][✘] task4 diff --git a/src/main/java/Duke.java b/src/main/java/Duke.java deleted file mode 100644 index 5d313334cc..0000000000 --- a/src/main/java/Duke.java +++ /dev/null @@ -1,10 +0,0 @@ -public class Duke { - public static void main(String[] args) { - String logo = " ____ _ \n" - + "| _ \\ _ _| | _____ \n" - + "| | | | | | | |/ / _ \\\n" - + "| |_| | |_| | < __/\n" - + "|____/ \\__,_|_|\\_\\___|\n"; - System.out.println("Hello from\n" + logo); - } -} diff --git a/src/main/java/Duke/Duke.java b/src/main/java/Duke/Duke.java new file mode 100644 index 0000000000..e725c52048 --- /dev/null +++ b/src/main/java/Duke/Duke.java @@ -0,0 +1,99 @@ +package Duke; + +import Duke.DukeException.DeadlineNullException; +import Duke.DukeException.EventNullException; +import Duke.DukeException.TodoNullException; +import Duke.command.Command; +import Duke.parser.Parser; +import Duke.storage.Storage; +import Duke.taskList.TaskList; +import Duke.ui.UI; + +import java.time.Month; + +import static Duke.ui.UI.DOUBLEINDENTATION; +import static Duke.ui.UI.printStatement; + +public class Duke { + + private Storage storage; + private TaskList tasks; + private UI ui; + + public Duke(String filePath) { + ui = new UI(); + storage = new Storage(filePath); + //try { + tasks = new TaskList(storage.load()); + /*} catch (DukeException e) { + ui.showLoadingError(); + tasks = new TaskList(); + }*/ + } + + public void run() { + ui.showWelcome(); + boolean isExit = false; + int numberOfTasks = storage.loadNumberOfTasks(); + while (!isExit) { + //try { + String fullCommand = ui.readCommand(); + ui.showLine(); // show the divider line ("_______") + Command c; + if(fullCommand.contains("todo")) { + c = Parser.parseTodoCommand(fullCommand, numberOfTasks); + numberOfTasks++; + } else if(fullCommand.contains("deadline")){ + c = Parser.parseDeadlineCommand(fullCommand, numberOfTasks); + numberOfTasks++; + } else if(fullCommand.contains("event")) { + c = Parser.parseEventCommand(fullCommand, numberOfTasks); + numberOfTasks++; + } else if(fullCommand.contains("help")) { + c = Parser.parseHelpCommand(numberOfTasks); + } else if(fullCommand.contains("list")){ + c = Parser.parseListCommand(numberOfTasks); + } else if(fullCommand.contains("find")) { + c = Parser.parseFindCommand(fullCommand.substring(fullCommand.indexOf("find")+4).trim(), + numberOfTasks); + } else if(fullCommand.contains("done")) { + c = Parser.parseDoneCommand(fullCommand, numberOfTasks); + } else if(fullCommand.contains("delete")) { + c = Parser.parseDeleteCommand(fullCommand, numberOfTasks); + if(c.description.length() != 0) { + numberOfTasks--; + } + } else if(fullCommand.contains("bye")){ + c = Parser.parseExitCommand(numberOfTasks); + } else { + c = Parser.parseExceptionCommand(numberOfTasks); + } + try{ + c.execute(tasks, ui, storage); + c.sava(tasks, ui, storage); + isExit = c.isExit(); + } catch (NullPointerException e) { + numberOfTasks--; + } catch (TodoNullException e) { + printStatement(DOUBLEINDENTATION + + "☹ OOPS!!! The description of a todo cannot be empty.\n"); + tasks.remove(numberOfTasks-1); + numberOfTasks--; + } catch (DeadlineNullException e) { + numberOfTasks--; + } catch (EventNullException e) { + numberOfTasks--; + } + + /*} catch (DukeException e) { + ui.showError(e.getMessage()); + } finally { + ui.showLine(); + }*/ + } + } + + public static void main(String[] args) { + new Duke("/Users/yuqiao/Desktop/CS2113T/ip/data/duke.txt").run(); + } +} \ No newline at end of file diff --git a/src/main/java/Duke/DukeException/DeadlineNullException.java b/src/main/java/Duke/DukeException/DeadlineNullException.java new file mode 100644 index 0000000000..be6faa2379 --- /dev/null +++ b/src/main/java/Duke/DukeException/DeadlineNullException.java @@ -0,0 +1,4 @@ +package Duke.DukeException; + +public class DeadlineNullException extends Exception { +} diff --git a/src/main/java/Duke/DukeException/EventNullException.java b/src/main/java/Duke/DukeException/EventNullException.java new file mode 100644 index 0000000000..4fdbf71de1 --- /dev/null +++ b/src/main/java/Duke/DukeException/EventNullException.java @@ -0,0 +1,4 @@ +package Duke.DukeException; + +public class EventNullException extends Throwable { +} diff --git a/src/main/java/Duke/DukeException/InvalidStorageFilePathException.java b/src/main/java/Duke/DukeException/InvalidStorageFilePathException.java new file mode 100644 index 0000000000..71781ccb83 --- /dev/null +++ b/src/main/java/Duke/DukeException/InvalidStorageFilePathException.java @@ -0,0 +1,10 @@ +package Duke.DukeException; + +/** + * build InvalidStorageNullException extending Exception. + */ +public class InvalidStorageFilePathException extends Exception { + public InvalidStorageFilePathException(String s) { + } + //no other code needed +} diff --git a/src/main/java/Duke/DukeException/TodoNullException.java b/src/main/java/Duke/DukeException/TodoNullException.java new file mode 100644 index 0000000000..f9bb43a8a2 --- /dev/null +++ b/src/main/java/Duke/DukeException/TodoNullException.java @@ -0,0 +1,8 @@ +package Duke.DukeException; + +/** + * build TodoNullException extending Exception. + */ +public class TodoNullException extends Exception { + //no other code needed +} diff --git a/src/main/java/Duke/command/Command.java b/src/main/java/Duke/command/Command.java new file mode 100644 index 0000000000..a3b49f3375 --- /dev/null +++ b/src/main/java/Duke/command/Command.java @@ -0,0 +1,53 @@ +package Duke.command; + +import Duke.DukeException.DeadlineNullException; +import Duke.DukeException.EventNullException; +import Duke.DukeException.TodoNullException; +import Duke.storage.Storage; +import Duke.taskList.TaskList; +import Duke.ui.UI; + +/** + * Represents a Command with description and numberOfTasks. + * Is it an abstracted type. + */ +public class Command { + public String description; + protected int numberOfTasks = 0; + + public Command(String description, int numberOfTasks) { + this.description = description; + this.numberOfTasks = numberOfTasks; + } + + /** + * Execute the Command. + */ + public void execute(TaskList tasks, UI ui, Storage storage) throws TodoNullException, DeadlineNullException, EventNullException { + } + + /** + * Execute the save function. + * Save the changed taskList into the file + */ + public void sava(TaskList tasks, UI ui, Storage storage){ + + } + + /** + * Return a boolean variable indicating whether the command + * is an ExitCommand. + * If it is, return true. Else wise, return false. + * + * @return Boolean variable indicating whether the command + * is an ExitCommand. + */ + public boolean isExit() { + if(description == "bye") { + return true; + } + else { + return false; + } + } +} diff --git a/src/main/java/Duke/command/DeadlineCommand.java b/src/main/java/Duke/command/DeadlineCommand.java new file mode 100644 index 0000000000..d5049a3db9 --- /dev/null +++ b/src/main/java/Duke/command/DeadlineCommand.java @@ -0,0 +1,58 @@ +package Duke.command; + +import Duke.DukeException.DeadlineNullException; +import Duke.DukeException.EventNullException; +import Duke.DukeException.TodoNullException; +import Duke.storage.Storage; +import Duke.task.Deadline; +import Duke.taskList.TaskList; +import Duke.ui.UI; + +import java.time.LocalDateTime; +import java.time.format.DateTimeParseException; + +import static Duke.ui.UI.*; + +/** + * Represents a DeadlineCommand with description and numberOfTasks. + * A deadline object corresponds to a TodoCommand + * with the description and due time extracted from what entered by users. + */ +public class DeadlineCommand extends Command { + protected LocalDateTime by; + + public DeadlineCommand(String description, int numberOfTasks, String by) { + super(description, numberOfTasks); + try { + this.by = LocalDateTime.parse(by); + } catch (DateTimeParseException e) { + printStatement(DOUBLEINDENTATION + "☹ OOPS!!! The time entered is not in the format(yyyy-mm-dd).\n"); + } + } + + /** + * Override: Execute the Command. + * add a new Deadline into the taskList. + */ + @Override + public void execute(TaskList tasks, UI ui, Storage storage) throws TodoNullException, DeadlineNullException, + EventNullException { + super.execute(tasks, ui, storage); + if(this.by.toString().length() == 0 && this.by.toString().length() == 0){ + throw new DeadlineNullException(); + } + tasks.add(new Deadline(this.description, this.by)); + ui.printStatement(DOUBLEINDENTATION + "Got it. I've added this task:\n" + + TRIPLEINDENTATION + tasks.get(numberOfTasks - 1).toString() + "\n" + DOUBLEINDENTATION + + "Now you have " + (numberOfTasks) + " tasks in the list.\n"); + } + + /** + * Execute the save function. + * Save the changed taskList into the file + */ + @Override + public void sava(TaskList tasks, UI ui, Storage storage){ + Storage.save(tasks, numberOfTasks); + } +} diff --git a/src/main/java/Duke/command/DeleteCommand.java b/src/main/java/Duke/command/DeleteCommand.java new file mode 100644 index 0000000000..770843951f --- /dev/null +++ b/src/main/java/Duke/command/DeleteCommand.java @@ -0,0 +1,45 @@ +package Duke.command; + +import Duke.storage.Storage; +import Duke.taskList.TaskList; +import Duke.ui.UI; + +import static Duke.ui.UI.*; + +/** + * Represents a DeleteCommand with description and numberOfTasks. + * A delete object corresponds to a DeleteCommand + * with the description extracted from what entered by users, + * which is the index of the task users intend to delete. + */ +public class DeleteCommand extends Command { + public DeleteCommand(String description, int numberOfTasks) { + super(description, numberOfTasks); + } + + /** + * Override: Execute the Command. + * Delete the task with entered index. + * Print out the delete message. + */ + @Override + public void execute(TaskList tasks, UI ui, Storage storage){ + try { + printStatement(DOUBLEINDENTATION + "Noted. I've removed this task: \n" + + TRIPLEINDENTATION + tasks.get(Integer.parseInt(this.description)-1).toString() + "\n" + + DOUBLEINDENTATION + "Now you have " + (numberOfTasks-1) + " tasks in the list.\n"); + tasks.remove(Integer.parseInt(this.description)-1); + } catch (NumberFormatException e) { + printStatement(DOUBLEINDENTATION + "☹ OOPS!!! You did not indicate which task to delete.\n"); + } + } + + /** + * Execute the save function. + * Save the changed taskList into the file + */ + @Override + public void sava(TaskList tasks, UI ui, Storage storage){ + Storage.save(tasks, numberOfTasks-1); + } +} diff --git a/src/main/java/Duke/command/DoneCommand.java b/src/main/java/Duke/command/DoneCommand.java new file mode 100644 index 0000000000..191754793e --- /dev/null +++ b/src/main/java/Duke/command/DoneCommand.java @@ -0,0 +1,46 @@ +package Duke.command; + +import Duke.storage.Storage; +import Duke.taskList.TaskList; +import Duke.ui.UI; + +import static Duke.ui.UI.*; + +/** + * Represents a DoneCommand with description and numberOfTasks. + * A done object corresponds to a DoneCommand + * with the description extracted from what entered by users, + * which is the index of the task users intend to mark as done. + */ +public class DoneCommand extends Command { + public DoneCommand(String description, int numberOfTasks) { + super(description, numberOfTasks); + } + + /** + * Override: Execute the Command. + * Mark the task with the entered index as done. + * Print out the done message. + */ + @Override + public void execute(TaskList tasks, UI ui, Storage storage){ + try { + tasks.get(Integer.parseInt(this.description)- 1).markAsDone(); + printStatement(DOUBLEINDENTATION + "Nice! I've marked this task as done: \n" + + TRIPLEINDENTATION + tasks.get(Integer.parseInt(this.description) - 1).toString() + "\n"); + } catch (NumberFormatException e) { + printStatement(DOUBLEINDENTATION + "☹ OOPS!!! You did not indicate which task is done.\n"); + } catch (IndexOutOfBoundsException e) { + printStatement(DOUBLEINDENTATION + "☹ OOPS!!! The index is out of the list boundary.\n"); + } + } + + /** + * Execute the save function. + * Save the changed taskList into the file + */ + @Override + public void sava(TaskList tasks, UI ui, Storage storage){ + Storage.save(tasks, numberOfTasks); + } +} diff --git a/src/main/java/Duke/command/EventCommand.java b/src/main/java/Duke/command/EventCommand.java new file mode 100644 index 0000000000..d9321aceb8 --- /dev/null +++ b/src/main/java/Duke/command/EventCommand.java @@ -0,0 +1,54 @@ +package Duke.command; + +import Duke.DukeException.DeadlineNullException; +import Duke.DukeException.EventNullException; +import Duke.DukeException.TodoNullException; +import Duke.storage.Storage; +import Duke.task.Event; +import Duke.taskList.TaskList; +import Duke.ui.UI; + +import java.time.LocalDateTime; + +import static Duke.ui.UI.DOUBLEINDENTATION; +import static Duke.ui.UI.TRIPLEINDENTATION; + +/** + * Represents an EventCommand with description and numberOfTasks. + * A event object corresponds to a TodoCommand + * with the description and happening time extracted from what entered by users. + */ +public class EventCommand extends Command { + protected LocalDateTime at; + + public EventCommand(String description, int numberOfTasks, String at) { + super(description, numberOfTasks); + this.at = LocalDateTime.parse(at); + } + + /** + * Override: Execute the Command. + * add a new Event into the taskList. + */ + @Override + public void execute(TaskList tasks, UI ui, Storage storage) throws TodoNullException, DeadlineNullException, + EventNullException { + super.execute(tasks, ui, storage); + if(this.at.toString().length() == 0 && this.at.toString().length() == 0){ + throw new EventNullException(); + } + tasks.add(new Event(this.description, this.at)); + ui.printStatement(DOUBLEINDENTATION + "Got it. I've added this task:\n" + + TRIPLEINDENTATION + tasks.get(numberOfTasks - 1).toString() + "\n" + DOUBLEINDENTATION + + "Now you have " + (numberOfTasks) + " tasks in the list.\n"); + } + + /** + * Execute the save function. + * Save the changed taskList into the file + */ + @Override + public void sava(TaskList tasks, UI ui, Storage storage){ + Storage.save(tasks, numberOfTasks); + } +} diff --git a/src/main/java/Duke/command/ExceptionCommand.java b/src/main/java/Duke/command/ExceptionCommand.java new file mode 100644 index 0000000000..3d7fb7f58b --- /dev/null +++ b/src/main/java/Duke/command/ExceptionCommand.java @@ -0,0 +1,27 @@ +package Duke.command; + +import Duke.storage.Storage; +import Duke.taskList.TaskList; +import Duke.ui.UI; + +import static Duke.ui.UI.DOUBLEINDENTATION; +import static Duke.ui.UI.printStatement; + +/** + * Represents an ExceptionCommand with description and numberOfTasks. + * It indicates that there are no corresponding functions in this Duke. + */ +public class ExceptionCommand extends Command { + public ExceptionCommand(String description, int numberOfTasks) { + super(description, numberOfTasks); + } + + /** + * Override: Execute the Command. + * Print out the wrong message. + */ + @Override + public void execute(TaskList tasks, UI ui, Storage storage) { + printStatement(DOUBLEINDENTATION + ui.WRONGMESSAGE); + } +} diff --git a/src/main/java/Duke/command/ExitCommand.java b/src/main/java/Duke/command/ExitCommand.java new file mode 100644 index 0000000000..6e15639769 --- /dev/null +++ b/src/main/java/Duke/command/ExitCommand.java @@ -0,0 +1,23 @@ +package Duke.command; + +import Duke.storage.Storage; +import Duke.taskList.TaskList; +import Duke.ui.UI; + +/** + * Represents an ExitCommand with description and numberOfTasks. + */ +public class ExitCommand extends Command { + public ExitCommand(String description, int numberOfTasks) { + super(description, numberOfTasks); + } + + /** + * Override: Execute the Command. + * Print out the Exit message and exit. + */ + @Override + public void execute(TaskList tasks, UI ui, Storage storage) { + ui.printStatement(ui.BYE); + } +} diff --git a/src/main/java/Duke/command/FindCommand.java b/src/main/java/Duke/command/FindCommand.java new file mode 100644 index 0000000000..f997a92328 --- /dev/null +++ b/src/main/java/Duke/command/FindCommand.java @@ -0,0 +1,26 @@ +package Duke.command; + +import Duke.storage.Storage; +import Duke.taskList.TaskList; +import Duke.ui.UI; + +import static Duke.ui.UI.*; + +public class FindCommand extends Command { + public FindCommand(String description, int numberOfTasks) { + super(description, numberOfTasks); + } + + @Override + public void execute(TaskList tasks, UI ui, Storage storage) { + System.out.print(HORIZONTALLINE); + System.out.println(INDENTATION + "Here is yuqiaoluolong's Duke: \n" + + " Here are the matching tasks in your list:"); + for(int i = 0; i < numberOfTasks; i++){ + if(tasks.get(i).toString().contains(description)) { + System.out.println(DOUBLEINDENTATION + (i + 1) + "." + tasks.get(i).toString()); + } + } + System.out.println(HORIZONTALLINE); + } +} \ No newline at end of file diff --git a/src/main/java/Duke/command/HelpCommand.java b/src/main/java/Duke/command/HelpCommand.java new file mode 100644 index 0000000000..4976bfbd18 --- /dev/null +++ b/src/main/java/Duke/command/HelpCommand.java @@ -0,0 +1,32 @@ +package Duke.command; + +import Duke.storage.Storage; +import Duke.taskList.TaskList; +import Duke.ui.UI; + +import static Duke.ui.UI.DOUBLEINDENTATION; +import static Duke.ui.UI.TRIPLEINDENTATION; + +public class HelpCommand extends Command { + public HelpCommand(String description, int numberOfTasks) { + super(description, numberOfTasks); + } + + @Override + public void execute(TaskList tasks, UI ui, Storage storage) { + UI.printStatement(DOUBLEINDENTATION + "Hello, below is the explanation of the functions:\n" + + TRIPLEINDENTATION + "1. you can add todo tasks follwed by the description\n" + + TRIPLEINDENTATION + "example: todo task1 --> [T][✘] task1\n" + + TRIPLEINDENTATION + "2. you can add deadlines followed by the description and the due time\n" + + TRIPLEINDENTATION + "example: deadline d2 /by 2015-02-20T06:30:00 --> " + + "[D][✘] d2 (by: Year.2015, Month.FEBRUARY, Day.20, Time: h.6, m.30)\n" + + TRIPLEINDENTATION + "3. you can add events followed by the description and the happening time\n" + + TRIPLEINDENTATION + "example: event e2 /by 2015-02-20T06:30:00 --> " + + "[E][✘] e2 (by: Year.2015, Month.FEBRUARY, Day.20, Time: h.6, m.30)\n" + + TRIPLEINDENTATION + "4. you can view all the tasks by typing \" list\" \n" + + TRIPLEINDENTATION + "5. you can search for the tasks containing some words\n" + + TRIPLEINDENTATION + "example: find book --> Duke will show all the tasks related with book\n" + + TRIPLEINDENTATION + "6. you can mark one task as done by byping \"done\" followed its number\n" + + TRIPLEINDENTATION + "7. you can delete one task as done by byping \"delete\" followed its number\n"); + } +} \ No newline at end of file diff --git a/src/main/java/Duke/command/ListCommand.java b/src/main/java/Duke/command/ListCommand.java new file mode 100644 index 0000000000..55356ad6a2 --- /dev/null +++ b/src/main/java/Duke/command/ListCommand.java @@ -0,0 +1,32 @@ +package Duke.command; + +import Duke.storage.Storage; +import Duke.taskList.TaskList; +import Duke.ui.UI; + +import static Duke.ui.UI.*; + +/** + * Represents a ListCommand with description and numberOfTasks. + */ +public class ListCommand extends Command { + public ListCommand(String description, int numberOfTasks) { + super(description, numberOfTasks); + } + + /** + * Override: Execute the Command. + * Print out all the tasks in the taskList. + */ + @Override + public void execute(TaskList tasks, UI ui, Storage storage) { + System.out.print(HORIZONTALLINE); + System.out.println(INDENTATION + "Here is yuqiaoluolong's Duke: \n" + + " Here are the tasks in your list:"); + for(int i = 0; i < numberOfTasks; i++){ + System.out.println(DOUBLEINDENTATION + (i+1) + "." + tasks.get(i).toString()); + } + System.out.println(HORIZONTALLINE); + } +} + diff --git a/src/main/java/Duke/command/TodoCommand.java b/src/main/java/Duke/command/TodoCommand.java new file mode 100644 index 0000000000..10b9223666 --- /dev/null +++ b/src/main/java/Duke/command/TodoCommand.java @@ -0,0 +1,50 @@ +package Duke.command; + +import Duke.DukeException.DeadlineNullException; +import Duke.DukeException.EventNullException; +import Duke.DukeException.TodoNullException; +import Duke.storage.Storage; +import Duke.task.Todo; +import Duke.taskList.TaskList; +import Duke.ui.UI; + +import static Duke.ui.UI.DOUBLEINDENTATION; +import static Duke.ui.UI.TRIPLEINDENTATION; + +/** + * Represents a TodoCommand with description and numberOfTasks. + * A todo object corresponds to a TodoCommand + * with the description extracted from what entered by users. + */ +public class TodoCommand extends Command { + + public TodoCommand(String description, int numberOfTasks) { + super(description, numberOfTasks); + } + + /** + * Override: Execute the Command. + * add a new Todo into the taskList. + */ + @Override + public void execute(TaskList tasks, UI ui, Storage storage) throws TodoNullException, DeadlineNullException, + EventNullException { + super.execute(tasks, ui, storage); + tasks.add(new Todo(this.description)); + if(tasks.get(numberOfTasks-1).description.length() == 0){ + throw new TodoNullException(); + } + ui.printStatement(DOUBLEINDENTATION + "Got it. I've added this task:\n" + + TRIPLEINDENTATION + tasks.get(numberOfTasks - 1).toString() + "\n" + DOUBLEINDENTATION + + "Now you have " + (numberOfTasks) + " tasks in the list.\n"); + } + + /** + * Execute the save function. + * Save the changed taskList into the file + */ + @Override + public void sava(TaskList tasks, UI ui, Storage storage){ + Storage.save(tasks, numberOfTasks); + } +} diff --git a/src/main/java/Duke/parser/Parser.java b/src/main/java/Duke/parser/Parser.java new file mode 100644 index 0000000000..990b1fbd3a --- /dev/null +++ b/src/main/java/Duke/parser/Parser.java @@ -0,0 +1,128 @@ +package Duke.parser; + +import Duke.command.*; + +import static Duke.ui.UI.DOUBLEINDENTATION; +import static Duke.ui.UI.printStatement; + +/** + * parse the command entered into different format + * for methods to take in + */ +public class Parser { + + /** + * Returns TodolineCommand with the description + * extracted from the fullCommand + * + * @param fullCommand Command entered by users. + * @param numberOfTasks Number of tasks. + * @return TodolineCommand with the description. + */ + public static TodoCommand parseTodoCommand(String fullCommand, int numberOfTasks) { + String description = fullCommand.substring(fullCommand.indexOf("todo")+4).trim(); + if(description =="") { + return null; + } + return new TodoCommand(description, numberOfTasks); + } + + /** + * Returns DeadlineCommand with the description and due time + * extracted from the fullCommand + * + * @param fullCommand Command entered by users. + * @param numberOfTasks Number of tasks. + * @return DeadlineCommand with the description and due time. + */ + public static DeadlineCommand parseDeadlineCommand(String fullCommand, int numberOfTasks) { + try { + return new DeadlineCommand(fullCommand.substring(fullCommand.indexOf("deadline") + 8, + fullCommand.indexOf("/")).trim(), numberOfTasks, + fullCommand.substring(fullCommand.indexOf("/") + 3).trim()); + } catch (StringIndexOutOfBoundsException e) { + printStatement(DOUBLEINDENTATION + "☹ OOPS!!! There is nothing following \"deadline\".\n"); + } + return null; + } + + /** + * Returns EventCommand with the description and happening time + * extracted from the fullCommand + * + * @param fullCommand Command entered by users. + * @param numberOfTasks Number of tasks. + * @return EventCommand with the description and happening time. + */ + public static EventCommand parseEventCommand(String fullCommand, int numberOfTasks) { + try { + return new EventCommand(fullCommand.substring(fullCommand.indexOf("event")+5, + fullCommand.indexOf("/")).trim(), numberOfTasks, + fullCommand.substring(fullCommand.indexOf("/")+3).trim()); + } catch (StringIndexOutOfBoundsException e) { + printStatement(DOUBLEINDENTATION + "☹ OOPS!!! There is nothing following \"event\".\n"); + } + return null; + } + + /** + * Returns ListCommand with the description of "list" + * + * @param numberOfTasks Number of tasks. + * @return ListCommand with the description of "list". + */ + public static Command parseListCommand(int numberOfTasks) { + return new ListCommand("list", numberOfTasks); + } + /** + * Returns ListCommand with the description of "bye" + * + * @param numberOfTasks Number of tasks. + * @return ListCommand with the description of "bye". + */ + public static Command parseExitCommand(int numberOfTasks) { + return new ExitCommand("bye", numberOfTasks); + } + + /** + * Returns DoneCommand with the description which is the index of tasks to change to done + * and extracted from the fullCommand. + * + * @param fullCommand Command entered by users + * @param numberOfTasks Number of tasks. + * @return DoneCommand with the description of the index of tasks to change to done. + */ + public static Command parseDoneCommand(String fullCommand, int numberOfTasks) { + return new DoneCommand(fullCommand.replace("done", " ").trim(), numberOfTasks); + } + + /** + * Returns DeleteCommand with the description which is the index of tasks to delete + * and extracted from the fullCommand. + * + * @param fullCommand Command entered by users + * @param numberOfTasks Number of tasks. + * @return DeleteCommand with the description that is the index of tasks to delete. + */ + public static Command parseDeleteCommand(String fullCommand, int numberOfTasks) { + return new DeleteCommand(fullCommand.replace("delete", " ").trim(), numberOfTasks); + } + + /** + * Returns Exception Command with the description "exception" + * + * @param numberOfTasks Number of tasks. + * @return Exception Command with the description "exception" + */ + public static Command parseExceptionCommand(int numberOfTasks) { + return new ExceptionCommand("exception", numberOfTasks); + } + + public static Command parseFindCommand(String index, int numberOfTasks) { + return new FindCommand(index, numberOfTasks); + } + + public static Command parseHelpCommand(int numberOfTasks) { + return new HelpCommand("help", numberOfTasks); + } +} diff --git a/src/main/java/Duke/storage/Storage.java b/src/main/java/Duke/storage/Storage.java new file mode 100644 index 0000000000..a13b0f5cd4 --- /dev/null +++ b/src/main/java/Duke/storage/Storage.java @@ -0,0 +1,187 @@ +package Duke.storage; + +import Duke.DukeException.InvalidStorageFilePathException; +import Duke.task.Deadline; +import Duke.task.Event; +import Duke.task.Task; +import Duke.task.Todo; +import Duke.taskList.TaskList; + +import java.io.FileWriter; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.time.LocalDateTime; +import java.time.Month; +import java.time.format.DateTimeParseException; +import java.util.ArrayList; + +import static Duke.ui.UI.INDENTATION; +import static Duke.ui.UI.printStatement; + +/** + * Represents a class saving the tasklist to a file and load the content from it. + */ +public class Storage { + public static final String DEFAULT_STORAGE_FILEPATH = "/Users/yuqiao/Desktop/CS2113T/ip/data/duke.txt"; + public static Path path = Path.of(DEFAULT_STORAGE_FILEPATH); + + public Storage(String filePath) /*throws InvalidStorageFilePathException*/ { + path = Paths.get(filePath); + if (!isValidPath(path)) { + try { + throw new InvalidStorageFilePathException("Storage file should end with '.txt'"); + } catch (InvalidStorageFilePathException e) { + e.printStackTrace(); + } + } + } + + /** + * Returns a boolean variable indicating whethe the path is valid or not + * + * @param filePath Path of the file to be tested. + * @return the validity of the filePath. + */ + private static boolean isValidPath(Path filePath) { + return filePath.toString().endsWith(".txt"); + } + + /** + * save the changed task list into the file + * + * @param tasks Task list to save + * @param numberOfTasks Number of the tasks in the task list. + */ + public static void save(TaskList tasks, int numberOfTasks) { + String text = ""; + for(int i = 0; i + * + * @return Task list containing tasks inside the + * file of the type ArrayList + */ + public ArrayList load(){ + ArrayList tasklist = new ArrayList<>(); + try { + for (String encodedTask : Files.readAllLines(path)) { + if(encodedTask.contains("D")) { + int year, dayOfMonth, hour, minute; + Month month; + try{ + year =Integer.parseInt(encodedTask.substring(encodedTask.indexOf("Year") + 5, + encodedTask.indexOf("Month") - 2)); + month = Month.valueOf(encodedTask.substring(encodedTask.indexOf("Month") + 6, + encodedTask.indexOf("Day") - 2)); + dayOfMonth = Integer.parseInt(encodedTask.substring(encodedTask.indexOf("Day") + 4, + encodedTask.indexOf("Time") - 2)); + hour = Integer.parseInt(encodedTask.substring(encodedTask.lastIndexOf("h") + 2, + encodedTask.lastIndexOf("m") - 2)); + minute = Integer.parseInt(encodedTask.substring(encodedTask.lastIndexOf("m") + 2, + encodedTask.indexOf(")"))); + tasklist.add(new Deadline(getDescriptiongFromFile(encodedTask), + LocalDateTime.of(year, month, dayOfMonth, hour, minute))); + } catch (DateTimeParseException e) { + tasklist.remove(tasklist.size()-1); + printStatement(INDENTATION + "☹ OOPS!!! There are time entered wrongly in the text file.\n" + + INDENTATION + "Please delete them.\n"); + } + if(encodedTask.contains("\u2713")) { + tasklist.get(tasklist.size()-1).markAsDone(); + } + } else if(encodedTask.contains("E")) { + int year, dayOfMonth, hour, minute; + Month month; + try { + year =Integer.parseInt(encodedTask.substring(encodedTask.indexOf("Year") + 5, + encodedTask.indexOf("Month") - 2)); + month = Month.valueOf(encodedTask.substring(encodedTask.indexOf("Month") + 6, + encodedTask.indexOf("Day") - 2)); + dayOfMonth = Integer.parseInt(encodedTask.substring(encodedTask.indexOf("Day") + 4, + encodedTask.indexOf("Time") - 2)); + hour = Integer.parseInt(encodedTask.substring(encodedTask.lastIndexOf("h") + 2, + encodedTask.lastIndexOf("m") - 2)); + minute = Integer.parseInt(encodedTask.substring(encodedTask.lastIndexOf("m") + 2, + encodedTask.indexOf(")"))); + tasklist.add(new Event(getDescriptiongFromFile(encodedTask), + LocalDateTime.of(year, month, dayOfMonth, hour, minute))); + } catch (DateTimeParseException e) { + tasklist.remove(tasklist.size()-1); + printStatement(INDENTATION + "☹ OOPS!!! There are time entered wrongly in the text file.\n" + + INDENTATION + "Please delete them.\n"); + } + if(encodedTask.contains("\u2713")) { + tasklist.get(tasklist.size()-1).markAsDone(); + } + } else { + tasklist.add(new Todo(getDescriptiongFromFile(encodedTask))); + if(encodedTask.contains("\u2713")) { + tasklist.get(tasklist.size()-1).markAsDone(); + } + } + } + return tasklist; + } catch (IOException e) { + e.printStackTrace(); + } + return null; + } + + /** + * Returns the description of a task as a String variable. + * extracted from the inputCommand + * + * @param inputCommand Command entered by users. + * @return Description of a task as a String variable. + */ + public static String getDescriptiongFromFile(String inputCommand) { + if(inputCommand.contains(":")){ + return inputCommand.substring(inputCommand.lastIndexOf("]") + 1, inputCommand.indexOf((":"))-4).trim(); + } else { + return inputCommand.substring(inputCommand.lastIndexOf("]") + 1).trim(); + } + } + + /** + * Returns the number of tasks inside the file when loading + * + * @return Number of tasks inside the file. + */ + public int loadNumberOfTasks(){ + int number = 0; + try { + for (int i = 0; i< Files.readAllLines(path).size(); i++) { + number++; + } + return number; + } catch (IOException e) { + e.printStackTrace(); + } + return -1; + } +} + diff --git a/src/main/java/Duke/task/Deadline.java b/src/main/java/Duke/task/Deadline.java new file mode 100644 index 0000000000..bf17032ee2 --- /dev/null +++ b/src/main/java/Duke/task/Deadline.java @@ -0,0 +1,26 @@ +package Duke.task; + +import java.time.LocalDateTime; + +/** + * Represents a Deadline Task. Adeadline corresponds to a task + * described by description ,isDone, and by. + */ +public class Deadline extends Task { + + protected LocalDateTime by; + + public Deadline(String description, LocalDateTime by) { + super(description); + this.by = by; + } + + /** + * Override: convert the task to a String in a certain format + */ + @Override + public String toString() { + return "[D]" + super.toString() + " (by: Year." + by.getYear() +", Month." + by.getMonth() + + ", Day." + by.getDayOfMonth() +", Time: h." + by.getHour() +", m." + by.getMinute() + ")"; + } +} \ No newline at end of file diff --git a/src/main/java/Duke/task/Event.java b/src/main/java/Duke/task/Event.java new file mode 100644 index 0000000000..144688ea0e --- /dev/null +++ b/src/main/java/Duke/task/Event.java @@ -0,0 +1,26 @@ +package Duke.task; + +import java.time.LocalDateTime; + +/** + * Represents a Event Task. Aevent corresponds to a task + * described by description ,isDone, and at. + */ +public class Event extends Task { + + protected LocalDateTime at; + + public Event(String description, LocalDateTime at){ + super(description); + this.at = at; + } + + /** + * Override: convert the task to a String in a certain format + */ + @Override + public String toString() { + return "[E]" + super.toString() + " (at: Year." + at.getYear() +", Month." + at.getMonth() + + ", Day." + at.getDayOfMonth() +", Time: h." + at.getHour() +", m." + at.getMinute() + ")"; + } +} diff --git a/src/main/java/Duke/task/Task.java b/src/main/java/Duke/task/Task.java new file mode 100644 index 0000000000..2d06198c6a --- /dev/null +++ b/src/main/java/Duke/task/Task.java @@ -0,0 +1,32 @@ +package Duke.task; + +/** + * Represents a Task. It is an abstract type + */ +public class Task { + public String description; + public boolean isDone; + + public Task(String description) { + this.description = description; + this.isDone = false; + } + + /** + * mark the task as done. + */ + public void markAsDone(){ + this.isDone = true; + } + + public String getStatusIcon() { + return (isDone ? "\u2713" : "\u2718"); //return tick or X symbols + } + + /** + * convert the task to a String in a certain format + */ + public String toString() { + return "[" + this.getStatusIcon() + "] " + this.description; + } +} diff --git a/src/main/java/Duke/task/Todo.java b/src/main/java/Duke/task/Todo.java new file mode 100644 index 0000000000..ad910fd702 --- /dev/null +++ b/src/main/java/Duke/task/Todo.java @@ -0,0 +1,20 @@ +package Duke.task; + +/** + * Represents a Todo Task. Atodo corresponds to a task + * described by description and isDone. + */ +public class Todo extends Task { + + public Todo(String description){ + super(description); + } + + /** + * Override: convert the task to a String in a certain format + */ + @Override + public String toString() { + return "[T]" + super.toString(); + } +} diff --git a/src/main/java/Duke/taskList/TaskList.java b/src/main/java/Duke/taskList/TaskList.java new file mode 100644 index 0000000000..0b32a6baac --- /dev/null +++ b/src/main/java/Duke/taskList/TaskList.java @@ -0,0 +1,47 @@ +package Duke.taskList; + +import Duke.task.Task; + +import java.util.ArrayList; + +/** + * Represents an ArrayList of Task. + */ +public class TaskList { + private static ArrayList taskList = new ArrayList<>(); + + public TaskList() { + } + + public TaskList(ArrayList tasks) { + for(int i=0; i< tasks.size(); i++){ + taskList.add(tasks.get(i)); + } + } + + /** + * add one element to the taskList + */ + public void add(Task oneTask){ + taskList.add(oneTask); + } + + /** + * get the element in the taskList with entered index + * + * @param index the index of the element in taskList that we want. + * @return the element of type Task + */ + public Task get(int index){ + return taskList.get(index); + } + + /** + * remove one element in the taskList with entered index + * + * @param i the index of the element in taskList that we want to remove. + */ + public void remove(int i) { + taskList.remove(i); + } +} diff --git a/src/main/java/Duke/ui/UI.java b/src/main/java/Duke/ui/UI.java new file mode 100644 index 0000000000..6fadc7ca1d --- /dev/null +++ b/src/main/java/Duke/ui/UI.java @@ -0,0 +1,75 @@ +package Duke.ui; + +import java.io.InputStream; +import java.io.PrintStream; +import java.util.Scanner; + +/** + * Represents a ui + * Contains the common constant Strings and methods + */ +public class UI { + private static final String LS = System.lineSeparator(); + public static final int MAX_NUM_TASKS = 100; + public static final String INDENTATION = " "; + public static final String DOUBLEINDENTATION = INDENTATION + " "; + public static final String TRIPLEINDENTATION = DOUBLEINDENTATION + " "; + public static final String HORIZONTALLINE = INDENTATION + + "<------------------------------------------------------------>\n"; + public final String LOGO = TRIPLEINDENTATION + " ____ _ \n" + + TRIPLEINDENTATION + "| _ \\ _ _| | _____ \n" + + TRIPLEINDENTATION + "| | | | | | | |/ / _ \\\n" + + TRIPLEINDENTATION + "| |_| | |_| | < __/\n" + + TRIPLEINDENTATION + "|____/ \\__,_|_|\\_\\___|\n"; + public final String GREET = INDENTATION + " Hello! I'm Duke\n" + + INDENTATION + " What can I do for you? (type\"help\" to get explanation)\n"; + public final String BYE = INDENTATION + " Bye. Hope to see you again soon!\n"; + public final String WRONGMESSAGE = "☹ OOPS!!! I'm sorry, but I don't know what that means :-(\n"; + + private final Scanner in; + private final PrintStream out; + public UI() { + this(System.in, System.out); + } + + public UI(InputStream in, PrintStream out) { + this.in = new Scanner(in); + this.out = out; + } + + /** + * print out the input String + * @param statement The String need to print. + */ + public static void printStatement(String statement) { + System.out.println(HORIZONTALLINE + INDENTATION + "Here is yuqiaoluolong's Duke: \n" + + statement + HORIZONTALLINE); + } + + /** + * print out the Welcome message + */ + public void showWelcome() { + printStatement(TRIPLEINDENTATION + "Hello from\n" + LOGO); + printStatement(GREET); + } + + /** + * Returns what is entered by users as a String variable. + * + * @return inputcommand. + */ + + public String readCommand(){ + String input = in.nextLine(); + return input; + } + + /** + * Show a line. + */ + public void showLine(){ + System.out.printf(LS); + } + +} diff --git a/text-ui-test/ACTUAL.TXT b/text-ui-test/ACTUAL.TXT new file mode 100644 index 0000000000..97e74e8523 --- /dev/null +++ b/text-ui-test/ACTUAL.TXT @@ -0,0 +1,21 @@ + <------------------------------------------------------------> + Here is yuqiaoluolong's Duke: +Hello from + ____ _ +| _ \ _ _| | _____ +| | | | | | | |/ / _ \ +| |_| | |_| | < __/ +|____/ \__,_|_|\_\___| + <------------------------------------------------------------> + + <------------------------------------------------------------> + Here is yuqiaoluolong's Duke: + Hello! I'm Duke + What can I do for you? + <------------------------------------------------------------> + + <------------------------------------------------------------> + Here is yuqiaoluolong's Duke: + Bye. Hope to see you again soon! + <------------------------------------------------------------> + diff --git a/text-ui-test/EXPECTED-UNIX.TXT b/text-ui-test/EXPECTED-UNIX.TXT new file mode 100644 index 0000000000..0b3737bbe0 --- /dev/null +++ b/text-ui-test/EXPECTED-UNIX.TXT @@ -0,0 +1,21 @@ + <------------------------------------------------------------> + Here is yuqiaoluolong's Duke: +Hello from + ____ _ +| _ \ _ _| | _____ +| | | | | | | |/ / _ \ +| |_| | |_| | < __/ +|____/ \__,_|_|\_\___| + <------------------------------------------------------------> + + <------------------------------------------------------------> + Here is yuqiaoluolong's Duke: + Hello! I'm Duke + What can I do for you? + <------------------------------------------------------------> + + <------------------------------------------------------------> + Here is yuqiaoluolong's Duke: + Bye. Hope to see you again soon! + <------------------------------------------------------------> + diff --git a/text-ui-test/EXPECTED.TXT b/text-ui-test/EXPECTED.TXT index 657e74f6e7..0b3737bbe0 100644 --- a/text-ui-test/EXPECTED.TXT +++ b/text-ui-test/EXPECTED.TXT @@ -1,7 +1,21 @@ + <------------------------------------------------------------> + Here is yuqiaoluolong's Duke: Hello from - ____ _ -| _ \ _ _| | _____ + ____ _ +| _ \ _ _| | _____ | | | | | | | |/ / _ \ | |_| | |_| | < __/ |____/ \__,_|_|\_\___| + <------------------------------------------------------------> + + <------------------------------------------------------------> + Here is yuqiaoluolong's Duke: + Hello! I'm Duke + What can I do for you? + <------------------------------------------------------------> + + <------------------------------------------------------------> + Here is yuqiaoluolong's Duke: + Bye. Hope to see you again soon! + <------------------------------------------------------------> diff --git a/text-ui-test/input.txt b/text-ui-test/input.txt index e69de29bb2..b023018cab 100644 --- a/text-ui-test/input.txt +++ b/text-ui-test/input.txt @@ -0,0 +1 @@ +bye diff --git a/text-ui-test/runtest.sh b/text-ui-test/runtest.sh index e169618a34..d47aa28099 100644 --- a/text-ui-test/runtest.sh +++ b/text-ui-test/runtest.sh @@ -13,7 +13,7 @@ then fi # compile the code into the bin folder, terminates if error occurred -if ! javac -cp ../src -Xlint:none -d ../bin ../src/main/java/Duke.java +if ! javac -cp ../src -Xlint:none -d ../bin ../src/main/java/*.java then echo "********** BUILD FAILURE **********" exit 1