-
Notifications
You must be signed in to change notification settings - Fork 228
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
[Wang Haochen] iP #233
base: master
Are you sure you want to change the base?
[Wang Haochen] iP #233
Changes from 28 commits
6050b37
6fd5092
ca4f2a4
ebb2b49
3c4e80a
08bc173
1866354
5d2bbdf
b379cc6
69be918
bea5c35
7c3f602
71eadd9
76c1d33
9486102
5ba35ea
47b74a9
5c39d4d
9680dfc
25ce9bd
48dfc42
d0de061
bc65901
d28682b
1a9093c
4edb089
1a7719c
1ffe0ca
42deda2
b58f80f
e080cee
fd8f275
6fd6bf1
a52b97c
936f6f5
7ebbaf0
876ffb8
bcbbaae
9578301
eab7755
b103639
06a43e4
0c74975
9f94d03
ae63913
06aa20c
8c9dbbe
2a00b34
681223c
90a57a0
99bfd80
4d85d0e
ac4fe40
b6b9c47
57a2dcb
aa624ef
9fe8ade
3b59951
1780df0
b79bd72
d658f1b
1e445e4
49dba24
b6a3ba7
e2e117a
fbbc8f2
c5b8fde
7313a0c
d4f7e8c
60ae821
a064a92
d788d2d
ae967ca
58be175
dd3f9d2
20d6e32
bb0fd9d
f0e8833
9fca0a1
57c78cb
7b00d84
e6fffed
20bae0b
0d7ac25
6e65908
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
Manifest-Version: 1.0 | ||
Main-Class: ssagit.Duke | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
package ssagit; | ||
|
||
import java.util.Locale; | ||
import java.time.format.DateTimeFormatter; | ||
|
||
import ssagit.parser.Parser; | ||
import ssagit.storage.Storage; | ||
import ssagit.ui.ConsoleUI; | ||
import ssagit.taskclass.*; | ||
import ssagit.datevalidator.DateValidator; | ||
import ssagit.datevalidator.DateValidatorLocalDate; | ||
|
||
public class Duke { | ||
|
||
public static void main(String[] args) { | ||
/** Create validator for dates */ | ||
DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("d/MM/yyyy HHmm", Locale.ENGLISH); | ||
DateValidator validator = new DateValidatorLocalDate(dateFormatter); | ||
/** Handler for all UI stuff. */ | ||
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. I think adding an empty line between these logical blocks would help readability |
||
ConsoleUI ui = new ConsoleUI(System.in); | ||
ui.introduction(); | ||
/** Parser for user inputs */ | ||
Parser parser = new Parser(ui, validator); | ||
/** Create tasks */ | ||
Task[] tasks = new Task[100]; | ||
/** Initialize file IO */ | ||
Storage storage = new Storage("./ssagit/data/taskList.txt"); | ||
int taskIterator = storage.readTaskListToArray(tasks, validator); | ||
|
||
while (parser.getIsBye() == false) { | ||
parser.parseInput(tasks, taskIterator); | ||
} | ||
storage.writeTasks(tasks); | ||
ui.bye(); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
restore branch-Level-9 (from Level-9) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
deadline | not done | return book | 2/12/2019 1800 | ||
deadline | not done | return book | 2/12/2019 1800 | ||
todo | not done | 1 | ||
todo | not done | 2 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
todo | not done | a | ||
todo | not done | b | ||
todo | not done | c | ||
deadline | not done | return book | 2/12/2019 1800 | ||
deadline | not done | return book | 2/12/2019 1800 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
package ssagit.datevalidator; | ||
|
||
/** | ||
* Interface to validate String date input | ||
*/ | ||
public interface DateValidator { | ||
boolean isValid(String dateStr); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
package ssagit.datevalidator; | ||
|
||
import java.time.LocalDate; | ||
import java.time.LocalDateTime; | ||
import java.time.LocalTime; | ||
import java.time.format.DateTimeFormatter; | ||
import java.time.format.DateTimeParseException; | ||
|
||
public class DateValidatorLocalDate implements DateValidator { | ||
private DateTimeFormatter dateFormatter; | ||
|
||
/** | ||
* DateValidatorLocalDate Constructor. | ||
* @param df {@code dateFormatter} object | ||
*/ | ||
public DateValidatorLocalDate(DateTimeFormatter df) { | ||
dateFormatter = df; | ||
} | ||
|
||
@Override | ||
/** | ||
* Checks if date given is valid, in the following order: | ||
* date - time - locale; | ||
* If all 3 fails, return with invalid, otherwise return results. | ||
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. |
||
*/ | ||
public boolean isValid(String dateStr) { | ||
LocalDateTime ldt = null; | ||
|
||
try { | ||
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. This is really hard to read, why do you need to catch the same kind of exception in so many different places? Maybe there's a way to have only one try-catch block? |
||
ldt = LocalDateTime.parse(dateStr, this.dateFormatter); | ||
String result = ldt.format(dateFormatter); | ||
return result.equals(dateStr); | ||
} catch (DateTimeParseException e) { | ||
try { | ||
LocalDate ld = LocalDate.parse(dateStr, dateFormatter); | ||
String result = ld.format(dateFormatter); | ||
return result.equals(dateStr); | ||
} catch (DateTimeParseException exp) { | ||
try { | ||
LocalTime lt = LocalTime.parse(dateStr, dateFormatter); | ||
String result = lt.format(dateFormatter); | ||
return result.equals(dateStr); | ||
} catch (DateTimeParseException e2) { | ||
// Debugging purposes | ||
e2.printStackTrace(); | ||
} | ||
} | ||
} | ||
|
||
return false; | ||
} | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,132 @@ | ||
package ssagit.parser; | ||
|
||
import ssagit.datevalidator.DateValidator; | ||
import ssagit.taskclass.DeadlineTask; | ||
import ssagit.taskclass.EventTask; | ||
import ssagit.taskclass.Task; | ||
import ssagit.ui.ConsoleUI; | ||
|
||
import java.text.ParseException; | ||
import java.text.SimpleDateFormat; | ||
import java.util.Date; | ||
|
||
public class Parser { | ||
ConsoleUI ui; | ||
boolean isBye; | ||
DateValidator validator; | ||
|
||
public Parser(ConsoleUI ui, DateValidator validator) { | ||
this.ui = ui; | ||
this.isBye = false; | ||
this.validator = validator; | ||
} | ||
|
||
/** | ||
* Exception class for missing todoTask descriptor. | ||
*/ | ||
static class MissingTodoDescriptorException extends Exception { | ||
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. I feel these exceptions should be under a different class, like a DukeException suggested in the project guide |
||
public MissingTodoDescriptorException(String errorMessage) { | ||
super(errorMessage); | ||
} | ||
} | ||
|
||
/** | ||
* Exception class for unknown input parameters. | ||
*/ | ||
static class UnknownInputParamException extends Exception { | ||
public UnknownInputParamException(String errorMessage) { | ||
super(errorMessage); | ||
} | ||
} | ||
|
||
public boolean getIsBye() { | ||
return this.isBye; | ||
} | ||
|
||
/** | ||
* Parses lines of user input and outputs corresponding command. | ||
* @param tasks List of tasks from file. | ||
* @param taskIterator Integer to count number of tasks at a time. | ||
*/ | ||
public void parseInput(Task[] tasks, int taskIterator) { | ||
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. Whew this is long, maybe try moving some logic to other methods. |
||
String input = ui.nextLine(); | ||
String inputArr[] = input.split(" ", 2); | ||
|
||
try { | ||
switch (inputArr[0]) { | ||
case "bye": | ||
this.isBye = true; | ||
break; | ||
case "list": | ||
ui.list(tasks); | ||
break; | ||
case "done": | ||
int taskNum = Integer.parseInt(inputArr[1]) - 1; | ||
tasks[taskNum].markDone(); | ||
ui.markDone(tasks[taskNum].toFormattedString()); | ||
break; | ||
case "todo": | ||
case "event": | ||
case "deadline": | ||
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. This doesn't seem like good practice to me, should handle the todo and event in their respective cases I feel |
||
// add to list | ||
String[] inputArrTasks = input.split("/", 2); | ||
String[] firstHalf = inputArrTasks[0].split(" ", 2); | ||
if (inputArrTasks.length != 1) { | ||
// create Deadline/Event | ||
String[] secondHalf = inputArrTasks[1].split(" ", 2); | ||
if (validator.isValid(secondHalf[1])) { | ||
Date date = new SimpleDateFormat("d/MM/yyyy HHmm").parse(secondHalf[1]); | ||
if (inputArr[0].equals("event")) { | ||
tasks[taskIterator] = new EventTask(firstHalf[1], false, secondHalf[1].trim(), date); | ||
} else if (inputArr[0].equals("deadline")) { | ||
tasks[taskIterator] = new DeadlineTask(firstHalf[1], false, secondHalf[1].trim(), date); | ||
} | ||
} else { | ||
System.out.println("Invalid date format for timed Task"); | ||
} | ||
} else { | ||
// create todoTask | ||
if (firstHalf.length == 1) { | ||
throw new MissingTodoDescriptorException("------------------------------------\n" + | ||
":( OOPS!!! The description of a todo cannot be empty\n" + | ||
"------------------------------------"); | ||
} else { | ||
tasks[taskIterator] = new Task(firstHalf[1], false); | ||
} | ||
} | ||
break; | ||
case "delete": | ||
int removeIndex = Integer.parseInt(inputArr[1]); | ||
taskIterator--; // reduce task count in list | ||
ui.deleteTaskMessage(tasks[removeIndex - 1].toFormattedString(), taskIterator); | ||
// actually delete the task and move all other tasks forward | ||
for (int i = removeIndex - 1; i < tasks.length - 1; i++) { | ||
tasks[i] = tasks[i + 1]; | ||
} | ||
break; | ||
case "find": | ||
String toFind = inputArr[1]; | ||
String output = "Here are the matching tasks in your list:\n"; | ||
for (Task t : tasks) { | ||
if (t != null) { | ||
if (t.getTaskName().contains(toFind)) { | ||
output = output + t.toFormattedString() + "\n"; | ||
} | ||
} | ||
} | ||
ui.formatBox(output); | ||
break; | ||
default: | ||
throw new UnknownInputParamException("------------------------------------\n" + | ||
":( OOPS!!! I'm sorry, but I don't know what that means :-(\n" + | ||
"------------------------------------"); | ||
} | ||
} catch (MissingTodoDescriptorException e) { | ||
System.out.println(e.getMessage()); | ||
} catch (UnknownInputParamException e) { | ||
System.out.println(e.getMessage()); | ||
} catch (ParseException e) { | ||
System.out.println(e.getMessage()); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
package ssagit.storage; | ||
|
||
import ssagit.datevalidator.DateValidator; | ||
import ssagit.taskclass.DeadlineTask; | ||
import ssagit.taskclass.EventTask; | ||
import ssagit.taskclass.Task; | ||
|
||
import java.io.File; | ||
import java.io.FileWriter; | ||
import java.io.IOException; | ||
import java.nio.charset.Charset; | ||
import java.nio.file.Files; | ||
import java.nio.file.Path; | ||
import java.nio.file.Paths; | ||
import java.text.ParseException; | ||
import java.text.SimpleDateFormat; | ||
import java.util.Date; | ||
import java.util.List; | ||
|
||
public class Storage { | ||
Path relativePath; | ||
Path absolutePath; | ||
File taskText; | ||
|
||
/** | ||
* Constructor, creates a file of the searched file if it doesn't exist. | ||
* Afterwards, create a {@code FileWriter} which is used to write to the file. | ||
* @param relativePath relative path of file to be searched for. | ||
*/ | ||
public Storage (String relativePath) { | ||
this.relativePath = Paths.get(relativePath); | ||
absolutePath = this.relativePath.toAbsolutePath(); | ||
taskText = new File(absolutePath.toString()); | ||
|
||
try { | ||
if (!taskText.exists()) { | ||
System.out.println("new file created"); | ||
taskText.createNewFile(); // creates the file if it doesn't exist | ||
} | ||
} catch (IOException e) { | ||
System.out.println("IOException has occurred"); | ||
e.printStackTrace(); | ||
} | ||
} | ||
|
||
/** | ||
* Reads a file into the program and parses each line into a Task and puts it into taskArr. | ||
* @param taskArr array of Task objects. | ||
* @return number of tasks currently available in list (1 index). | ||
*/ | ||
public int readTaskListToArray(Task[] taskArr, DateValidator validator) { | ||
int taskIterator = 0; | ||
try { | ||
List<String> list = Files.readAllLines(Paths.get(relativePath.toString()), Charset.defaultCharset()); | ||
String[] taskListStr = list.toArray(new String[list.size()]); | ||
for (String str : taskListStr) { | ||
String[] strArr = str.split(" \\| "); | ||
String taskType = strArr[0]; | ||
String isDoneStr = strArr[1]; | ||
String taskName = strArr[2]; | ||
|
||
if (taskType.equals("todo")) { | ||
taskArr[taskIterator] = new Task(taskName, isDoneStr.equals("done")); | ||
} else if (taskType.equals("event")) { | ||
if (validator.isValid(strArr[3].trim())) { | ||
Date eventDate = new SimpleDateFormat("d/MM/yyyy HHmm").parse(strArr[3].trim()); | ||
taskArr[taskIterator] = new EventTask(taskName, isDoneStr.equals("done"), strArr[3].trim(), eventDate); | ||
} else { | ||
System.out.println("Invalid date format for timed Task"); | ||
} | ||
} else if (taskType.equals("deadline")) { | ||
if (validator.isValid(strArr[3].trim())) { | ||
Date deadlineDate = new SimpleDateFormat("d/MM/yyyy HHmm").parse(strArr[3].trim()); | ||
taskArr[taskIterator] = new DeadlineTask(taskName, isDoneStr.equals("done"), strArr[3].trim(), deadlineDate); | ||
} else { | ||
System.out.println("Invalid date format for timed Task"); | ||
} | ||
} | ||
taskIterator++; | ||
} | ||
return taskIterator; | ||
} catch (IOException e) { | ||
System.out.println("IOException has occurred"); | ||
e.printStackTrace(); | ||
} catch (ParseException e) { | ||
System.out.println("ParseException has occurred"); | ||
e.printStackTrace(); | ||
} | ||
return taskIterator; | ||
} | ||
|
||
/** | ||
* Writes all tasks from an array of {@code Task} objects to file output. | ||
* @param taskArr Array of {@code Task} objects. | ||
*/ | ||
public void writeTasks(Task[] taskArr) { | ||
try { | ||
FileWriter fw = new FileWriter(absolutePath.toString()); | ||
for (Task t : taskArr) { | ||
if (t != null) { | ||
fw.write(t.toOutputFileString() + "\n"); | ||
fw.flush(); | ||
} | ||
} | ||
fw.close(); | ||
} catch (IOException e) { | ||
System.out.println("IOException has occurred"); | ||
e.printStackTrace(); | ||
} | ||
} | ||
} |
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.
Seems a little odd that your package is called ssagit when the application is still called duke.