Skip to content
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

[kevinz420] iP #62

Open
wants to merge 16 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
68 changes: 54 additions & 14 deletions docs/README.md
Original file line number Diff line number Diff line change
@@ -1,29 +1,69 @@
# User Guide
# KevBot Guide

## Features

### Feature-ABC
### List

Description of the feature.
List all outstanding todos, deadlines, and events.

### Feature-XYZ
### Find

Description of the feature.
Filter the listed tasks by a specific keyword(s).

## Usage
### Mark

Mark a task as completed/incomplete.

### Delete

### `Keyword` - Describe action
Delete a specific task.

Describe the action and its outcome.
### Add

Add a new todo, deadline, or event task.

## Usage

### `list` - List all tasks

Example of usage:

`keyword (optional arguments)`
`list`

### `find` - Match tasks by keyword

Example of usage:

`find (keyword)`

### `mark` - Mark a task
Marks an undone task as done and vice versa. Task index is 1-based as displayed in the list command.

Example of usage:

`mark (task index)`

### `delete` - Remove a task
Task index is 1-based as displayed in the list command.

Example of usage:

`delete (task index)`

### `todo` - Add a todo

Example of usage:

`todo (description)`

### `deadline` - Add a deadline

Example of usage:

`deadline (description) /by (end time)`

Expected outcome:
### `event` - Add an event

Description of the outcome.
Example of usage:

```
expected output
```
`event (description) /from (start time) /to (end time)`
6 changes: 6 additions & 0 deletions duke.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
T|false|asdfkasdh
T|true|re98ui
D|true|return book|tmrw
E|false|proj meeting|today|forever
T|false|hu
T|true|deez
10 changes: 0 additions & 10 deletions src/main/java/Duke.java

This file was deleted.

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.Duke

59 changes: 59 additions & 0 deletions src/main/java/duke/Duke.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package duke;

import duke.command.DukeException;
import duke.parser.Parser;
import duke.storage.StorageFile;
import duke.tasklist.TaskList;
import duke.ui.TextUi;

kevinz420 marked this conversation as resolved.
Show resolved Hide resolved
public class Duke {
private TextUi ui;
private Parser parser;
private TaskList tasks;
private StorageFile storage;

public Duke(String filePath) {
tasks = new TaskList();
ui = new TextUi();
parser = new Parser();
storage = new StorageFile(filePath);

try {
tasks = new TaskList(storage.load());
} catch (DukeException e) {
ui.showInitFailedMessage();
tasks = new TaskList();
}
}

public void run() {
ui.showWelcomeMessage();

String userCommandText = ui.getUserCommand();
while (!userCommandText.equals("bye")) {
String result = handleCommand(userCommandText);
ui.showResultToUser(result);
userCommandText = ui.getUserCommand();
}

ui.showGoodbyeMessage();
}

public String handleCommand(String userInput) {
if (userInput.equals("list")) {
return tasks.getIndexedTasks();
} else {
try {
String result = parser.executeCommand(userInput, tasks);
storage.saveTasks(tasks);
return result;
} catch (Exception e) {
return e.getMessage();
}
}
}

public static void main(String[] args) {
new Duke("duke.txt").run();
}
}
10 changes: 10 additions & 0 deletions src/main/java/duke/command/DukeException.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package duke.command;

/**
* Wrapper for an exception throw within Duke
*/
public class DukeException extends Exception {
public DukeException(String message) {
super(message);
}
}
108 changes: 108 additions & 0 deletions src/main/java/duke/parser/Parser.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
package duke.parser;

import duke.command.DukeException;
import duke.task.Deadline;
import duke.task.Event;
import duke.task.Todo;
import duke.tasklist.TaskList;

import java.util.HashMap;

