diff --git a/docs/staticpages/DisplayRoutes.html b/docs/staticpages/DisplayRoutes.html
index 961c584aa267..fde437173dac 100644
--- a/docs/staticpages/DisplayRoutes.html
+++ b/docs/staticpages/DisplayRoutes.html
@@ -28,8 +28,6 @@
var tempObject = {};
var keyList = [];
if (queryString) {
- // stuff after # is not part of query string, so get rid of it
- queryString = queryString.split('#')[0];
// split our query string into its component parts
var arr = queryString.split('&');
for (var i = 0; i < arr.length; i++) {
diff --git a/src/main/java/seedu/equipment/logic/commands/CommandResult.java b/src/main/java/seedu/equipment/logic/commands/CommandResult.java
index d5a33e56bbb6..77cb04cedb87 100644
--- a/src/main/java/seedu/equipment/logic/commands/CommandResult.java
+++ b/src/main/java/seedu/equipment/logic/commands/CommandResult.java
@@ -4,6 +4,8 @@
import java.util.Objects;
+import seedu.equipment.model.equipment.Address;
+
/**
* Represents the result of a command execution.
*/
@@ -20,6 +22,12 @@ public class CommandResult {
/** The application should show map on right hand side with equipment locations. */
private final boolean displayMap;
+ /** The application should show map on right hand side with route to equipments. */
+ private final boolean route;
+
+ /** The address send back to UI to display route. */
+ private final Address routeAddress;
+
/**
* Constructs a {@code CommandResult} with the specified fields.
*/
@@ -40,10 +48,21 @@ public CommandResult(String feedbackToUser) {
* and other fields set to their default value.
*/
public CommandResult(String feedbackToUser, boolean showHelp, boolean exit, boolean displayMap) {
+ this(feedbackToUser, showHelp, exit, displayMap, false, null);
+ }
+
+ /**
+ * Constructs a {@code CommandResult} with the specified {@code feedbackToUser},
+ * and other fields set to their default value.
+ */
+ public CommandResult(String feedbackToUser, boolean showHelp, boolean exit, boolean displayMap,
+ boolean route, Address routeAddress) {
this.feedbackToUser = requireNonNull(feedbackToUser);
this.showHelp = showHelp;
this.exit = exit;
this.displayMap = displayMap;
+ this.route = route;
+ this.routeAddress = routeAddress;
}
public String getFeedbackToUser() {
@@ -62,6 +81,14 @@ public boolean isDisplayMap() {
return displayMap;
}
+ public boolean isRoute() {
+ return route;
+ }
+
+ public Address getRouteAddress() {
+ return routeAddress;
+ }
+
@Override
public boolean equals(Object other) {
if (other == this) {
@@ -77,12 +104,14 @@ public boolean equals(Object other) {
return feedbackToUser.equals(otherCommandResult.feedbackToUser)
&& showHelp == otherCommandResult.showHelp
&& exit == otherCommandResult.exit
- && displayMap == otherCommandResult.displayMap;
+ && displayMap == otherCommandResult.displayMap
+ && route == otherCommandResult.route
+ && ((routeAddress == null && otherCommandResult.routeAddress == null)
+ || (routeAddress != null && routeAddress.equals(otherCommandResult.routeAddress)));
}
- @Override
public int hashCode() {
- return Objects.hash(feedbackToUser, showHelp, exit, displayMap);
+ return Objects.hash(feedbackToUser, showHelp, exit, displayMap, route, routeAddress);
}
}
diff --git a/src/main/java/seedu/equipment/logic/commands/RouteCommand.java b/src/main/java/seedu/equipment/logic/commands/RouteCommand.java
new file mode 100644
index 000000000000..6a57f30c49c0
--- /dev/null
+++ b/src/main/java/seedu/equipment/logic/commands/RouteCommand.java
@@ -0,0 +1,63 @@
+package seedu.equipment.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+
+import java.util.List;
+
+import seedu.equipment.logic.CommandHistory;
+import seedu.equipment.logic.commands.exceptions.CommandException;
+import seedu.equipment.model.Model;
+import seedu.equipment.model.equipment.Address;
+import seedu.equipment.model.equipment.Equipment;
+
+/**
+ * Selects an equipment identified using it's displayed index from the equipment manager.
+ */
+public class RouteCommand extends Command {
+
+ public static final String COMMAND_WORD = "route";
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD
+ + ": Produce a optimized route from current location to the displayed equipment list.\n"
+ + "Parameters: CURRENT ADDRESS (must be a valid address with postal code and country name)\n"
+ + "Example: " + COMMAND_WORD + " School of Computing, NUS, Singapore 117417";
+
+ public static final String MESSAGE_ROUTE_EQUIPMENT_SUCCESS = "Routes displayed on map.";
+
+ public static final String MESSAGE_NO_EQUIPMENTS_TO_ROUTE = "At least 1 equipment in the equipment panel "
+ + " is required to use route command.";
+
+ public static final String MESSAGE_TOO_MANY_EQUIPMENTS_TO_ROUTE = "At most 15 equipment in the equipment panel "
+ + " to use route command.";
+
+ private final Address startendAddress;
+
+ public RouteCommand(Address startendAddress) {
+ this.startendAddress = startendAddress;
+ }
+
+ @Override
+ public CommandResult execute(Model model, CommandHistory history) throws CommandException {
+ requireNonNull(model);
+
+ List filteredEquipmentList = model.getFilteredPersonList();
+
+ if (filteredEquipmentList.size() < 1) {
+ throw new CommandException(MESSAGE_NO_EQUIPMENTS_TO_ROUTE);
+ }
+
+ if (filteredEquipmentList.size() > 15) {
+ throw new CommandException(MESSAGE_TOO_MANY_EQUIPMENTS_TO_ROUTE);
+ }
+
+ return new CommandResult(MESSAGE_ROUTE_EQUIPMENT_SUCCESS, false, false, false, true, startendAddress);
+
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return other == this // short circuit if same object
+ || (other instanceof RouteCommand // instanceof handles nulls
+ && startendAddress.equals(((RouteCommand) other).startendAddress)); // state check
+ }
+}
diff --git a/src/main/java/seedu/equipment/logic/parser/EquipmentManagerParser.java b/src/main/java/seedu/equipment/logic/parser/EquipmentManagerParser.java
index 2f9c19ff3caa..ceffa7c38a8f 100644
--- a/src/main/java/seedu/equipment/logic/parser/EquipmentManagerParser.java
+++ b/src/main/java/seedu/equipment/logic/parser/EquipmentManagerParser.java
@@ -22,6 +22,7 @@
import seedu.equipment.logic.commands.ListWorkListCommand;
import seedu.equipment.logic.commands.PutCommand;
import seedu.equipment.logic.commands.RedoCommand;
+import seedu.equipment.logic.commands.RouteCommand;
import seedu.equipment.logic.commands.SelectCommand;
import seedu.equipment.logic.commands.SortCommand;
import seedu.equipment.logic.commands.UndoCommand;
@@ -114,6 +115,9 @@ public Command parseCommand(String userInput) throws ParseException {
case DisplayCommand.COMMAND_WORD:
return new DisplayCommand();
+ case RouteCommand.COMMAND_WORD:
+ return new RouteCommandParser().parse(arguments);
+
default:
throw new ParseException(Messages.MESSAGE_UNKNOWN_COMMAND);
}
diff --git a/src/main/java/seedu/equipment/logic/parser/RouteCommandParser.java b/src/main/java/seedu/equipment/logic/parser/RouteCommandParser.java
new file mode 100644
index 000000000000..e33021e5b4c8
--- /dev/null
+++ b/src/main/java/seedu/equipment/logic/parser/RouteCommandParser.java
@@ -0,0 +1,27 @@
+package seedu.equipment.logic.parser;
+
+import seedu.equipment.commons.core.Messages;
+import seedu.equipment.logic.commands.RouteCommand;
+import seedu.equipment.logic.parser.exceptions.ParseException;
+import seedu.equipment.model.equipment.Address;
+
+/**
+ * Parses input arguments and creates a new RouteCommand object
+ */
+public class RouteCommandParser implements Parser {
+
+ /**
+ * Parses the given {@code String} of arguments in the context of the RoutetCommand
+ * and returns an RouteCommand object for execution.
+ * @throws ParseException if the user input does not conform the expected format
+ */
+ public RouteCommand parse(String args) throws ParseException {
+ try {
+ Address address = ParserUtil.parseAddress(args);
+ return new RouteCommand(address);
+ } catch (ParseException pe) {
+ throw new ParseException(
+ String.format(Messages.MESSAGE_INVALID_COMMAND_FORMAT, RouteCommand.MESSAGE_USAGE), pe);
+ }
+ }
+}
diff --git a/src/main/java/seedu/equipment/ui/BrowserPanel.java b/src/main/java/seedu/equipment/ui/BrowserPanel.java
index a975f982615e..909e765e8d91 100644
--- a/src/main/java/seedu/equipment/ui/BrowserPanel.java
+++ b/src/main/java/seedu/equipment/ui/BrowserPanel.java
@@ -23,6 +23,7 @@ public class BrowserPanel extends UiPart {
public static final String MAP_PAGE_BASE_URL = "https://cs2103-ay1819s2-w10-3.github.io/"
+ "main/DisplayEquipmentDetail";
public static final String MAP_MULTIPLE_POINT_BASE_URL = "https://cs2103-ay1819s2-w10-3.github.io/main/DisplayGmap";
+ public static final String MAP_ROUTE_BASE_URL = "https://cs2103-ay1819s2-w10-3.github.io/main/DisplayRoutes";
public static final URL DEFAULT_PAGE = processDefaultPage(MAP_MULTIPLE_POINT_BASE_URL);
private static final String FXML = "BrowserPanel.fxml";
diff --git a/src/main/java/seedu/equipment/ui/MainWindow.java b/src/main/java/seedu/equipment/ui/MainWindow.java
index ca7106add56b..e93cffa3f875 100644
--- a/src/main/java/seedu/equipment/ui/MainWindow.java
+++ b/src/main/java/seedu/equipment/ui/MainWindow.java
@@ -17,6 +17,7 @@
import seedu.equipment.logic.commands.CommandResult;
import seedu.equipment.logic.commands.exceptions.CommandException;
import seedu.equipment.logic.parser.exceptions.ParseException;
+import seedu.equipment.model.equipment.Address;
import seedu.equipment.model.equipment.Equipment;
/**
@@ -206,6 +207,25 @@ public void handleDisplayMap() {
browserPanel.loadPage(url);
}
+ /**
+ * Opens the map window and display the route on it.
+ */
+ @FXML
+ public void handleRoute(Address startendAddress) {
+ List equipmentList = logic.getFilteredEquipment();
+ String addressString = "[";
+ for (Equipment equipment:equipmentList) {
+ Address address = equipment.getAddress();
+ addressString += "\"" + address.toString() + "\",";
+ }
+ addressString = addressString.replaceAll(",$", "");
+ addressString += "]";
+ String url = BrowserPanel.MAP_ROUTE_BASE_URL + "?address=" + addressString + "&start=\""
+ + startendAddress.toString() + "\"&end=\"" + startendAddress.toString() + "\"";
+ System.out.println("Loading page: " + url);
+ browserPanel.loadPage(url);
+ }
+
/**
* Executes the command and returns the result.
*
@@ -230,6 +250,10 @@ private CommandResult executeCommand(String commandText) throws CommandException
handleDisplayMap();
}
+ if (commandResult.isRoute()) {
+ handleRoute(commandResult.getRouteAddress());
+ }
+
return commandResult;
} catch (CommandException | ParseException e) {
logger.info("Invalid command: " + commandText);
diff --git a/src/test/java/seedu/equipment/logic/commands/RouteCommandTest.java b/src/test/java/seedu/equipment/logic/commands/RouteCommandTest.java
new file mode 100644
index 000000000000..00662147539a
--- /dev/null
+++ b/src/test/java/seedu/equipment/logic/commands/RouteCommandTest.java
@@ -0,0 +1,109 @@
+package seedu.equipment.logic.commands;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+import static seedu.equipment.testutil.TypicalEquipments.getTypicalAddressBook;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import seedu.equipment.logic.CommandHistory;
+import seedu.equipment.logic.commands.exceptions.CommandException;
+import seedu.equipment.logic.parser.RouteCommandParser;
+import seedu.equipment.logic.parser.exceptions.ParseException;
+import seedu.equipment.model.Model;
+import seedu.equipment.model.ModelManager;
+import seedu.equipment.model.UserPrefs;
+import seedu.equipment.model.equipment.Address;
+import seedu.equipment.model.equipment.Equipment;
+import seedu.equipment.testutil.EquipmentBuilder;
+
+public class RouteCommandTest {
+
+ private Model model;
+ private Model expectedModel;
+ private Model emptyModel;
+ private CommandHistory commandHistory = new CommandHistory();
+
+ @Before
+ public void setUp() {
+ model = new ModelManager(getTypicalAddressBook(), new UserPrefs());
+ emptyModel = new ModelManager();
+ expectedModel = new ModelManager(model.getEquipmentManager(), new UserPrefs());
+ }
+
+ @Test
+ public void execute_routeCommandExecuteSuccessful() {
+ try {
+ CommandHistory expectedCommandHistory = new CommandHistory(commandHistory);
+ Address testAddress = new Address("School of computing, NUS, Singapore");
+ CommandResult result = new RouteCommand(testAddress).execute(model, commandHistory);
+ CommandResult expectedCommandResult = new CommandResult(
+ RouteCommand.MESSAGE_ROUTE_EQUIPMENT_SUCCESS, false, false, false, true, testAddress);
+ assertEquals(expectedCommandResult.toString(), result.toString());
+ assertEquals(expectedModel, model);
+ assertEquals(expectedCommandHistory, commandHistory);
+ } catch (CommandException ce) {
+ fail("NO invalid command exception should be thrown.");
+ }
+ }
+
+ @Test
+ public void execute_routeCommandExecuteNoEquipmentExceptions() {
+ try {
+ Address testAddress = new Address("School of computing, NUS, Singapore");
+ CommandResult result = new RouteCommand(testAddress).execute(emptyModel, commandHistory);
+ fail("Routing with empty equipment list should raise exception.");
+ } catch (CommandException ce) {
+ if (ce.getMessage() != RouteCommand.MESSAGE_NO_EQUIPMENTS_TO_ROUTE) {
+ fail("Should display no equipment message to user.");
+ }
+ }
+ }
+
+ @Test
+ public void execute_routeCommandExecuteTooManyEquipmentExceptions() {
+ try {
+ Address testAddress = new Address("School of computing, NUS, Singapore");
+ for (int i = 0; i < 16; i++) {
+ Equipment newEquipment = new EquipmentBuilder().withName("PGPR" + i).withPhone("8482131")
+ .withDate("10-05-2019").withAddress("PGPR, NUS, SINGAPORE")
+ .withSerialNumber(String.valueOf(i)).build();
+ model.addEquipment(newEquipment);
+ }
+ CommandResult result = new RouteCommand(testAddress).execute(model, commandHistory);
+ fail("Routing with 16 equipment list should raise exception.");
+ } catch (CommandException ce) {
+ if (ce.getMessage() != RouteCommand.MESSAGE_TOO_MANY_EQUIPMENTS_TO_ROUTE) {
+ fail("Should display too many equipments message to user.");
+ }
+ }
+ }
+
+ @Test
+ public void execute_routeCommandParserExecuteInvalidAddressExceptions() {
+ try {
+ CommandResult result = new RouteCommandParser().parse("").execute(model, commandHistory);
+ fail("Routing with invalid starting address should raise exception.");
+ } catch (CommandException ce) {
+ fail("ParseException should be thrown but CommandException is thrown.");
+ } catch (ParseException pe) {
+ if (pe.getMessage() == null) {
+ fail("Should display some error message.");
+ }
+ }
+ }
+
+ @Test
+ public void execute_routeCommandEqualsTest() {
+ try {
+ RouteCommand command1 = new RouteCommandParser().parse("ABC");
+ RouteCommand command2 = new RouteCommandParser().parse("ABC");
+ if (!command1.equals(command2)) {
+ fail("Route commands with same address should be equal.");
+ }
+ } catch (ParseException pe) {
+ fail("No ParseException should be thrown.");
+ }
+ }
+}
diff --git a/src/test/java/systemtests/EquipmentManagerSystemTest.java b/src/test/java/systemtests/EquipmentManagerSystemTest.java
index a26b69e1543f..ce77af3eaad4 100644
--- a/src/test/java/systemtests/EquipmentManagerSystemTest.java
+++ b/src/test/java/systemtests/EquipmentManagerSystemTest.java
@@ -280,6 +280,14 @@ protected void assertSelectedCardUnchanged() {
assertFalse(getPersonListPanel().isSelectedPersonCardChanged());
}
+ /**
+ * Asserts that the selected card in the equipment list panel remain unchanged.
+ * @see EquipmentListPanelHandle#isSelectedPersonCardChanged()
+ */
+ protected void assertSelectedPersonCardUnchanged() {
+ assertFalse(getPersonListPanel().isSelectedPersonCardChanged());
+ }
+
/**
* Asserts that the command box's shows the default style.
*/
diff --git a/src/test/java/systemtests/RouteCommandSystemTest.java b/src/test/java/systemtests/RouteCommandSystemTest.java
new file mode 100644
index 000000000000..2074632c89fc
--- /dev/null
+++ b/src/test/java/systemtests/RouteCommandSystemTest.java
@@ -0,0 +1,49 @@
+package systemtests;
+
+import static org.junit.Assert.assertNotEquals;
+
+import java.net.URL;
+
+import org.junit.Test;
+
+import seedu.equipment.logic.commands.RouteCommand;
+import seedu.equipment.model.Model;
+import seedu.equipment.ui.BrowserPanel;
+
+public class RouteCommandSystemTest extends EquipmentManagerSystemTest {
+
+ @Test
+ public void route() {
+ /* Case: display route of equipments equipments on map
+ * -> Equipments showed on map!
+ */
+ String command = "" + RouteCommand.COMMAND_WORD + " School of Computing, NUS, Singapore 117417";
+ Model expectedModel = getModel();
+ assertCommandSuccess(command, expectedModel);
+
+ }
+
+ /**
+ * Executes {@code command} and verifies that the command box displays an empty string, the result display
+ * box displays {@code Messages#MESSAGE_EQUIPMENTS_LISTED_OVERVIEW} with the number of people in the filtered list,
+ * and the model related components equal to {@code expectedModel}.
+ * These verifications are done by
+ * {@code EquipmentManagerSystemTest#assertApplicationDisplaysExpected(String, String, Model)}.
+ * Also verifies that the status bar remains unchanged, and the command box has the default style class, and the
+ * selected card updated accordingly, depending on {@code cardStatus}.
+ * @see EquipmentManagerSystemTest#assertApplicationDisplaysExpected(String, String, Model)
+ */
+ private void assertCommandSuccess(String command, Model expectedModel) {
+ String expectedResultMessage = RouteCommand.MESSAGE_ROUTE_EQUIPMENT_SUCCESS;
+ URL oldUrl = getBrowserPanel().getLoadedUrl();
+ executeCommand(command);
+ assertApplicationDisplaysExpected("", expectedResultMessage, expectedModel);
+ assertCommandBoxShowsDefaultStyle();
+ assertStatusBarUnchanged();
+ assertSelectedPersonCardUnchanged();
+ assertNotEquals(oldUrl.toString(), getBrowserPanel().getLoadedUrl().toString());
+ assertNotEquals(BrowserPanel.DEFAULT_PAGE, getBrowserPanel().getLoadedUrl().toString());
+ assertNotEquals(BrowserPanel.MAP_MULTIPLE_POINT_BASE_URL, getBrowserPanel().getLoadedUrl().toString());
+ assertNotEquals(BrowserPanel.MAP_ROUTE_BASE_URL, getBrowserPanel().getLoadedUrl().toString());
+ }
+}