-
Notifications
You must be signed in to change notification settings - Fork 193
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Izdiyad] iP #184
base: master
Are you sure you want to change the base?
[Izdiyad] iP #184
Changes from 23 commits
0ae4476
f1e5ced
3414427
73e3f7f
3422f00
875b0d9
8ee920b
d053ba6
8ffc16c
87960ac
01d5ff9
b95926a
eb20187
d2b41c7
a808481
cd1002c
67b4f6d
5d454d8
236ed11
6f88ba0
873adc0
f36e778
b03f960
cac1c93
2a1bdf2
5fb40cf
8a45ea6
1c71c8a
acf3a4d
7a0c133
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
T | 0 | buy McD | ||
T | 1 | iP submission | ||
T | 0 | match |
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
Manifest-Version: 1.0 | ||
Main-Class: duke.Duke | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
package duke; | ||
|
||
import duke.command.Command; | ||
import duke.exceptions.DukeException; | ||
|
||
public class Duke { | ||
|
||
private Ui ui; | ||
private Storage storage; | ||
private Parser parser; | ||
private TaskList tasks; | ||
|
||
/** | ||
* Duke constructor which initialises the User Interface(UI), Storage, Parser and TaskList. | ||
* @param filePath file path of duke_data, which stores data of Duke | ||
*/ | ||
public Duke(String filePath) { | ||
ui = new Ui(); | ||
storage = new Storage(filePath, ui); | ||
|
||
try { | ||
tasks = new TaskList(storage.readFile()); | ||
} catch (DukeException e) { | ||
ui.printWithLines(e.toString()); | ||
tasks = new TaskList(); | ||
} | ||
|
||
parser = new Parser(ui, storage, tasks); | ||
} | ||
|
||
/** Reads user command and executes it until the exit command is entered by the user. */ | ||
public void run() { | ||
ui.printHelloMessage(); | ||
|
||
String input; | ||
|
||
input = ui.getUserCommand(); | ||
|
||
while (true) { | ||
try { | ||
Command userCommand = parser.selectCommand(input); | ||
userCommand.execute(); | ||
storage.saveFile(tasks); | ||
} catch (DukeException e) { | ||
ui.printWithLines(e.getMessage()); | ||
} | ||
|
||
// Gets the next command entered | ||
input = ui.getUserCommand(); | ||
} | ||
} | ||
|
||
public static void main(String[] args) { | ||
new Duke("duke_data/store.txt").run(); | ||
} | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,171 @@ | ||
package duke; | ||
|
||
import duke.command.*; | ||
import duke.tasks.Task; | ||
import duke.tasks.ToDo; | ||
import duke.tasks.Deadline; | ||
import duke.tasks.Event; | ||
import duke.exceptions.DukeException; | ||
|
||
public class Parser { | ||
|
||
protected Ui ui; | ||
protected Storage storage; | ||
protected TaskList tasks; | ||
Task newTask; | ||
|
||
public static final String TODO = "todo"; | ||
public static final String TODO_EXCEPTION = "Description of todo cannot be empty."; | ||
public static final String DEADLINE = "deadline"; | ||
public static final String DEADLINE_EXCEPTION = "Deadline task requires a /by property."; | ||
public static final String DEADLINE_EMPTY_DESCRIPTION = " /by property cannot be empty."; | ||
public static final String EVENT = "event"; | ||
public static final String EVENT_EXCEPTION = "Event task requires an /at property."; | ||
public static final String EVENT_EMPTY_DESCRIPTION = " /at property cannot be empty."; | ||
public static final String INVALID_TASK_TYPE = "Invalid task type. Try a todo, deadline or event."; | ||
public static final String LIST = "list"; | ||
public static final String DONE = "done"; | ||
public static final String FIND = "find"; | ||
public static final String DELETE = "delete"; | ||
public static final String BYE = "bye"; | ||
public static final String INVALID_INPUT = "Your input is invalid."; | ||
|
||
|
||
/** | ||
* Parser constructor with its associated UI, Storage and TaskList | ||
* @param ui UI to be used by Parser | ||
* @param storage Storage to be used by Parser | ||
* @param tasks TaskList to be used by Parser | ||
*/ | ||
public Parser(Ui ui, Storage storage, TaskList tasks) { | ||
this.ui = ui; | ||
this.storage = storage; | ||
this.tasks = tasks; | ||
} | ||
|
||
/** | ||
* Parses user's raw input and initiates a new task to be added according to its type. | ||
* @param input string of user's raw input | ||
*/ | ||
public void trimInput(String input) { | ||
|
||
if (input.startsWith(DEADLINE)) { | ||
String description = | ||
input.substring(0, input.indexOf("/by")).replaceFirst(DEADLINE, "").trim(); | ||
String by = input.substring(input.indexOf("/by") + "/by".length()).trim(); | ||
newTask = new Deadline(description, by); | ||
|
||
} else if (input.startsWith(EVENT)) { | ||
String description = | ||
input.substring(0, input.indexOf("/at")).replaceFirst(EVENT, "").trim(); | ||
String at = input.substring(input.indexOf("/at") + "/at".length()).trim(); | ||
newTask = new Event(description, at); | ||
|
||
} else if (input.startsWith(TODO)) { | ||
String description = input.replaceFirst(TODO, "").trim(); | ||
newTask = new ToDo(description); | ||
} | ||
} | ||
|
||
/** | ||
* Dissects user's raw input and returns an appropriate AddCommand object. | ||
* @param input string of user's raw input | ||
* @return an appropriate AddCommand object | ||
* @throws DukeException | ||
*/ | ||
public Command addTask(String input) throws DukeException { | ||
|
||
if (input.startsWith(TODO)) { | ||
if (input.substring(4).isEmpty()) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 4 seems to be a Magic Number |
||
throw new DukeException(TODO_EXCEPTION); | ||
} | ||
trimInput(input); | ||
|
||
} else if (input.startsWith(DEADLINE)) { | ||
if (!input.contains("/by")) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You can also consider making |
||
throw new DukeException(DEADLINE_EXCEPTION); | ||
} else if (input.substring(input.indexOf("/by") + "/by".length()).isEmpty()) { | ||
throw new DukeException(DEADLINE_EMPTY_DESCRIPTION); | ||
} | ||
trimInput(input); | ||
|
||
} else if (input.startsWith(EVENT)) { | ||
if (!input.contains("/at")) { | ||
throw new DukeException(EVENT_EXCEPTION); | ||
} else if (input.substring(input.indexOf("/at") + "/at".length()).isEmpty()) { | ||
throw new DukeException(EVENT_EMPTY_DESCRIPTION); | ||
} | ||
trimInput(input); | ||
|
||
} else { | ||
throw new DukeException(INVALID_TASK_TYPE); | ||
} | ||
|
||
return new AddCommand(ui, tasks, newTask); | ||
} | ||
|
||
/** | ||
* Dissects user's raw input and returns an appropriate SetDoneCommand | ||
* @param input string of user's raw input | ||
* @return a SetDoneCommand object | ||
*/ | ||
public Command markTaskDone(String input) { | ||
int taskNumber = Integer.parseInt(input.replace("done ", "")) - 1; | ||
|
||
return new SetDoneCommand(ui, tasks, taskNumber); | ||
} | ||
|
||
/** | ||
* Dissects user's raw input and returns an appropriate DeleteCommand | ||
* @param input string of user's raw input | ||
* @return a DeleteCommand object | ||
*/ | ||
public Command deleteTask(String input) { | ||
int taskNumber = Integer.parseInt(input.replaceFirst("delete", "").trim()) - 1; | ||
|
||
return new DeleteCommand(ui, tasks, taskNumber); | ||
} | ||
|
||
/** | ||
* Dissects user's raw input beforehand and then calls appropriate command methods. | ||
* @param input string of user's raw input | ||
* @return a Command object | ||
* @throws DukeException | ||
*/ | ||
public Command findTask(String input) { | ||
String keyword = input.replaceFirst("find", "").trim(); | ||
|
||
return new FindCommand(ui, tasks, keyword); | ||
} | ||
|
||
public Command selectCommand(String input) throws DukeException { | ||
|
||
String trimmedInput = input.trim().split(" ")[0]; | ||
Command commandFromInput = null; | ||
|
||
switch (trimmedInput){ | ||
case TODO: case DEADLINE: case EVENT: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. When you have multiple cases and you want the control to cascade down, you can still follow the same recommended code style to have each case in a new line. |
||
commandFromInput = addTask(input); | ||
break; | ||
case LIST: | ||
commandFromInput = new ListCommand(ui, tasks); | ||
break; | ||
case DONE: | ||
commandFromInput = markTaskDone(input); | ||
break; | ||
case FIND: | ||
commandFromInput = findTask(input); | ||
break; | ||
case DELETE: | ||
commandFromInput = deleteTask(input); | ||
break; | ||
case BYE: | ||
ui.printByeMessage(); | ||
System.exit(0); | ||
break; | ||
default: | ||
throw new DukeException(INVALID_INPUT); | ||
} | ||
return commandFromInput; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
package duke; | ||
|
||
import duke.tasks.Task; | ||
import duke.tasks.ToDo; | ||
import duke.tasks.Deadline; | ||
import duke.tasks.Event; | ||
import duke.exceptions.DukeException; | ||
|
||
import java.io.File; | ||
import java.io.FileWriter; | ||
import java.io.IOException; | ||
import java.io.FileNotFoundException; | ||
import java.nio.file.Files; | ||
import java.nio.file.Path; | ||
import java.nio.file.Paths; | ||
|
||
import java.util.Scanner; | ||
|
||
public class Storage { | ||
|
||
protected Ui ui; | ||
private final Path FILE_PATH; | ||
|
||
/** | ||
* Storage constructor with its associated UI and file path. | ||
* @param filePath file path to be used by Storage | ||
* @param ui UI to be used by Storage | ||
*/ | ||
public Storage(String filePath, Ui ui) { | ||
this.ui = ui; | ||
FILE_PATH = Paths.get("duke_data/duke.txt"); | ||
} | ||
|
||
/** | ||
* Reads storage file, decodes encoded TaskList written in that file. | ||
* @return a TaskList object | ||
* @throws DukeException | ||
*/ | ||
public TaskList readFile() throws DukeException { | ||
TaskList readTasks = new TaskList(100); | ||
|
||
try { | ||
File f = new File(FILE_PATH.toString()); | ||
Scanner s = new Scanner(f); | ||
|
||
while (s.hasNext()) { | ||
Task t; | ||
String line = s.nextLine(); | ||
String[] inputArray = line.split(" [ | ] "); | ||
|
||
switch (inputArray[0]) { | ||
case "T": | ||
t = new ToDo(inputArray[2]); | ||
break; | ||
case "D": | ||
t = new Deadline(inputArray[2], inputArray[3]); | ||
break; | ||
case "E": | ||
t = new Event(inputArray[2], inputArray[3]); | ||
break; | ||
default: | ||
throw new DukeException("Error while parsing"); | ||
} | ||
|
||
if (inputArray[1].equals("1")) { | ||
t.setDone(); | ||
} | ||
|
||
readTasks.add(t); | ||
} | ||
|
||
return readTasks; | ||
|
||
} catch (FileNotFoundException e) { | ||
try { | ||
createFile(); | ||
} catch (IOException o) { | ||
throw new DukeException("Error while reading file."); | ||
} | ||
} | ||
return null; | ||
} | ||
|
||
/** | ||
* Encodes and saves a TaskList. Overwrites previously saved file | ||
* @param tasks a list of tasks to be encoded and saved | ||
* @throws DukeException | ||
*/ | ||
public void saveFile(TaskList tasks) throws DukeException { | ||
try { | ||
FileWriter fw = new FileWriter(FILE_PATH.toString()); | ||
String newText = ""; | ||
|
||
for (int i = 0; i < tasks.size(); i++) { | ||
Task t = tasks.get(i); | ||
newText = newText.concat(t.encode()); | ||
newText = newText.concat("\n"); | ||
} | ||
|
||
fw.write(newText); | ||
fw.close(); | ||
|
||
} catch (IOException e) { | ||
throw new DukeException("IO exception"); | ||
} | ||
} | ||
|
||
/** | ||
* Creates a storage file if there is none existing. Also creates a directory if path is non-existing. | ||
* @throws IOException | ||
*/ | ||
public void createFile() throws IOException { | ||
// from https://stackoverflow.com/questions/2833853/create-whole-path-automatically-when-writing-to-a-new-file | ||
Files.createDirectories(FILE_PATH.getParent()); | ||
Files.createFile(FILE_PATH); | ||
ui.printWithLines("New storage file created."); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The code is well structured and easy to understand what the code is doing here. Hence, this comment seems redundant. You may want to consider removing it :)