aboutsummaryrefslogtreecommitdiffstats
path: root/src/eu/equalparts/cardbase/standalone/CardbaseCLI.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/eu/equalparts/cardbase/standalone/CardbaseCLI.java')
-rw-r--r--src/eu/equalparts/cardbase/standalone/CardbaseCLI.java540
1 files changed, 290 insertions, 250 deletions
diff --git a/src/eu/equalparts/cardbase/standalone/CardbaseCLI.java b/src/eu/equalparts/cardbase/standalone/CardbaseCLI.java
index 4071fad..e0f5433 100644
--- a/src/eu/equalparts/cardbase/standalone/CardbaseCLI.java
+++ b/src/eu/equalparts/cardbase/standalone/CardbaseCLI.java
@@ -5,7 +5,7 @@ import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
-import java.util.HashMap;
+import java.util.Arrays;
import java.util.Iterator;
import java.util.Scanner;
@@ -17,7 +17,6 @@ import eu.equalparts.cardbase.data.Card;
import eu.equalparts.cardbase.data.CardbaseManager;
import eu.equalparts.cardbase.data.FullCardSet;
import eu.equalparts.cardbase.data.CardSet;
-import eu.equalparts.cardbase.query.IO;
/**
* This provides a lightweight CLI for interacting with cardbase files.
@@ -32,11 +31,11 @@ public class CardbaseCLI {
* @author Eduardo Pedroni
*/
private enum Action {
-
+
ADD, REMOVE;
public Card card;
public Integer count;
-
+
/**
* Sets both fields at once.
*
@@ -48,7 +47,7 @@ public class CardbaseCLI {
this.count = count;
}
}
-
+
/**
* The last action performed by the user.
*/
@@ -58,21 +57,13 @@ public class CardbaseCLI {
*/
private FullCardSet selectedSet = null;
/**
- * A cache of CardSets to avoid querying the server many times for the same information.
- */
- private HashMap<String, FullCardSet> setCache = new HashMap<String, FullCardSet>();
- /**
- * The manager object which provides a façade to the cardbase data structure.
- */
- private CardbaseManager cbm;
- /**
- * Exit flag, program breaks out of the main loop when true.
+ * The manager object which allows interaction with cardbase data structure.
*/
- private boolean exit = false;
+ private CardbaseManager cardbaseManager;
/**
* Printed to the console when the user enter the help command.
*/
- private String help = "Not available, check project page.";
+ private String help = "Not available, check project page on GitHub.";
/**
* The cardbase file off which we are currently working, if any.
*/
@@ -82,6 +73,10 @@ public class CardbaseCLI {
* if the user tries to exit with unsaved changed.
*/
private boolean savePrompt = false;
+ /**
+ * Exit flag, program breaks out of the main loop when true.
+ */
+ private boolean exit = false;
/**
* Execute the interface.
@@ -90,7 +85,7 @@ public class CardbaseCLI {
*/
public static void main(String... args) {
try {
- new CardbaseCLI(args).run();
+ new CardbaseCLI(args).startInterface();
} catch (JsonParseException e) {
System.out.println("Error: poorly formatted cardbase, check the syntax and try again.");
// although the problem could also be with the upstream CardSetList json.
@@ -103,23 +98,33 @@ public class CardbaseCLI {
e.printStackTrace();
}
}
-
+
+ /**
+ * Reads in an optional cardbase JSON and initialises other necessary components.
+ * This does not actually produce the CLI, for that use {@code startInterface()}
+ * on the constructed object.
+ *
+ * @param args a list of arguments. Only the first argument is used, as a cardbase JSON.
+ * @throws JsonParseException the file specified does not comply to JSON standards.
+ * @throws JsonMappingException the file specified cannot be mapped to a {@code Cardbase} object.
+ * @throws IOException something went wrong with the low-level I/O.
+ */
private CardbaseCLI(String... args) throws JsonParseException, JsonMappingException, IOException {
System.out.println("Welcome to Cardbase CLI!");
// make the CardbaseManager
if (args.length > 0) {
- cardbaseFile = new File(args[0]);
+ File cardbaseFile = new File(args[0]);
if (cardbaseFile.exists() && cardbaseFile.isFile() && cardbaseFile.canRead()) {
System.out.println("Loading cardbase from \"" + args[0] + "\".");
- cbm = new CardbaseManager(cardbaseFile);
+ cardbaseManager = new CardbaseManager(cardbaseFile);
} else {
System.out.println(args[0] + " appears to be invalid.");
System.exit(0);
}
} else {
System.out.println("No cardbase file was provided, creating a clean cardbase.");
- cbm = new CardbaseManager();
+ cardbaseManager = new CardbaseManager();
}
// load help information
@@ -127,18 +132,49 @@ public class CardbaseCLI {
if (is != null) {
help = new Scanner(is).useDelimiter("\\Z").next();
} else {
- System.out.println("Help file was not found, check the project page for help instead.");
+ System.out.println("Help file was not found, check the project page on GitHub for help instead.");
}
}
- private void run() {
+ /**
+ * Read stdin for user input, sanitise and interpret any commands entered.
+ */
+ private void startInterface() {
BufferedReader consoleReader = new BufferedReader(new InputStreamReader(System.in));
- // the main loop
try {
+ // the main loop
while (!exit) {
- System.out.print(selectedSet == null ? "> " : selectedSet.code + " > ");
- interpret(consoleReader.readLine().trim().toLowerCase().split("[ \t]+"));
+ // print prompt
+ System.out.print(selectedSet == null ? "> " : selectedSet.getCode() + " > ");
+ // condition input and interpret
+ String[] raw = consoleReader.readLine().trim().toLowerCase().split("[ \t]+");
+ String command = raw[0];
+ String[] args = Arrays.copyOfRange(raw, 1, raw.length);
+
+ if (command.equalsIgnoreCase("help")) {
+ help();
+ } else if (command.equalsIgnoreCase("write")
+ || command.equalsIgnoreCase("save")) {
+ write(args);
+ } else if (command.equalsIgnoreCase("exit")) {
+ exit();
+ } else if (command.equalsIgnoreCase("sets")) {
+ sets();
+ } else if (command.equalsIgnoreCase("set")) {
+ set(args);
+ } else if (command.equalsIgnoreCase("glance")) {
+ glance();
+ } else if (command.equalsIgnoreCase("peruse")) {
+ peruse(args);
+ } else if (command.equalsIgnoreCase("undo")) {
+ undo();
+ } else if (command.equalsIgnoreCase("remove")
+ || command.equalsIgnoreCase("rm")) {
+ remove(args);
+ } else {
+ add(command, args);
+ }
}
} catch (IOException e) {
System.out.println("Error: something went wrong with stdin, exiting...");
@@ -147,232 +183,233 @@ public class CardbaseCLI {
}
/**
- * Handle console commands appropriately.
- *
- * @param commands an array of {@code String} containing the arguments in order.
+ * Print help to console.
*/
- private void interpret(String[] commands) {
- if (commands.length > 0) {
- switch (commands[0]) {
- /*
- * Show help.
- */
- case "help":
- System.out.println(help);
- break;
-
- /*
- * Write current cardbase to file.
- */
- case "write":
- File outputFile;
- if (commands.length > 1) {
- outputFile = new File(sanitiseFileName(commands[1]));
- } else {
- outputFile = cardbaseFile;
- }
-
- if (outputFile != null) {
- if (outputFile.exists() && (!outputFile.isFile() || !outputFile.canWrite())) {
- System.out.println("Could not write to \"" + outputFile.getAbsolutePath() + "\".");
- return;
- }
- // handle these exceptions locally - they don't necessarily mean the program should halt.
- try {
- IO.writeCardbase(outputFile, cbm.cardbase);
- // we are now working off outputFile, which may or may not be the same as cardbaseFile at this point
- cardbaseFile = outputFile;
- System.out.println("Cardbase was saved to \"" + outputFile.getAbsolutePath() + "\". "
- + "Subsequent writes will be done to this same file unless otherwise requested.");
- savePrompt = false;
- } catch (JsonGenerationException | JsonMappingException e) {
- System.out.println("Error: something terrible happened to the internal cardbase data structure. Oops.");
- e.printStackTrace();
- } catch (IOException e) {
- System.out.println("Error: lost contact with the output file, try again?");
- e.printStackTrace();
- }
- } else {
- System.out.println("Please provide a file name.");
- }
- break;
-
- /*
- * Exit procedure.
- */
- case "exit":
- if (savePrompt) {
- System.out.println("Don't forget to save. If you really wish to quit without saving, type \"exit\" again.");
+ public void help() {
+ System.out.println(help);
+ }
+
+ /**
+ * Write current cardbase to file.
+ *
+ * @param args optionally the file to which to write.
+ */
+ public void write(String[] args) {
+ File outputFile;
+ // user-provided file overrides everything else
+ if (args.length > 0) {
+ outputFile = new File(sanitiseFileName(args[0]));
+ } else {
+ outputFile = cardbaseFile;
+ }
+
+ if (outputFile != null) {
+ if (outputFile.exists() && (!outputFile.isFile() || !outputFile.canWrite())) {
+ System.out.println("Could not write to \"" + outputFile.getAbsolutePath() + "\".");
+ } else {
+ // handle these exceptions locally - they don't necessarily mean the program should exit
+ try {
+ cardbaseManager.writeCardbase(outputFile);
+ // we are now working off outputFile, which may or may not be the same as cardbaseFile at this point
+ cardbaseFile = outputFile;
+ System.out.println("Cardbase was saved to \"" + outputFile.getAbsolutePath() + "\". "
+ + "Subsequent writes will be done to this same file unless otherwise requested.");
savePrompt = false;
- } else {
- exit = true;
- }
- break;
-
- /*
- * Print a list of valid set codes.
- */
- case "sets":
- for (CardSet set : cbm.getCardSetList()) {
- // MetaCardSet has an overridden toString().
- System.out.println(set);
- }
- break;
-
- /*
- * Select a set.
- */
- case "set":
- // first check if the set code is valid
- for (CardSet set : cbm.getCardSetList()) {
- if (set.code.equalsIgnoreCase(commands[1])) {
- // if the set is already cached, use that
- if (setCache.containsKey(set.code)) {
- selectedSet = setCache.get(set.code);
- } else {
- // if not, download it and cache it
- try {
- selectedSet = IO.getCardSet(set.code);
- setCache.put(set.code, selectedSet);
- } catch (JsonParseException e) {
- System.out.println("Error: JSON fetched from upstream was not formatted properly.");
- e.printStackTrace();
- return;
- } catch (JsonMappingException e) {
- System.out.println("Error: JSON fetched from upstream does not match the data structure used internally.");
- e.printStackTrace();
- return;
- } catch (IOException e) {
- System.out.println("Error: JSON could not be fetched from upstream.");
- e.printStackTrace();
- return;
- }
- }
- System.out.println("Selected set: " + set.name + ".");
- // undoing is not allowed if the set is changed - it would get tricky
- lastAction = null;
- return;
- }
- }
- System.out.println("\"" + commands[1] + "\" does not correspond to any set (use \"sets\" to see all valid set codes).");
- break;
-
- /*
- * Print a brief list of the whole cardbase.
- */
- case "glance":
- Card current;
- int total = 0;
- for (Iterator<Card> i = cbm.cardIterator(); i.hasNext();) {
- current = i.next();
- printGlance(current);
- total += current.count;
+ } catch (JsonGenerationException | JsonMappingException e) {
+ System.out.println("Error: something terrible happened to the internal cardbase data structure. Oops.");
+ e.printStackTrace();
+ } catch (IOException e) {
+ System.out.println("Error: lost contact with the output file, try again?");
+ e.printStackTrace();
}
- System.out.println("Total: " + total);
- break;
-
- /*
- * Print detailed information of a single card or the whole cardbase.
- */
- case "peruse":
- // if a card is specified, peruse only that
- if (commands.length > 1) {
- if (selectedSet != null) {
- Card card = cbm.getCard(selectedSet.code, commands[1]);
- if (card != null) {
- printPerusal(card);
- } else {
- System.out.println("Card not in cardbase.");
- }
- } else {
- System.out.println("Please select a set before perusing a specific card.");
- }
+ }
+ } else {
+ System.out.println("Please provide a file name.");
+ }
+ }
+
+ /**
+ * Exit procedure.
+ */
+ public void exit() {
+ if (savePrompt) {
+ System.out.println("Don't forget to save. If you really wish to quit without saving, type \"exit\" again.");
+ savePrompt = false;
+ } else {
+ exit = true;
+ }
+ }
+
+ /**
+ * Print a list of valid set codes.
+ */
+ public void sets() {
+ for (CardSet set : cardbaseManager.getCardSetList()) {
+ // CardSet has an overridden toString().
+ System.out.println(set);
+ }
+ }
+
+ /**
+ * Select a set.
+ *
+ * @param args the code of the chosen set.
+ */
+ public void set(String[] args) {
+ if (args.length > 0) {
+ try {
+ selectedSet = cardbaseManager.getFullCardSet(args[0]);
+ // if the set code is invalid, null is returned
+ if (selectedSet != null) {
+ System.out.println("Selected set: " + selectedSet.getName() + ".");
+ // undoing is not allowed if the set is changed - it would get tricky
+ lastAction = null;
} else {
- // peruse all cards in cardbase
- for (Iterator<Card> i = cbm.cardIterator(); i.hasNext();) {
- printPerusal(i.next());
- }
+ System.out.println("\"" + args[0] + "\" does not correspond to any set (use \"sets\" to see all valid set codes).");
}
- break;
-
- /*
- * Undo previous action.
- */
- case "undo":
- if (lastAction != null) {
- if (lastAction == Action.ADD) {
- remove(lastAction.card, lastAction.count);
- } else if (lastAction == Action.REMOVE) {
- add(lastAction.card, lastAction.count);
- }
- // can only undo once
- lastAction = null;
+ } catch (JsonParseException e) {
+ System.out.println("Error: JSON fetched from upstream was not formatted properly.");
+ e.printStackTrace();
+ return;
+ } catch (JsonMappingException e) {
+ System.out.println("Error: JSON fetched from upstream does not match the data structure used internally.");
+ e.printStackTrace();
+ return;
+ } catch (IOException e) {
+ System.out.println("Error: JSON could not be fetched from upstream.");
+ e.printStackTrace();
+ return;
+ }
+ } else {
+ System.out.println("Please enter a set code (use \"sets\" to see all valid set codes).");
+ }
+ }
+
+ /**
+ * Print a brief list of the whole cardbase.
+ */
+ public void glance() {
+ Card current;
+ int total = 0;
+ for (Iterator<Card> i = cardbaseManager.cardIterator(); i.hasNext();) {
+ current = i.next();
+ printGlance(current);
+ total += current.count;
+ }
+ System.out.println("Total: " + total);
+ }
+
+ /**
+ * Print detailed information of a single card or the whole cardbase.
+ *
+ * @param args optionally a card within the set (by number) to peruse.
+ */
+ public void peruse(String[] args) {
+ // if a card is specified, peruse only that
+ if (args.length > 0) {
+ if (selectedSet != null) {
+ Card card = cardbaseManager.getCard(selectedSet.getCode(), args[0]);
+ if (card != null) {
+ printPerusal(card);
} else {
- System.out.println("Nothing to undo.");
+ System.out.println("Card not in cardbase.");
}
- break;
-
- /*
- * Remove one or more of a card.
- */
- case "remove":
- if (selectedSet != null) {
- if (commands.length > 1) {
- Card cardToRemove = selectedSet.getCardByNumber(commands[1]);
- if (cardToRemove != null) {
- Integer count = 1;
- if (commands.length > 2 && commands[2].matches("[0-9]+")) {
- count = Integer.valueOf(commands[2]);
- if (count <= 0) {
- System.out.println("Can't remove " + count + " cards.");
- return;
- }
- }
- remove(cardToRemove, count);
- } else {
- System.out.println(commands[1] + " does not correspond to a card in " + selectedSet.name + ".");
+ } else {
+ System.out.println("Please select a set before perusing a specific card.");
+ }
+ } else {
+ // peruse all cards in cardbase
+ Card current;
+ int total = 0;
+ for (Iterator<Card> i = cardbaseManager.cardIterator(); i.hasNext();) {
+ current = i.next();
+ printPerusal(current);
+ total += current.count;
+ }
+ System.out.println("Total: " + total);
+ }
+ }
+
+ /**
+ * Undo previous action.
+ */
+ public void undo() {
+ if (lastAction != null) {
+ if (lastAction == Action.ADD) {
+ removeCard(lastAction.card, lastAction.count);
+ } else if (lastAction == Action.REMOVE) {
+ addCard(lastAction.card, lastAction.count);
+ }
+ // can only undo once
+ lastAction = null;
+ } else {
+ System.out.println("Nothing to undo.");
+ }
+ }
+
+ /**
+ * Remove one or more of a card.
+ *
+ * @param args the set number of the card to remove and optionally the count to be removed.
+ */
+ public void remove(String[] args) {
+ if (selectedSet != null) {
+ if (args.length > 0) {
+ Card cardToRemove = selectedSet.getCardByNumber(args[0]);
+ if (cardToRemove != null) {
+ Integer count = 1;
+ if (args.length > 1 && args[1].matches("[0-9]+")) {
+ count = Integer.valueOf(args[1]);
+ if (count <= 0) {
+ System.out.println("Can't remove " + count + " cards.");
+ return;
}
- } else {
- System.out.println("Please specify a card number to remove.");
}
+ removeCard(cardToRemove, count);
} else {
- System.out.println("Select a set before removing cards.");
+ System.out.println(args[0] + " does not correspond to a card in " + selectedSet.getName() + ".");
}
- break;
-
- /*
- * Add one or more of a card.
- */
- default:
- if (selectedSet != null) {
- // a blank line after adding a card repeats the addition unlimitedly
- if (commands.length == 1 && commands[0].isEmpty()) {
- if (lastAction == Action.ADD)
- add(lastAction.card, lastAction.count);
- } else {
- Card cardToAdd = selectedSet.getCardByNumber(commands[0]);
- if (cardToAdd != null) {
- Integer count = 1;
- if (commands.length > 1 && commands[1].matches("[0-9]+")) {
- count = Integer.valueOf(commands[1]);
- if (count <= 0) {
- System.out.println("Can't add " + count + " cards.");
- return;
- }
- }
- add(cardToAdd, count);
- } else {
- System.out.println(commands[0] + " does not correspond to a card in " + selectedSet.name + ".");
+ } else {
+ System.out.println("Please specify a card number to remove.");
+ }
+ } else {
+ System.out.println("Select a set before removing cards.");
+ }
+ }
+
+ /**
+ * Add one or more of a card.
+ *
+ * @param number the number of the card to add.
+ * @param args optionally the count to add.
+ */
+ public void add(String number, String[] args) {
+ if (selectedSet != null) {
+ // a blank line after adding a card repeats the addition unlimitedly
+ if (number.isEmpty()) {
+ if (lastAction == Action.ADD)
+ addCard(lastAction.card, lastAction.count);
+ } else {
+ Card cardToAdd = selectedSet.getCardByNumber(number);
+ if (cardToAdd != null) {
+ Integer count = 1;
+ if (args.length > 0 && args[0].matches("[0-9]+")) {
+ count = Integer.valueOf(args[0]);
+ if (count <= 0) {
+ System.out.println("Can't add " + count + " cards.");
+ return;
}
}
+ addCard(cardToAdd, count);
} else {
- System.out.println("Select a set before adding cards.");
+ System.out.println(number + " does not correspond to a card in " + selectedSet.getName() + ".");
}
- break;
}
+ } else {
+ System.out.println("Select a set before adding cards.");
}
}
-
+
/**
* Add the specified count of the specified card
* to the cardbase.
@@ -380,16 +417,14 @@ public class CardbaseCLI {
* @param card the card to add.
* @param count the number of times to add it.
*/
- private void add(Card card, Integer count) {
- // MTG JSON does not contain this information, but it is useful for sorting
- card.setCode = selectedSet.code;
- cbm.addCard(card, count);
+ private void addCard(Card card, Integer count) {
+ cardbaseManager.addCard(card, count);
System.out.println("Added " + count + "x " + card.name + ".");
savePrompt = true;
lastAction = Action.ADD;
lastAction.set(card, count);
}
-
+
/**
* Remove the specified count of the specified card
* from the cardbase.
@@ -397,14 +432,19 @@ public class CardbaseCLI {
* @param card the card to remove.
* @param count the number of times to remove it.
*/
- private void remove(Card card, Integer count) {
- cbm.removeCard(card, count);
- System.out.println("Removed " + count + "x " + card.name + ".");
- savePrompt = true;
- lastAction = Action.REMOVE;
- lastAction.set(card, count);
+ private void removeCard(Card card, Integer count) {
+ Integer removed = cardbaseManager.removeCard(card, count);
+ if (removed > 0) {
+ System.out.println("Removed " + removed + "x " + card.name + ".");
+ savePrompt = true;
+ lastAction = Action.REMOVE;
+ lastAction.set(card, removed);
+ } else {
+ System.out.println(card.name + " is not in the cardbase.");
+ }
+
}
-
+
/**
* Return a {@code String} that is guaranteed to be a legal file name.
*
@@ -420,7 +460,7 @@ public class CardbaseCLI {
}
return name;
}
-
+
/**
* Prints a glance of the specified card. A glance contains simply
* the card count, name, set code and set number.
@@ -430,7 +470,7 @@ public class CardbaseCLI {
private void printGlance(Card card) {
System.out.println(String.format("%1$-4d %2$s (%3$s, %4$s)", card.count, card.name, card.setCode, card.number));
}
-
+
/**
* Prints a perusal of the specified card. A perusal contains more
* information than a glance, but not every single field the card has
@@ -444,10 +484,10 @@ public class CardbaseCLI {
if (card.manaCost != null) System.out.println("\tCost: " + card.manaCost);
if (card.power != null && card.toughness != null) System.out.println("\t" + card.power + "/" + card.toughness);
if (card.loyalty != null) System.out.println("\tLoyalty: " + card.loyalty);
-
+
if (card.text != null) System.out.println("\t" + card.text.replaceAll("\n", "\n\t"));
if (card.flavor != null) System.out.println("\t" + card.flavor.replaceAll("\n", "\n\t"));
-
+
if (card.rarity != null) System.out.println("\t" + card.rarity);
if (card.multiverseid != null) System.out.println("\tMID: " + card.multiverseid);
if (card.artist != null) System.out.println("\tIllus. " + card.artist);