/**
* A <code>Parser</code> object is responsible for parsing and executing
* a user provided command string.
*/
public class Parser {
public Parser() {}

/**
* Returns a human-readable result of the command
* executed.
*
* @param line inputted by user.
* @param tasks that are currently in the TaskList
* @return A human-readable string of the command's result.
* @throws DukeException If command has issues.
*/
public String executeCommand(String line, TaskList tasks) throws DukeException {
int divider = line.indexOf(" ");
if (divider == -1) {
throw new DukeException("Sorry! Not sure what you mean");
}
if (divider == line.length() - 1) {
throw new DukeException("Please enter a non-empty parameter value");
}


if (line.startsWith("todo")){
String description = line.substring(divider + 1);

return tasks.addTask(new Todo(description));
} else if (line.startsWith("find")) {
String keyword = line.substring(divider + 1);

return tasks.getIndexedTasksByKeyword(keyword);
}

if (line.contains("mark") || line.startsWith("delete")) {
int idx = Integer.parseInt(line.substring(divider + 1)) - 1;
if (idx < 0 || idx >= tasks.size()) {
throw new DukeException("Sorry! That's not a valid task");
}

if (line.contains("mark")) {
return tasks.markTask(idx, line.startsWith("mark"));
} else {
return tasks.removeTask(idx);
}
}

HashMap<String, String> parameters = parseParameters(line);
String description = parameters.get("description");
if (description == null) {
throw new DukeException("Sorry! Please provide a valid description");
}
if (line.startsWith("deadline")) {
String by = parameters.get("by");
if (by == null) {
throw new DukeException("Sorry! Please provide a valid `by`");
}
return tasks.addTask(new Deadline(description, by));
} else if (line.startsWith("event")) {
String from = parameters.get("from");
String to = parameters.get("to");
if (from == null || to == null) {
throw new DukeException("Sorry! Please provide a valid `from` and/or `to`");
}
return tasks.addTask(new Event(description, from, to));
} else {
throw new DukeException("Sorry! Please enter a valid command");
}
}

private static HashMap<String, String> parseParameters(String line) throws DukeException {
HashMap<String, String> fieldToValue = new HashMap<>();

int startDescription = line.indexOf(" ");
int endOfDescription = line.indexOf(" /");
if (startDescription == endOfDescription || startDescription == -1 || endOfDescription == -1) {
throw new DukeException("Sorry! Not sure what you mean");
}
fieldToValue.put("description", line.substring(startDescription + 1, endOfDescription));

String[] splitParams = line.split(" /");
for (int i = 1; i < splitParams.length; i++) {
String rawParam = splitParams[i];
int divider = rawParam.indexOf(" ");
if (divider == -1) {
throw new DukeException("Sorry! Please enter valid inputs");
}

String field = rawParam.substring(0, divider);
String value = rawParam.substring(divider + 1);
fieldToValue.put(field, value);
}

return fieldToValue;
}
}
93 changes: 93 additions & 0 deletions src/main/java/duke/storage/StorageFile.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
package duke.storage;

import duke.command.DukeException;
import duke.task.Deadline;
import duke.task.Event;
import duke.task.Task;
import duke.task.Todo;
import duke.tasklist.TaskList;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

/**
* Handles Duke's storage capabilities. A <code>StorageFile</code> object handles the
* loading and saving aspects of new tasks.
*/
public class StorageFile {
String filePath;
public StorageFile(String filePath) {
this.filePath = filePath;
}

/**
* Loads all tasks from the .txt file
* when the program is first ran.
*
* @return List of Task objects representing saved tasks.
* @throws DukeException If there is an issue loading tasks.
*/
public List<Task> load() throws DukeException {
List<Task> tasks = new ArrayList<>();
File f = new File(filePath);

try {
f.createNewFile();
Scanner s = new Scanner(f);
while (s.hasNext()) {
String line = s.nextLine();
String[] parsed = line.split("\\|");
String taskType = parsed[0];
String description = parsed[2];

switch (taskType) {
case "T":
tasks.add(new Todo(description));
break;
case "D":
String by = parsed[3];
tasks.add(new Deadline(description, by));
break;
case "E":
String from = parsed[3];
String to = parsed[4];
tasks.add(new Event(description, from, to));
break;
default:
throw new DukeException("Unknown task type detected");
}

if (parsed[1].equals("true")) {
tasks.get(tasks.size() - 1).setStatus(true);
}
}
} catch (IOException e) {
throw new DukeException(e.getMessage());
}

return tasks;
}

/**
* Saves all tasks to the .txt file after
* a command that modifies the TaskList
*
* @param tasks to be written to the file
* @throws DukeException If there is an error writing.
*/
public void saveTasks(TaskList tasks) throws DukeException {
File f = new File(filePath);

try {
FileWriter fw = new FileWriter(f);
fw.write(tasks.getSerializedTasks());
fw.close();
} catch (IOException e) {
throw new DukeException(e.getMessage());
}
}
}
Loading