Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions data/duke.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
D | 0 | deadline ba | by 6
4 changes: 4 additions & 0 deletions src/main/java/Action.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
public enum Action{
BYE, LIST, CREATE_TODO, CREATE_DEADLINE, CREATE_EVENT,
MARK_AS_DONE, DELETE, CLEAR, FIND, UNKNOWN_ACTION
}
109 changes: 109 additions & 0 deletions src/main/java/Command.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import duke.exception.DukeException;
import duke.exception.IrregularInputException;
import duke.exception.RepeatedCompletionException;
import duke.task.Task;
import duke.task.TaskBank;

import java.util.ArrayList;

public class Command {
public static void perform(String sentence, Action action, Ui ui, Storage storage, TaskBank tb) throws DukeException {
switch (action) {
case UNKNOWN_ACTION:
System.out.printf("☹ OOPS!!! I'm sorry, but I don't know what that means :-( %nPlease try again!%n");
break;
case CLEAR:
clear(tb, storage);
ui.showClearMessage();
storage.exportTasks(tb);
break;
case DELETE:
Task deletedTask = deleteTask(sentence, tb);
ui.showDeleteMessage(deletedTask, tb.getTaskSize());
storage.exportTasks(tb);
break;
case BYE:
bye();
ui.showByeMessage();
break;
case LIST:
ui.showAllTaskMessage();
listAllTask(tb);
break;
case CREATE_TODO:
case CREATE_DEADLINE:
case CREATE_EVENT:
Task createdTask = createTask(action, tb, sentence);
ui.showTaskAddedMessage(createdTask, tb.getTaskSize());
storage.exportTasks(tb);
break;
case MARK_AS_DONE:
Task completedTask = completeTask(tb, sentence);
ui.showCompleteMessage(completedTask);
storage.exportTasks(tb);
break;
case FIND:
TaskBank matchedTaskBank = findTask(sentence, tb);
ui.showFindMessage();
listAllTask(matchedTaskBank);
break;
default:
System.out.println("ERROR IN COMMMAND");
}

}

private static void clear(TaskBank tb, Storage storage) {
tb.clear();
}

private static Task deleteTask(String deleteStament, TaskBank tb) throws IrregularInputException {
int targetIndex = Parser.parseIndex(deleteStament);
Task deletedTask = tb.removeTask(targetIndex);
return deletedTask;
}

private static void bye() {
Duke.terminateDuke();
}

private static void listAllTask(TaskBank tb) {
tb.printList();
}

private static Task createTask(Action action, TaskBank tb, String sentence) {
Task newTask;
String description = Parser.parseDescription(sentence);
switch (action) {
case CREATE_TODO:
newTask = tb.addTodo(description);
break;
case CREATE_DEADLINE:
newTask = tb.addDeadline(description);
break;
case CREATE_EVENT:
newTask = tb.addEvent(description);
break;
default:
newTask = null;
}
return newTask;
}

private static TaskBank findTask(String input, TaskBank givenTaskBank) throws IrregularInputException {
String keywordInput = Parser.parseKeyWord(input);
ArrayList<Task> matchingTasks = TaskBank.findMatchingTask(givenTaskBank, keywordInput);
if (matchingTasks.isEmpty()) {
return null;
} else {
return new TaskBank(matchingTasks);
}
}

private static Task completeTask(TaskBank tb, String sentence) throws RepeatedCompletionException, NumberFormatException, IrregularInputException {
int targetIndex = Parser.parseIndex(sentence);
Task completedTask = tb.searchTask(targetIndex);
completedTask.markAsDone();
return completedTask;
}
}
57 changes: 51 additions & 6 deletions src/main/java/Duke.java
Original file line number Diff line number Diff line change
@@ -1,10 +1,55 @@
import duke.exception.DukeException;
import duke.task.TaskBank;

import java.util.Scanner;

