diff --git a/README.md b/README.md index 8715d4d9..63d0ad6b 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Duke project template +# Duke.Duke project template This is a project template for a greenfield Java project. It's named after the Java mascot _Duke_. Given below are instructions on how to use it. @@ -13,7 +13,7 @@ Prerequisites: JDK 11, update Intellij to the most recent version. 1. If there are any further prompts, accept the defaults. 1. Configure the project to use **JDK 11** (not other versions) as explained in [here](https://www.jetbrains.com/help/idea/sdk.html#set-up-jdk).
In the same dialog, set the **Project language level** field to the `SDK default` option. -3. After that, locate the `src/main/java/Duke.java` file, right-click it, and choose `Run Duke.main()` (if the code editor is showing compile errors, try restarting the IDE). If the setup is correct, you should see something like the below as the output: +3. After that, locate the `src/main/java/Duke.Duke.java` file, right-click it, and choose `Run Duke.Duke.main()` (if the code editor is showing compile errors, try restarting the IDE). If the setup is correct, you should see something like the below as the output: ``` Hello from ____ _ diff --git a/src/main/java/Duke.java b/src/main/java/Duke.java deleted file mode 100644 index 5d313334..00000000 --- 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 00000000..3ae813b7 --- /dev/null +++ b/src/main/java/Duke/Duke.java @@ -0,0 +1,139 @@ +package Duke; + +import Duke.ExceptionList.*; +import Duke.Storage.Storage; +import Duke.TaskList.*; +import Duke.Ui.Ui; + +import java.util.Scanner; +import java.io.IOException; // Import the IOException class to handle errors +import java.util.regex.Pattern; + +public class Duke { + + private Storage storage; + private TaskList tl; + private Ui ui; + + public Duke(){ + run(); + } + + private Pattern pattern = Pattern.compile("-?\\d+(\\.\\d+)?"); + + public boolean isNumeric(String strNum) { + if (strNum == null) { + return false; + } + return pattern.matcher(strNum).matches(); + } + + public void run() { + ui = new Ui(); + ui.showStartMessage(); + ui.printBreak(); + storage = new Storage(); + try { + tl = new TaskList(storage.load()); + } + catch (DukeException | IOException e) { + ui.showLoadingError(); + tl = new TaskList(); + } + String line, desc, desc2, s1, s2; + while (true) { + Scanner in = new Scanner(System.in); + line = in.nextLine(); + try { + if (!line.isEmpty()) { + desc2 = ""; + if (line.contains(" ")) { + + String[] input = line.split(" ", 2); + desc = input[0]; + desc2 = input[1]; + } else { + desc = line; + } + if (line.equalsIgnoreCase("bye")) { + storage.saveTask(tl); + break; + } + if (line.equalsIgnoreCase("list")) { + ui.printBreak(); + tl.printTaskList(); + ui.printBreak(); + } else if (desc.equalsIgnoreCase("done")) { + if (desc2.isEmpty() || !isNumeric(desc2)){ + throw new CommandNotFoundException("Please enter a number."); + }else if (Integer.parseInt(desc2) > tl.getSize() || Integer.parseInt(desc2) <= 0){ + throw new CommandNotFoundException("Sorry, Please enter a legit number."); + } + ui.printBreak(); + int x = Integer.parseInt(desc2); + tl.setDoneStatus(x); + ui.printBreak(); + } else if (desc.equalsIgnoreCase("delete")) { + if (tl.getSize()==0){ + throw new NoListFoundException("Sorry, I am unable to delete any task because no task is found."); + } + if (desc2.isEmpty()|| !isNumeric(desc2)){ + throw new CommandNotFoundException("Please enter a number."); + }else if (Integer.parseInt(desc2) > tl.getSize() || Integer.parseInt(desc2) <= 0){ + throw new CommandNotFoundException("Sorry, Please enter a legit number."); + } + ui.printBreak(); + int x = Integer.parseInt(desc2); + System.out.println("I've deleted this task entered: "); + tl.deleteTask(x); + ui.printBreak(); + } else if (desc.equalsIgnoreCase("deadline")) { + if (desc2.isEmpty()){ + throw new deadlineNotFoundException("Sorry, there cannot be any empty deadline task."); + } + ui.printBreak(); + tl.addTask(desc,desc2,false); + System.out.println("Got it. I've added this task: "); + System.out.println(tl.getLastAddedTask()); + ui.printTotalTask(tl.getSize()); + ui.printBreak(); + } else if (desc.equalsIgnoreCase("event")) { + if (desc2.isEmpty()){ + throw new eventNotFoundException("Sorry, there cannot be any empty event task."); + } + ui.printBreak(); + tl.addTask(desc,desc2,false); + System.out.println("Got it. I've added this task: "); + System.out.println(tl.getLastAddedTask()); + ui.printTotalTask(tl.getSize()); + ui.printBreak(); + } else if (desc.equalsIgnoreCase("todo")) { + if (desc2.isEmpty()){ + throw new toDoNotFoundException("Sorry, there cannot be any empty todo task."); + } + ui.printBreak(); + tl.addTask(desc,desc2,false); + System.out.println("Got it. I've added this task: "); + System.out.println(tl.getLastAddedTask()); + ui.printTotalTask(tl.getSize()); + ui.printBreak(); + } else { + throw new CommandNotFoundException("Sorry, I am unable to handle your request."); + } + } + } catch (toDoNotFoundException | CommandNotFoundException | NoListFoundException | deadlineNotFoundException | eventNotFoundException e ) { + ui.printBreak(); + System.out.println(e.getMessage()); + ui.printBreak(); + continue; + } + } + ui.printBreak(); + ui.printBye(); + ui.printBreak(); + } + + public static void main(String[] args) { + new Duke(); + } +} diff --git a/src/main/java/Duke/ExceptionList/CommandNotFoundException.java b/src/main/java/Duke/ExceptionList/CommandNotFoundException.java new file mode 100644 index 00000000..7d4eb33a --- /dev/null +++ b/src/main/java/Duke/ExceptionList/CommandNotFoundException.java @@ -0,0 +1,11 @@ +package Duke.ExceptionList; + +public class CommandNotFoundException extends Exception{ + //no other code needed + public CommandNotFoundException(String message) { + super(message); + } + public CommandNotFoundException(){ + super(); + } +} diff --git a/src/main/java/Duke/ExceptionList/DukeException.java b/src/main/java/Duke/ExceptionList/DukeException.java new file mode 100644 index 00000000..09a0d5b1 --- /dev/null +++ b/src/main/java/Duke/ExceptionList/DukeException.java @@ -0,0 +1,10 @@ +package Duke.ExceptionList; + +public class DukeException extends Exception { + public DukeException(String message) { + super(message); + } + public DukeException(){ + super(); + } +} diff --git a/src/main/java/Duke/ExceptionList/NoListFoundException.java b/src/main/java/Duke/ExceptionList/NoListFoundException.java new file mode 100644 index 00000000..1d4be88d --- /dev/null +++ b/src/main/java/Duke/ExceptionList/NoListFoundException.java @@ -0,0 +1,12 @@ +package Duke.ExceptionList; + +public class NoListFoundException extends Exception { + //no other code needed + public NoListFoundException(String message) { + super(message); + } + + public NoListFoundException() { + super(); + } +} diff --git a/src/main/java/Duke/ExceptionList/deadlineNotFoundException.java b/src/main/java/Duke/ExceptionList/deadlineNotFoundException.java new file mode 100644 index 00000000..9cab566c --- /dev/null +++ b/src/main/java/Duke/ExceptionList/deadlineNotFoundException.java @@ -0,0 +1,11 @@ +package Duke.ExceptionList; + +public class deadlineNotFoundException extends Exception{ + //no other code needed + public deadlineNotFoundException(String message) { + super(message); + } + public deadlineNotFoundException(){ + super(); + } +} diff --git a/src/main/java/Duke/ExceptionList/eventNotFoundException.java b/src/main/java/Duke/ExceptionList/eventNotFoundException.java new file mode 100644 index 00000000..baf9a3fe --- /dev/null +++ b/src/main/java/Duke/ExceptionList/eventNotFoundException.java @@ -0,0 +1,10 @@ +package Duke.ExceptionList; + +public class eventNotFoundException extends Exception{ + public eventNotFoundException(String message) { + super(message); + } + public eventNotFoundException(){ + super(); + } +} diff --git a/src/main/java/Duke/ExceptionList/toDoNotFoundException.java b/src/main/java/Duke/ExceptionList/toDoNotFoundException.java new file mode 100644 index 00000000..73cc06ee --- /dev/null +++ b/src/main/java/Duke/ExceptionList/toDoNotFoundException.java @@ -0,0 +1,11 @@ +package Duke.ExceptionList; + +public class toDoNotFoundException extends Exception{ + //no other code needed + public toDoNotFoundException(String message) { + super(message); + } + public toDoNotFoundException(){ + super(); + } +} diff --git a/src/main/java/Duke/Storage/Storage.java b/src/main/java/Duke/Storage/Storage.java new file mode 100644 index 00000000..5395bd7d --- /dev/null +++ b/src/main/java/Duke/Storage/Storage.java @@ -0,0 +1,79 @@ +package Duke.Storage; + +import java.io.FileWriter; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +import Duke.TaskList.*; +import java.util.ArrayList; + +public class Storage { + protected final String DEFAULT_STORAGE_FILEPATH = "duke.txt"; + protected final String home = System.getProperty("user.home"); + private String filePath = DEFAULT_STORAGE_FILEPATH; + protected Path path; + + public Storage(){ + filePath = DEFAULT_STORAGE_FILEPATH; + path = Paths.get(home, filePath); + } + public Storage(String filepath) throws IOException { + this.filePath = filePath; + path = Paths.get(home, filePath); + if (!isValidPath(path)) {} + //check if file exist + isPathExist(); + } + + private static boolean isValidPath(Path filePath) { + return filePath.toString().endsWith(".txt"); + } + + private void isPathExist() throws IOException { + Path path = Paths.get(home, filePath); + // check if the directory and file exists, else create + if (!Files.exists(path)) { + Files.createDirectory(Paths.get(home,"data")); + Files.createFile(path); + } + } + /** + * This method save all the tasks in the ArrayList of TaskLists. + * + * @param tasks ArrayList of Task in TaskLists. + * */ + public void saveTask(TaskList tasks){ + path = Paths.get(home, "data",DEFAULT_STORAGE_FILEPATH); + + // start saving task + String content = ""; + ArrayList save = tasks.getTaskList(); + for (Task task : save) + content += task.saveTask() + System.lineSeparator(); + //System.out.println(content); + try{ + writeToFile(path+"",content); + }catch(IOException e){ + e.printStackTrace(); + } + } + /** + * This method writes all the text into the file. + * + * @param filePath Path of the file to be written. + * @param text String of the text to be stored in the file. + * */ + private void writeToFile(String filePath, String text) throws IOException { + FileWriter fw = new FileWriter(filePath); + fw.write(text); + fw.close(); + } + + public String load() throws IOException { + String path = home+"\\data\\"+filePath; + //return (File) Files.readAllLines(Path.of(path)); + return path; // create a File for the given file path + } +} diff --git a/src/main/java/Duke/TaskList/Deadline.java b/src/main/java/Duke/TaskList/Deadline.java new file mode 100644 index 00000000..4eb36ef1 --- /dev/null +++ b/src/main/java/Duke/TaskList/Deadline.java @@ -0,0 +1,18 @@ +package Duke.TaskList; + +public class Deadline extends Task { + protected String by; + + public Deadline(String description, String by) { + super(description); + this.by = by; + } + + @Override + public String toString() { + return "[D]" + super.toString() + " (by: " + by + ")"; + } + + @Override + public String saveTask(){ return "D|" + super.saveTask() + "|" + by;} +} diff --git a/src/main/java/Duke/TaskList/Event.java b/src/main/java/Duke/TaskList/Event.java new file mode 100644 index 00000000..75945739 --- /dev/null +++ b/src/main/java/Duke/TaskList/Event.java @@ -0,0 +1,19 @@ +package Duke.TaskList; + +public class Event extends Task{ + protected String at; + + public Event(String description, String at) { + super(description); + this.at = at; + } + + @Override + public String toString() { + return "[E]" + super.toString() + " (at: " + at + ")"; + } + + @Override + public String saveTask(){ return "E|" + super.saveTask() + "|" + at;} + +} \ No newline at end of file diff --git a/src/main/java/Duke/TaskList/Task.java b/src/main/java/Duke/TaskList/Task.java new file mode 100644 index 00000000..02f398cf --- /dev/null +++ b/src/main/java/Duke/TaskList/Task.java @@ -0,0 +1,54 @@ +package Duke.TaskList; + +public class Task { + protected String description; + protected boolean isDone; + + public Task(String description) { + this.description = description; + this.isDone = false; + } + public Task(String description,boolean isDone){ + this.description = description; + this.isDone = isDone; + } + + public String getStatusIcon() { + return (isDone ? "X" : " "); // mark done task with X + } + + public String getStatusDone(){ + return (isDone ? "1" : "0"); // mark done task with 1 + } + + public void setDone(boolean done){ + this.isDone = done; + } + + public String getDescription(){ + return description; + } + + public void setDescription(String description) { + this.description = description; + } + /** + * This method returns the object in String format. + * + * @return the object in string format + * */ + public String toString(){ + String print = "[" + getStatusIcon()+"] " + getDescription(); + return print; + } + /** + * This method return the object in String format. + * + * @return the object in string format for the task to be saved. + * */ + public String saveTask(){ + String save = getStatusDone() + "|" + getDescription(); + return save; + } + +} diff --git a/src/main/java/Duke/TaskList/TaskList.java b/src/main/java/Duke/TaskList/TaskList.java new file mode 100644 index 00000000..099e6cb2 --- /dev/null +++ b/src/main/java/Duke/TaskList/TaskList.java @@ -0,0 +1,133 @@ +package Duke.TaskList; + +import Duke.ExceptionList.*; + +import java.io.*; +import java.util.ArrayList; + + +public class TaskList { + ArrayList taskLists = new ArrayList(); + public TaskList() { + } + public TaskList(String f) throws DukeException { + //parse the String from the text file then use it to inside into the DB + try (BufferedReader br = new BufferedReader(new FileReader(f))) { + String line; + while ((line = br.readLine()) != null) { + // process the line. + addFileTask(line); + } + } catch (FileNotFoundException e) { + throw new DukeException("File is not found. Please, make sure you entered the correct path."); + } catch (toDoNotFoundException | eventNotFoundException | deadlineNotFoundException |IOException e) { + e.printStackTrace(); + } + } + + public void addFileTask(String str) throws toDoNotFoundException, eventNotFoundException, deadlineNotFoundException { + String[] input = str.split("\\|", 2); + String s1 = input[0]; + String s2 = input[1]; + addTask(s1, s2, true); + } + + /** + * Adds task into the ArrayList of Tasks object. The cmd has been passed through validation thus unwanted commands + * will not be written into the list. + * + * @param cmd the given command by the user + * @param description details on the task listed by user + * @param file checks if it is from a loaded file or an input string + * */ + public void addTask(String cmd, String description, boolean file) throws toDoNotFoundException, eventNotFoundException, deadlineNotFoundException { + if (cmd.equalsIgnoreCase("todo") || cmd.equalsIgnoreCase("T")) { + if (description.isEmpty()) { + throw new toDoNotFoundException("Sorry, there cannot be any empty todo task."); + } + if (file) { + String[] input = description.split("\\|", 2); + String s1 = input[0]; + String s2 = input[1]; + taskLists.add(new ToDo(s2)); + if (s1.equals("1")) { + taskLists.get(taskLists.size() - 1).setDone(true); + } + } else taskLists.add(new ToDo(description)); + + } else if (cmd.equalsIgnoreCase("deadline") || cmd.equalsIgnoreCase("D")) { + if (description.isEmpty()) { + throw new deadlineNotFoundException("Sorry, there cannot be any empty deadline task."); + } + if (file) { + String[] input = description.split("\\|", 3); + String s1 = input[0]; + String s2 = input[1]; + String s3 = input[2]; + taskLists.add(new Deadline(s2, s3)); + if (s1.equals("1")) { + taskLists.get(taskLists.size() - 1).setDone(true); + } + } else { + String[] input = description.split("/by ", 2); + String s1 = input[0]; + String s2 = input[1]; + taskLists.add(new Deadline(s1, s2)); + } + + } else if (cmd.equalsIgnoreCase("event") || cmd.equalsIgnoreCase("E")) { + if (description.isEmpty()) { + throw new eventNotFoundException("Sorry, there cannot be any empty event task."); + } + if (file) { + String[] input = description.split("\\|", 3); + String s1 = input[0]; + String s2 = input[1]; + String s3 = input[2]; + taskLists.add(new Event(s2, s3)); + if (s1.equals("1")) { + taskLists.get(taskLists.size() - 1).setDone(true); + } + } else { + String[] input = description.split("/at ", 2); + String s1 = input[0]; + String s2 = input[1]; + taskLists.add(new Event(s1, s2)); + } + } + } + + public String getLastAddedTask() { + return taskLists.get(taskLists.size() - 1).toString(); + } + /** + * User input will perform a deleting of the specific task from the ArrayList of Tasks object. + * + * @param x the given position of the list given by the user + * */ + public void deleteTask(int x) { + System.out.println(taskLists.get(x - 1).toString()); + taskLists.remove(x - 1); + } + + public void printTaskList() { + System.out.println("Here are the tasks in your list: "); + for (int i = 0; i < taskLists.size(); i++) { + System.out.println(taskLists.get(i).toString()); + } + } + + public void setDoneStatus(int x) { + taskLists.get(x - 1).setDone(true); + System.out.println("Nice! I've marked this task as done: "); + System.out.println(taskLists.get(x - 1).toString()); + } + + public int getSize() { + return taskLists.size(); + } + + public ArrayList getTaskList() { + return taskLists; + } +} diff --git a/src/main/java/Duke/TaskList/ToDo.java b/src/main/java/Duke/TaskList/ToDo.java new file mode 100644 index 00000000..afdfe427 --- /dev/null +++ b/src/main/java/Duke/TaskList/ToDo.java @@ -0,0 +1,16 @@ +package Duke.TaskList; + +public class ToDo extends Task{ + + public ToDo(String description) { + super(description); + } + + @Override + public String toString() { + return "[T]" + super.toString(); + } + + @Override + public String saveTask(){ return "T|" + super.saveTask();} +} \ No newline at end of file diff --git a/src/main/java/Duke/TaskList/taskToDo.java b/src/main/java/Duke/TaskList/taskToDo.java new file mode 100644 index 00000000..39b9fa82 --- /dev/null +++ b/src/main/java/Duke/TaskList/taskToDo.java @@ -0,0 +1,5 @@ +package Duke.TaskList; + +public enum taskToDo { + todo,deadline,list,event,done,delete +} diff --git a/src/main/java/Duke/Ui/Ui.java b/src/main/java/Duke/Ui/Ui.java new file mode 100644 index 00000000..243c2a69 --- /dev/null +++ b/src/main/java/Duke/Ui/Ui.java @@ -0,0 +1,46 @@ +package Duke.Ui; + +public class Ui { + private final String logo = " ____ _ \n" + + "| _ \\ _ _| | _____ \n" + + "| | | | | | | |/ / _ \\\n" + + "| |_| | |_| | < __/\n" + + "|____/ \\__,_|_|\\_\\___|\n"; + + private final String logoMessage = logo + "\nHello! I'm Duke.Duke. \nWhat can I do for you?"; + + private final String breakLines = "____________________________________________________________"; + + private String print(){ + return logoMessage; + } + + //Printing divider + public void printBreak() { + System.out.println(breakLines); + } + + //Printing goodbye message + public void printBye() { + System.out.println("Bye. Hope to see you again soon!"); + } + + /** + * Listing the total number of Task object inside the TaskLists. + * + * @param counter the number of task in the TaskLists + * */ + public void printTotalTask(int counter) { + System.out.println("Now you have " + counter + " tasks in the list."); + } + + //Printing start message + public void showStartMessage(){ + System.out.println(print()); + } + + //Printing Loading Error message + public void showLoadingError() { + System.out.println("Sorry file is not found. We will save a new copy."); + } +} diff --git a/src/main/java/META-INF/MANIFEST.MF b/src/main/java/META-INF/MANIFEST.MF new file mode 100644 index 00000000..5699c741 --- /dev/null +++ b/src/main/java/META-INF/MANIFEST.MF @@ -0,0 +1,3 @@ +Manifest-Version: 1.0 +Main-Class: Duke.Duke + diff --git a/text-ui-test/runtest.bat b/text-ui-test/runtest.bat index 08737446..cecfdb11 100644 --- a/text-ui-test/runtest.bat +++ b/text-ui-test/runtest.bat @@ -15,7 +15,7 @@ IF ERRORLEVEL 1 ( REM no error here, errorlevel == 0 REM run the program, feed commands from input.txt file and redirect the output to the ACTUAL.TXT -java -classpath ..\bin Duke < input.txt > ACTUAL.TXT +java -classpath ..\bin Duke.Duke < input.txt > ACTUAL.TXT REM compare the output to the expected output FC ACTUAL.TXT EXPECTED.TXT