public class Duke {
private Storage storage;
private TaskBank taskBank;
private Ui ui;
private static boolean isTerminating;

/**
* Instantiates Storage, TaskBank and Ui of the programme
* @param filePath the filePath which duke.txt is stored
*/
public Duke(String filePath) {
ui = new Ui();
taskBank = new TaskBank();
storage = new Storage(filePath, taskBank, ui);
}

/**
* Runs Duke program
*/
public void run() {
try (Scanner sc = new Scanner(System.in)) {
String fullCommand;
while (!isTerminating) {
fullCommand = ui.readInput(sc);
ui.printDashLine();
Action action = Parser.parseCommand(fullCommand);
Command.perform(fullCommand, action, ui, storage, taskBank);
ui.printDashLine();
}
} catch (DukeException e) {
ui.showErrorMessage(e);
}
}

public static void main(String[] args) {
String logo = " ____ _ \n"
+ "| _ \\ _ _| | _____ \n"
+ "| | | | | | | |/ / _ \\\n"
+ "| |_| | |_| | < __/\n"
+ "|____/ \\__,_|_|\\_\\___|\n";
System.out.println("Hello from\n" + logo);
isTerminating = false;
new Duke("./data/duke.txt").run();
}

/**
* Changes the variable isTerminating to true
* Used to end the while loop that continuously read user input
*/
public static void terminateDuke() {
isTerminating = true;
}
}



3 changes: 3 additions & 0 deletions src/main/java/META-INF/MANIFEST.MF
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Manifest-Version: 1.0
Main-Class: Duke

86 changes: 86 additions & 0 deletions src/main/java/Parser.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import duke.exception.DukeException;
import duke.exception.EmptyInputException;
import duke.exception.IrregularInputException;
import duke.task.Task;

public class Parser {
/** Parses user input to corresponding command enum based on user input.
*
* @param sentence Raw String taken from user input
* @return an action to be taken by Command
* @throws DukeException including illegal inputs and empty inputs
*/
public static Action parseCommand(String sentence) throws DukeException {
if (sentence.isEmpty()) {
throw new EmptyInputException("Empty input! Try again (o|o)\n");
} else if (sentence.equals("bye")) {
return Action.BYE;
} else if (sentence.equals("list")) {
return Action.LIST;
} else if (sentence.startsWith("done")) {
return Action.MARK_AS_DONE;
} else if (sentence.startsWith("todo")) {
return Action.CREATE_TODO;
} else if (sentence.startsWith("deadline")) {
return Action.CREATE_DEADLINE;
} else if (sentence.startsWith("event")) {
return Action.CREATE_EVENT;
} else if (sentence.startsWith("delete")) {
return Action.DELETE;
} else if (sentence.startsWith("clear")) {
return Action.CLEAR;
} else if (sentence.startsWith("find")) {
return Action.FIND;
} else {
return Action.UNKNOWN_ACTION;
}
}

/** Parse the index of the tasks the user wants to done / delete
*
* @param sentence the raw String from user input of "done" and "delete"
* @return targetIndex,
* @throws IrregularInputException if an int cannot be parsed
*/
public static int parseIndex(String sentence) throws IrregularInputException {
String[] words = sentence.split(" ");
try {
int targetIndex = Integer.parseInt(words[1]) - 1;
return targetIndex;
} catch (NumberFormatException nfe) {
throw new IrregularInputException("Not a number. Try again!");
}
}

/** Parse the keyword of the looks for
*
* @param sentence, raw user input
* @return the keyword that the user looks for
* @throws IrregularInputException if bad keyword or no keyword is keyyed in
*/
public static String parseKeyWord(String sentence) throws IrregularInputException {
try {
int spaceIndex = sentence.indexOf(' ');
if (spaceIndex == -1) {
throw new IndexOutOfBoundsException();
}
String keyWord = sentence.substring(spaceIndex + 1);
return keyWord;
} catch (NumberFormatException nfe) {
throw new IrregularInputException("Bad keyword!");
} catch (IndexOutOfBoundsException ie) {
throw new IrregularInputException("You have not keyed in any keyword");
}
}

/** Parse the description of task from user input
*
* @param sentence raw user input
* @return the description of the task
*/
public static String parseDescription(String sentence) {
int spaceIndex = sentence.indexOf(' ');
String description = sentence.substring(spaceIndex + 1);
return description;
}
}
113 changes: 113 additions & 0 deletions src/main/java/Storage.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import duke.exception.RepeatedCompletionException;
import duke.task.Task;
import duke.task.TaskBank;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Scanner;

public class Storage {
private String filePath;
private File file;

Storage(String filePath, TaskBank tb, Ui ui) {
this.filePath = filePath;
file = new File(filePath);
if (file.exists()) {
loadTasks(tb);
ui.showLoadMessage();
} else {
File directoryPath = new File(filePath);
directoryPath.mkdir();
try {
file.createNewFile();
} catch(IOException e){
System.out.println(e.getMessage());
}
ui.showGreeting();
}
}

/** Exports the content in the TaskBank to duke.txt
*
* @param tb - the TaskBank which tasks are exported from
*/
public void exportTasks(TaskBank tb) {
StringBuffer taskTextString = new StringBuffer();
for (Task task : tb.getTasks()) {
taskTextString.append(task.getTaskType());
taskTextString.append(" | ");
taskTextString.append(task.getDone() ? "1" : "0");
taskTextString.append(" | ");
taskTextString.append(task.describeInFile());
taskTextString.append("\r\n");
}
try {
FileWriter fw = new FileWriter(filePath);
fw.write(taskTextString.toString());
fw.close();
} catch (IOException e) {
System.out.println(e.getMessage());
}
}

/** Loads taks from file to target TaskBank
*
* @param tb TaskBank which tasks are loaded to
*/
public void loadTasks(TaskBank tb) {
File f = new File(this.filePath);
try (Scanner sc = new Scanner(f)) {
while (sc.hasNext()) {
loadTaskLine(sc.nextLine(), tb);
}
} catch (FileNotFoundException e) {
System.out.println("duke.txt is not found");
} catch (IOException e) {
System.out.println(e.getMessage());
}
}

private void loadTaskLine(String taskLine, TaskBank tb) throws IOException {
String taskTypeString = taskLine.substring(0, 1);
int firstDivisor = taskLine.indexOf("|", 1);
int secondDivisor = taskLine.indexOf("|", firstDivisor + 1);
int thirdDivisor = taskLine.indexOf("|", secondDivisor + 1);
if (thirdDivisor == -1) { // todo type
tb.addTodo(taskLine.substring(secondDivisor + 1).trim());
} else {
if (taskTypeString.equals("D")) {
String deadLineInput = taskLine.substring(secondDivisor + 1).trim();
String taskCompletionStatus = taskLine.substring(firstDivisor + 2, secondDivisor).trim();
Task newTask = tb.addDeadline(deadLineInput.replace("| ", "/"));
if (taskCompletionStatus.equals("1")) {
try {
newTask.markAsDone();
} catch (RepeatedCompletionException e) {
// This is left blank intentinally
// as from tasks are generated from
// local files, and will not be completed repeatedly
}
}

} else if (taskTypeString.equals("E")) {
String eventLineInput = taskLine.substring(secondDivisor + 1).trim();
String taskCompletionStatus = taskLine.substring(firstDivisor + 2, secondDivisor).trim();
Task newTask = tb.addEvent(eventLineInput.replace("| ", "/"));
if (taskCompletionStatus.equals("1")) {
try {
newTask.markAsDone();
} catch (RepeatedCompletionException e) {
// This is left blank intentinally
// as from tasks are generated from
// local files, and will not be completed repeatedly
}
}
} else {
throw new IOException("Wrong type from data loader");
}
}
}
}
Loading