aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--res/setlist.json1
-rw-r--r--src/eu/equalparts/cardbase/data/CardSet.java13
-rw-r--r--src/eu/equalparts/cardbase/data/Cardbase.java6
-rw-r--r--src/eu/equalparts/cardbase/data/CardbaseManager.java129
-rw-r--r--src/eu/equalparts/cardbase/data/FullCardSet.java12
-rw-r--r--src/eu/equalparts/cardbase/io/IO.java119
-rw-r--r--src/eu/equalparts/cardbase/standalone/CardbaseCLI.java83
-rw-r--r--src/eu/equalparts/cardbase/utils/IO.java35
-rw-r--r--src/eu/equalparts/cardbase/utils/MTGUniverse.java152
9 files changed, 300 insertions, 250 deletions
diff --git a/res/setlist.json b/res/setlist.json
new file mode 100644
index 0000000..bb5f4d6
--- /dev/null
+++ b/res/setlist.json
@@ -0,0 +1 @@
+[{"name":"Limited Edition Alpha","code":"LEA","releaseDate":"1993-08-05"},{"name":"Limited Edition Beta","code":"LEB","releaseDate":"1993-10-01"},{"name":"Arabian Nights","code":"ARN","releaseDate":"1993-12-01"},{"name":"Unlimited Edition","code":"2ED","releaseDate":"1993-12-01"},{"name":"Dragon Con","code":"pDRC","releaseDate":"1994-01-01"},{"name":"Antiquities","code":"ATQ","releaseDate":"1994-03-01"},{"name":"Revised Edition","code":"3ED","releaseDate":"1994-04-01"},{"name":"Legends","code":"LEG","releaseDate":"1994-06-01"},{"name":"The Dark","code":"DRK","releaseDate":"1994-08-01"},{"name":"Media Inserts","code":"pMEI","releaseDate":"1995-01-01"},{"name":"Fallen Empires","code":"FEM","releaseDate":"1994-11-01"},{"name":"Legend Membership","code":"pLGM","releaseDate":"1995-01-01"},{"name":"Fourth Edition","code":"4ED","releaseDate":"1995-04-01"},{"name":"Ice Age","code":"ICE","releaseDate":"1995-06-01"},{"name":"Chronicles","code":"CHR","releaseDate":"1995-07-01"},{"name":"Homelands","code":"HML","releaseDate":"1995-10-01"},{"name":"Alliances","code":"ALL","releaseDate":"1996-06-10"},{"name":"Rivals Quick Start Set","code":"RQS","releaseDate":"1996-07-01"},{"name":"Arena League","code":"pARL","releaseDate":"1996-08-02"},{"name":"Celebration","code":"pCEL","releaseDate":"1996-08-14"},{"name":"Mirage","code":"MIR","releaseDate":"1996-10-08"},{"name":"Multiverse Gift Box","code":"MGB","releaseDate":"1996-11-01"},{"name":"Introductory Two-Player Set","code":"ITP","releaseDate":"1996-12-31"},{"name":"Visions","code":"VIS","releaseDate":"1997-02-03"},{"name":"Fifth Edition","code":"5ED","releaseDate":"1997-03-24"},{"name":"Portal Demo Game","code":"pPOD","releaseDate":"1997-05-01"},{"name":"Portal","code":"POR","releaseDate":"1997-05-01"},{"name":"Vanguard","code":"VAN","releaseDate":"1997-05-01"},{"name":"Weatherlight","code":"WTH","releaseDate":"1997-06-09"},{"name":"Prerelease Events","code":"pPRE","releaseDate":"1997-10-04"},{"name":"Tempest","code":"TMP","releaseDate":"1997-10-14"},{"name":"Stronghold","code":"STH","releaseDate":"1998-03-02"},{"name":"Portal Second Age","code":"PO2","releaseDate":"1998-06-01"},{"name":"Judge Gift Program","code":"pJGP","releaseDate":"1998-06-01"},{"name":"Exodus","code":"EXO","releaseDate":"1998-06-15"},{"name":"Unglued","code":"UGL","releaseDate":"1998-08-11"},{"name":"Asia Pacific Land Program","code":"pALP","releaseDate":"1998-09-01"},{"name":"Urza's Saga","code":"USG","releaseDate":"1998-10-12"},{"name":"Anthologies","code":"ATH","releaseDate":"1998-11-01"},{"name":"Urza's Legacy","code":"ULG","releaseDate":"1999-02-15"},{"name":"Classic Sixth Edition","code":"6ED","releaseDate":"1999-04-21"},{"name":"Portal Three Kingdoms","code":"PTK","releaseDate":"1999-05-01"},{"name":"Urza's Destiny","code":"UDS","releaseDate":"1999-06-07"},{"name":"Starter 1999","code":"S99","releaseDate":"1999-07-01"},{"name":"Guru","code":"pGRU","releaseDate":"1999-07-12"},{"name":"Worlds","code":"pWOR","releaseDate":"1999-08-04"},{"name":"Wizards of the Coast Online Store","code":"pWOS","releaseDate":"1999-09-04"},{"name":"Mercadian Masques","code":"MMQ","releaseDate":"1999-10-04"},{"name":"Battle Royale Box Set","code":"BRB","releaseDate":"1999-11-12"},{"name":"Super Series","code":"pSUS","releaseDate":"1999-12-01"},{"name":"Friday Night Magic","code":"pFNM","releaseDate":"2000-02-01"},{"name":"European Land Program","code":"pELP","releaseDate":"2000-02-05"},{"name":"Nemesis","code":"NMS","releaseDate":"2000-02-14"},{"name":"Starter 2000","code":"S00","releaseDate":"2000-04-01"},{"name":"Prophecy","code":"PCY","releaseDate":"2000-06-05"},{"name":"Beatdown Box Set","code":"BTD","releaseDate":"2000-10-01"},{"name":"Invasion","code":"INV","releaseDate":"2000-10-02"},{"name":"Planeshift","code":"PLS","releaseDate":"2001-02-05"},{"name":"Seventh Edition","code":"7ED","releaseDate":"2001-04-11"},{"name":"Magic Player Rewards","code":"pMPR","releaseDate":"2001-05-01"},{"name":"Apocalypse","code":"APC","releaseDate":"2001-06-04"},{"name":"Odyssey","code":"ODY","releaseDate":"2001-10-01"},{"name":"Deckmasters","code":"DKM","releaseDate":"2001-12-01"},{"name":"Torment","code":"TOR","releaseDate":"2002-02-04"},{"name":"Judgment","code":"JUD","releaseDate":"2002-05-27"},{"name":"Onslaught","code":"ONS","releaseDate":"2002-10-07"},{"name":"Legions","code":"LGN","releaseDate":"2003-02-03"},{"name":"Scourge","code":"SCG","releaseDate":"2003-05-26"},{"name":"Release Events","code":"pREL","releaseDate":"2003-07-26"},{"name":"Eighth Edition","code":"8ED","releaseDate":"2003-07-28"},{"name":"Mirrodin","code":"MRD","releaseDate":"2003-10-02"},{"name":"Darksteel","code":"DST","releaseDate":"2004-02-06"},{"name":"Fifth Dawn","code":"5DN","releaseDate":"2004-06-04"},{"name":"Champions of Kamigawa","code":"CHK","releaseDate":"2004-10-01"},{"name":"Unhinged","code":"UNH","releaseDate":"2004-11-20"},{"name":"Betrayers of Kamigawa","code":"BOK","releaseDate":"2005-02-04"},{"name":"Saviors of Kamigawa","code":"SOK","releaseDate":"2005-06-03"},{"name":"Ninth Edition","code":"9ED","releaseDate":"2005-07-29"},{"name":"Ravnica: City of Guilds","code":"RAV","releaseDate":"2005-10-07"},{"name":"Two-Headed Giant Tournament","code":"p2HG","releaseDate":"2005-12-09"},{"name":"WPN and Gateway","code":"pWPN","releaseDate":"2006-01-01"},{"name":"Guildpact","code":"GPT","releaseDate":"2006-02-03"},{"name":"Champs and States","code":"pCMP","releaseDate":"2006-03-18"},{"name":"Dissension","code":"DIS","releaseDate":"2006-05-05"},{"name":"Coldsnap","code":"CSP","releaseDate":"2006-07-21"},{"name":"Coldsnap Theme Decks","code":"CST","releaseDate":"2006-07-21"},{"name":"Time Spiral","code":"TSP","releaseDate":"2006-10-06"},{"name":"Time Spiral \"Timeshifted\"","code":"TSB","releaseDate":"2006-10-06"},{"name":"Happy Holidays","code":"pHHO","releaseDate":"2006-12-31"},{"name":"Planar Chaos","code":"PLC","releaseDate":"2007-02-02"},{"name":"Pro Tour","code":"pPRO","releaseDate":"2007-02-09"},{"name":"Grand Prix","code":"pGPX","releaseDate":"2007-02-24"},{"name":"Future Sight","code":"FUT","releaseDate":"2007-05-04"},{"name":"Tenth Edition","code":"10E","releaseDate":"2007-07-13"},{"name":"Magic Game Day","code":"pMGD","releaseDate":"2007-07-14"},{"name":"Masters Edition","code":"MED","releaseDate":"2007-09-10"},{"name":"Lorwyn","code":"LRW","releaseDate":"2007-10-12"},{"name":"Duel Decks: Elves vs. Goblins","code":"EVG","releaseDate":"2007-11-16"},{"name":"Launch Parties","code":"pLPA","releaseDate":"2008-02-01"},{"name":"Morningtide","code":"MOR","releaseDate":"2008-02-01"},{"name":"15th Anniversary","code":"p15A","releaseDate":"2008-04-01"},{"name":"Shadowmoor","code":"SHM","releaseDate":"2008-05-02"},{"name":"Summer of Magic","code":"pSUM","releaseDate":"2007-07-21"},{"name":"Eventide","code":"EVE","releaseDate":"2008-07-25"},{"name":"From the Vault: Dragons","code":"DRB","releaseDate":"2008-08-29"},{"name":"Masters Edition II","code":"ME2","releaseDate":"2008-09-22"},{"name":"Shards of Alara","code":"ALA","releaseDate":"2008-10-03"},{"name":"Duel Decks: Jace vs. Chandra","code":"DD2","releaseDate":"2008-11-07"},{"name":"Conflux","code":"CON","releaseDate":"2009-02-06"},{"name":"Duel Decks: Divine vs. Demonic","code":"DDC","releaseDate":"2009-04-10"},{"name":"Alara Reborn","code":"ARB","releaseDate":"2009-04-30"},{"name":"Magic 2010","code":"M10","releaseDate":"2009-07-17"},{"name":"From the Vault: Exiled","code":"V09","releaseDate":"2009-08-28"},{"name":"Planechase","code":"HOP","releaseDate":"2009-09-04"},{"name":"Masters Edition III","code":"ME3","releaseDate":"2009-09-07"},{"name":"Zendikar","code":"ZEN","releaseDate":"2009-10-02"},{"name":"Duel Decks: Garruk vs. Liliana","code":"DDD","releaseDate":"2009-10-30"},{"name":"Premium Deck Series: Slivers","code":"H09","releaseDate":"2009-11-20"},{"name":"Worldwake","code":"WWK","releaseDate":"2010-02-05"},{"name":"Duel Decks: Phyrexia vs. the Coalition","code":"DDE","releaseDate":"2010-03-19"},{"name":"Rise of the Eldrazi","code":"ROE","releaseDate":"2010-04-23"},{"name":"Duels of the Planeswalkers","code":"DPA","releaseDate":"2010-06-04"},{"name":"Archenemy","code":"ARC","releaseDate":"2010-06-18"},{"name":"Magic 2011","code":"M11","releaseDate":"2010-07-16"},{"name":"From the Vault: Relics","code":"V10","releaseDate":"2010-08-27"},{"name":"Duel Decks: Elspeth vs. Tezzeret","code":"DDF","releaseDate":"2010-09-03"},{"name":"Scars of Mirrodin","code":"SOM","releaseDate":"2010-10-01"},{"name":"Premium Deck Series: Fire and Lightning","code":"PD2","releaseDate":"2010-11-19"},{"name":"Masters Edition IV","code":"ME4","releaseDate":"2011-01-10"},{"name":"Mirrodin Besieged","code":"MBS","releaseDate":"2011-02-04"},{"name":"Duel Decks: Knights vs. Dragons","code":"DDG","releaseDate":"2011-04-01"},{"name":"New Phyrexia","code":"NPH","releaseDate":"2011-05-13"},{"name":"Magic: The Gathering-Commander","code":"CMD","releaseDate":"2011-06-17"},{"name":"Magic 2012","code":"M12","releaseDate":"2011-07-15"},{"name":"From the Vault: Legends","code":"V11","releaseDate":"2011-08-26"},{"name":"Duel Decks: Ajani vs. Nicol Bolas","code":"DDH","releaseDate":"2011-09-02"},{"name":"Innistrad","code":"ISD","releaseDate":"2011-09-30"},{"name":"Premium Deck Series: Graveborn","code":"PD3","releaseDate":"2011-11-18"},{"name":"Dark Ascension","code":"DKA","releaseDate":"2012-02-03"},{"name":"Duel Decks: Venser vs. Koth","code":"DDI","releaseDate":"2012-03-30"},{"name":"Avacyn Restored","code":"AVR","releaseDate":"2012-05-04"},{"name":"Planechase 2012 Edition","code":"PC2","releaseDate":"2012-06-01"},{"name":"Magic 2013","code":"M13","releaseDate":"2012-07-13"},{"name":"From the Vault: Realms","code":"V12","releaseDate":"2012-08-31"},{"name":"Duel Decks: Izzet vs. Golgari","code":"DDJ","releaseDate":"2012-09-07"},{"name":"Return to Ravnica","code":"RTR","releaseDate":"2012-10-05"},{"name":"Commander's Arsenal","code":"CM1","releaseDate":"2012-11-02"},{"name":"Gatecrash","code":"GTC","releaseDate":"2013-02-01"},{"name":"Duel Decks: Sorin vs. Tibalt","code":"DDK","releaseDate":"2013-03-15"},{"name":"World Magic Cup Qualifiers","code":"pWCQ","releaseDate":"2013-04-06"},{"name":"Dragon's Maze","code":"DGM","releaseDate":"2013-05-03"},{"name":"Modern Masters","code":"MMA","releaseDate":"2013-06-07"},{"name":"Magic 2014 Core Set","code":"M14","releaseDate":"2013-07-19"},{"name":"From the Vault: Twenty","code":"V13","releaseDate":"2013-08-23"},{"name":"Duel Decks: Heroes vs. Monsters","code":"DDL","releaseDate":"2013-09-06"},{"name":"Theros","code":"THS","releaseDate":"2013-09-27"},{"name":"Commander 2013 Edition","code":"C13","releaseDate":"2013-11-01"},{"name":"Born of the Gods","code":"BNG","releaseDate":"2014-02-07"},{"name":"Duel Decks: Jace vs. Vraska","code":"DDM","releaseDate":"2014-03-14"},{"name":"Journey into Nyx","code":"JOU","releaseDate":"2014-05-02"},{"name":"Modern Event Deck 2014","code":"MD1","releaseDate":"2014-05-30"},{"name":"Magic: The Gathering—Conspiracy","code":"CNS","releaseDate":"2014-06-06"},{"name":"Vintage Masters","code":"VMA","releaseDate":"2014-06-16"},{"name":"Magic 2015 Core Set","code":"M15","releaseDate":"2014-07-18"},{"name":"From the Vault: Annihilation (2014)","code":"V14","releaseDate":"2014-08-22"},{"name":"Duel Decks: Speed vs. Cunning","code":"DDN","releaseDate":"2014-09-05"},{"name":"Khans of Tarkir","code":"KTK","releaseDate":"2014-09-26"},{"name":"Commander 2014","code":"C14","releaseDate":"2014-11-07"},{"name":"Duel Decks Anthology, Divine vs. Demonic","code":"DD3_DVD","releaseDate":"2014-12-05"},{"name":"Duel Decks Anthology, Elves vs. Goblins","code":"DD3_EVG","releaseDate":"2014-12-05"},{"name":"Duel Decks Anthology, Garruk vs. Liliana","code":"DD3_GVL","releaseDate":"2014-12-05"},{"name":"Duel Decks Anthology, Jace vs. Chandra","code":"DD3_JVC","releaseDate":"2014-12-05"},{"name":"Ugin's Fate promos","code":"FRF_UGIN","releaseDate":"2015-01-17"},{"name":"Fate Reforged","code":"FRF","releaseDate":"2015-01-23"},{"name":"Duel Decks: Elspeth vs. Kiora","code":"DDO","releaseDate":"2015-02-27"},{"name":"Dragons of Tarkir","code":"DTK","releaseDate":"2015-03-27"},{"name":"Tempest Remastered","code":"TPR","releaseDate":"2015-05-06"},{"name":"Modern Masters 2015 Edition","code":"MM2","releaseDate":"2015-05-22"}] \ No newline at end of file
diff --git a/src/eu/equalparts/cardbase/data/CardSet.java b/src/eu/equalparts/cardbase/data/CardSet.java
index b9720bf..b06be7c 100644
--- a/src/eu/equalparts/cardbase/data/CardSet.java
+++ b/src/eu/equalparts/cardbase/data/CardSet.java
@@ -2,26 +2,26 @@ package eu.equalparts.cardbase.data;
public class CardSet {
- private String name = "";
- private String code = "";
- private String releaseDate = "";
+ private String name;
+ private String code;
+ private String releaseDate;
/**
- * @return the name
+ * @return the set's name.
*/
public String getName() {
return name;
}
/**
- * @return the code
+ * @return the set code.
*/
public String getCode() {
return code;
}
/**
- * @return the releaseDate
+ * @return the set's release date.
*/
public String getReleaseDate() {
return releaseDate;
@@ -31,5 +31,4 @@ public class CardSet {
public String toString() {
return String.format("%1$-12s : %2$s", code, name, releaseDate);
}
-
}
diff --git a/src/eu/equalparts/cardbase/data/Cardbase.java b/src/eu/equalparts/cardbase/data/Cardbase.java
index 1c2aa12..021fac2 100644
--- a/src/eu/equalparts/cardbase/data/Cardbase.java
+++ b/src/eu/equalparts/cardbase/data/Cardbase.java
@@ -8,9 +8,9 @@ public class Cardbase {
public ArrayList<Deck> decks = new ArrayList<>();
/**
- * @param setCode
- * @param number
- * @return the card if found, else null.
+ * @param setCode the set to which the requested card belongs.
+ * @param number the requested card's set number.
+ * @return the requested {@code Card} or null if no card is found.
*/
public Card getCardByNumber(String setCode, String number) {
for (Card card : cards) {
diff --git a/src/eu/equalparts/cardbase/data/CardbaseManager.java b/src/eu/equalparts/cardbase/data/CardbaseManager.java
index dfef3c8..d6ba6ee 100644
--- a/src/eu/equalparts/cardbase/data/CardbaseManager.java
+++ b/src/eu/equalparts/cardbase/data/CardbaseManager.java
@@ -1,122 +1,93 @@
package eu.equalparts.cardbase.data;
import java.io.File;
import java.io.IOException;
-import java.util.ArrayList;
-import java.util.HashMap;
import java.util.Iterator;
import com.fasterxml.jackson.core.JsonGenerationException;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.databind.JsonMappingException;
-import eu.equalparts.cardbase.io.IO;
+import eu.equalparts.cardbase.utils.IO;
+/**
+ * Provides a variety of utility methods to interact with the loaded cardbase.
+ *
+ * @author Eduardo Pedroni
+ */
public class CardbaseManager {
- private ArrayList<CardSet> cardSets;
-
- /**
- * A cache of CardSets to avoid querying the server many times for the same information.
- */
- private HashMap<String, FullCardSet> cardSetCache = new HashMap<String, FullCardSet>();
/**
- *
+ * The cardbase being managed.
*/
private Cardbase cardbase;
-
/**
- * Parse a cardbase file and create an associated Cardbase object.
- *
- * @param cardbaseFile
+ * Creates an empty cardbase.
*
- * @throws JsonParseException if underlying input contains invalid content of type JsonParser supports (JSON for default case).
- * @throws JsonMappingException if the input JSON structure does not match structure expected for result type (or has other mismatch issues).
- * @throws IOException if a low-level I/O problem (unexpected end-of-input, network error) occurs.
*/
- public CardbaseManager(File cardbaseFile) throws JsonParseException, JsonMappingException, IOException {
- cardSets = IO.getCardSetList();
- cardbase = IO.readCardbase(cardbaseFile);
+ public CardbaseManager() {
+ cardbase = new Cardbase();
}
-
+
/**
- * Create an empty Cardbase.
+ * Initialises the cardbase with the contents of a file.
+ *
+ * @param cardbaseFile the cardbase JSON to load.
*
- * @throws JsonParseException if underlying input contains invalid content of type JsonParser supports (JSON for default case).
- * @throws JsonMappingException if the input JSON structure does not match structure expected for result type (or has other mismatch issues).
+ * @throws JsonParseException if the specified file does not contain valid JSON.
+ * @throws JsonMappingException if the specified file structure does not match that of {@code Cardbase}.
* @throws IOException if a low-level I/O problem (unexpected end-of-input, network error) occurs.
*/
- public CardbaseManager() throws JsonParseException, JsonMappingException, IOException {
- cardSets = IO.getCardSetList();
- cardbase = new Cardbase();
- }
-
- public ArrayList<CardSet> getCardSetList() {
- return cardSets;
+ public CardbaseManager(File cardbaseFile) throws JsonParseException, JsonMappingException, IOException {
+ cardbase = IO.jsonMapper.readValue(cardbaseFile, Cardbase.class);
}
- public void writeCardbase(File outputFile) throws JsonGenerationException, JsonMappingException, IOException {
- IO.writeCardbase(outputFile, cardbase);
- }
-
/**
- * Returns the specified set in the form of a {@code FullCardSet} object.
+ * Writes the provided {@code Cardbase} to the provided file in JSON format.
*
- * @param code the code of the set to be returned.
- * @return the requested {@code FullCardSet} or null if no set matches the given code.
+ * @param file the file to which to write the {@code Cardbase}.
+ * @param cardbase the {@code Cardbase} to write out.
*
- * @throws JsonParseException if the upstream JSON is not formatted correctly.
- * @throws JsonMappingException if the upstream JSON does not map to {@code FullCardSet}.
+ * @throws JsonGenerationException if the data structure given does not generate valid JSON.
+ * @throws JsonMappingException if the data structure given does not generate valid JSON as well?
* @throws IOException if a low-level I/O problem (unexpected end-of-input, network error) occurs.
*/
- public FullCardSet getFullCardSet(String code) throws JsonParseException, JsonMappingException, IOException {
- FullCardSet requestedSet = null;
- for (CardSet cardSet : cardSets) {
- if (cardSet.getCode().equalsIgnoreCase(code)) {
- // if the set is cached, no need to fetch
- if (cardSetCache.containsKey(cardSet.getCode())) {
- requestedSet = cardSetCache.get(cardSet.getCode());
- }
- // not cached; fetch, cache and return it
- else {
- requestedSet = IO.getFullCardSet(cardSet.getCode());
- cardSetCache.put(cardSet.getCode(), requestedSet);
- }
- return requestedSet;
- }
- }
- // not found
- return null;
+ public void writeCardbase(File outputFile) throws JsonGenerationException, JsonMappingException, IOException {
+ IO.jsonMapper.writeValue(outputFile, cardbase);
}
/**
- * Add a specific amount of a card to the cardbase.
+ * Adds a specific amount of a card to the cardbase.
* If the card is not already in the cardbase, it is added.
* If it is already present, the count is simply updated.
*
- *
- * @param newCard
- * @param count
+ * @param cardToAdd the card to be added.
+ * @param count the amount of the card to be added.
*/
- public void addCard(Card newCard, Integer count) {
- Card card = cardbase.getCardByNumber(newCard.setCode, newCard.number);
+ public void addCard(Card cardToAdd, Integer count) {
+ Card card = cardbase.getCardByNumber(cardToAdd.setCode, cardToAdd.number);
if (card != null) {
card.count += count;
} else {
- newCard.count = count;
- cardbase.cards.add(newCard);
+ cardToAdd.count = count;
+ cardbase.cards.add(cardToAdd);
}
}
/**
- * Remove a specific amount of a card from the cardbase.
+ * Removes a specific amount of a card from the cardbase.
* If the card is not present in the cardbase, nothing happens.
- * If the card is present in the card, the specified amount is removed.
+ * If the card is present in the cardbase, the specified amount is removed.
* If that amount is equal to or exceeds the count already in the cardbase,
- * the card entry is removed altogether.
+ * the card entry is removed altogether.
+ * <br><br>
+ * In any case, the value returned is the actual number of cards removed.
+ * For example, if 5 Shivan Dragons are in the cardbase and the method is
+ * called to remove 10 Shivan Dragons, the {@code Card} representing the
+ * Shivan Dragon is removed from the cardbase, and the value returned is 5.
*
- * @param cardToRemove
- * @param count
+ * @param cardToRemove the card to be removed.
+ * @param count the amount of the card to be removed.
* @return the number of cards actually removed.
*/
public Integer removeCard(Card cardToRemove, Integer count) {
@@ -135,21 +106,21 @@ public class CardbaseManager {
}
/**
- * @return an iterator to the cards in the cardbase.
+ * @return an iterator to the {@code Card}s in the cardbase.
*/
public Iterator<Card> cardIterator() {
return cardbase.cards.iterator();
}
/**
- * Return a card from the cardBase by setCode and number.
- * If no such card is in the cardbase, return null.
+ * Returns a card from the cardbase by set code and number.
+ * If no such card is in the cardbase, returns null.
*
- * @param code
- * @param string
- * @return
+ * @param setCode the set to which the requested card belongs.
+ * @param number the requested card's set number.
+ * @return the requested {@code Card} or null if no card is found.
*/
- public Card getCard(String code, String number) {
- return cardbase.getCardByNumber(code, number);
+ public Card getCard(String setCode, String number) {
+ return cardbase.getCardByNumber(setCode, number);
}
}
diff --git a/src/eu/equalparts/cardbase/data/FullCardSet.java b/src/eu/equalparts/cardbase/data/FullCardSet.java
index 48488b5..0f58633 100644
--- a/src/eu/equalparts/cardbase/data/FullCardSet.java
+++ b/src/eu/equalparts/cardbase/data/FullCardSet.java
@@ -11,35 +11,35 @@ public class FullCardSet extends CardSet {
private ArrayList<Card> cards;
/**
- * @return the border
+ * @return the set's border type.
*/
public String getBorder() {
return border;
}
/**
- * @return the type
+ * @return the type of the set.
*/
public String getType() {
return type;
}
/**
- * @return the block
+ * @return the set's block.
*/
public String getBlock() {
return block;
}
/**
- * @return the gathererCode
+ * @return the set's Gatherer code.
*/
public String getGathererCode() {
return gathererCode;
}
/**
- * @return the cards
+ * @return a full list of the set's cards.
*/
public ArrayList<Card> getCards() {
return cards;
@@ -49,7 +49,7 @@ public class FullCardSet extends CardSet {
* Searches for a card by number (the one shown on the card itself).
*
* @param number the number of the card to search.
- * @return the card, or null if no card is found with that number.
+ * @return the requested {@code Card}, or null if no card is found with that number.
*/
public Card getCardByNumber(String number) {
for (Card card : cards) {
diff --git a/src/eu/equalparts/cardbase/io/IO.java b/src/eu/equalparts/cardbase/io/IO.java
deleted file mode 100644
index 2275913..0000000
--- a/src/eu/equalparts/cardbase/io/IO.java
+++ /dev/null
@@ -1,119 +0,0 @@
-package eu.equalparts.cardbase.io;
-
-import java.io.File;
-import java.io.IOException;
-import java.net.URL;
-import java.util.ArrayList;
-
-import com.fasterxml.jackson.core.JsonGenerationException;
-import com.fasterxml.jackson.core.JsonParseException;
-import com.fasterxml.jackson.core.type.TypeReference;
-import com.fasterxml.jackson.databind.DeserializationFeature;
-import com.fasterxml.jackson.databind.JsonMappingException;
-import com.fasterxml.jackson.databind.ObjectMapper;
-
-import eu.equalparts.cardbase.data.Card;
-import eu.equalparts.cardbase.data.FullCardSet;
-import eu.equalparts.cardbase.data.Cardbase;
-import eu.equalparts.cardbase.data.CardSet;
-
-/**
- * Class responsible for all I/O operations, such as fetching content from remote servers, reading from
- * and writing to files.
- * <br>
- * All relevant methods here are static, this class should not be instantiated.
- *
- * @author Eduardo Pedroni
- */
-public class IO {
-
- /**
- * The base URL from where the information is fetched.
- */
- private static final String BASE_URL = "http://mtgjson.com/json/";
- /**
- * The URL where the complete list of sets is fetched.
- */
- private static final String SETS_URL = BASE_URL + "SetList.json";
- /**
- * The Jackson ObjectMapper which parses fetched JSON files.
- */
- private static final ObjectMapper mapper = createMapper();
-
- /**
- * Private constructor, this class is not to be instantiated.
- */
- private IO() {}
-
- /**
- * Instantiate and configure Jackson mapper statically.
- *
- * @return the {@code ObjectMapper}, ready to use.
- */
- private static ObjectMapper createMapper() {
- ObjectMapper objectMapper = new ObjectMapper();
- // TODO decide what to do about this
- objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
- return objectMapper;
- }
-
- /**
- * Fetches a complete set by code, where the code is a short string determined by WotC.
- * The full list of valid codes can be acquired with {@code IO.getCardSetList()}.
- *
- * @param setCode the code of the set to be fetched.
- * @return the complete specified set in a {@code FullCardSet} object.
- *
- * @throws JsonParseException if underlying input contains invalid content of type JsonParser supports (JSON for default case).
- * @throws JsonMappingException if the input JSON structure does not match structure expected for result type (or has other mismatch issues).
- * @throws IOException if a low-level I/O problem (unexpected end-of-input, network error) occurs.
- */
- public static FullCardSet getFullCardSet(String setCode) throws JsonParseException, JsonMappingException, IOException {
- FullCardSet fullCardSet = mapper.readValue(new URL(BASE_URL + setCode + ".json"), FullCardSet.class);
- // MTG JSON does not include set code in the card information, but it is useful for sorting
- for (Card card : fullCardSet.getCards()) {
- card.setCode = setCode;
- }
- return fullCardSet;
- }
-
- /**
- * @return a list of all card sets in the form of {@code CardSet} objects.
- *
- * @throws JsonParseException if underlying input contains invalid content of type JsonParser supports (JSON for default case).
- * @throws JsonMappingException if the input JSON structure does not match structure expected for result type (or has other mismatch issues).
- * @throws IOException if a low-level I/O problem (unexpected end-of-input, network error) occurs.
- */
- public static ArrayList<CardSet> getCardSetList() throws JsonParseException, JsonMappingException, IOException {
- return mapper.readValue(new URL(SETS_URL), new TypeReference<ArrayList<CardSet>>() {});
- }
-
- /**
- * Attemps to the read the specified file into a {@code Cardbase.} Exceptions are thrown as outlined below.
- *
- * @param file the file to read.
- * @return a {@code Cardbase} object equivalent to the given file.
- *
- * @throws JsonParseException if underlying input contains invalid content of type JsonParser supports (JSON for default case).
- * @throws JsonMappingException if the input JSON structure does not match structure expected for result type (or has other mismatch issues).
- * @throws IOException if a low-level I/O problem (unexpected end-of-input, network error) occurs.
- */
- public static Cardbase readCardbase(File file) throws JsonParseException, JsonMappingException, IOException {
- return mapper.readValue(file, Cardbase.class);
- }
-
- /**
- * Writes the provided {@code Cardbase} to the provided file in JSON format.
- *
- * @param file the file to which to write the {@code Cardbase}.
- * @param cardbase the {@code Cardbase} to write out.
- *
- * @throws JsonGenerationException if the data structure given does not generate valid JSON.
- * @throws JsonMappingException if the data structure given does not generate valid JSON as well?
- * @throws IOException if a low-level I/O problem (unexpected end-of-input, network error) occurs.
- */
- public static void writeCardbase(File file, Cardbase cardbase) throws JsonGenerationException, JsonMappingException, IOException {
- mapper.writeValue(file, cardbase);
- }
-
-}
diff --git a/src/eu/equalparts/cardbase/standalone/CardbaseCLI.java b/src/eu/equalparts/cardbase/standalone/CardbaseCLI.java
index e0f5433..a8b11ba 100644
--- a/src/eu/equalparts/cardbase/standalone/CardbaseCLI.java
+++ b/src/eu/equalparts/cardbase/standalone/CardbaseCLI.java
@@ -17,6 +17,7 @@ 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.utils.MTGUniverse;
/**
* This provides a lightweight CLI for interacting with cardbase files.
@@ -24,18 +25,16 @@ import eu.equalparts.cardbase.data.CardSet;
* @author Eduardo Pedroni
*/
public class CardbaseCLI {
-
+
/**
* Enum type to store actions.
*
* @author Eduardo Pedroni
*/
private enum Action {
-
ADD, REMOVE;
public Card card;
public Integer count;
-
/**
* Sets both fields at once.
*
@@ -49,6 +48,10 @@ public class CardbaseCLI {
}
/**
+ * Location of the help file.
+ */
+ private static final String HELP_FILE_PATH = "/help";
+ /**
* The last action performed by the user.
*/
private Action lastAction = null;
@@ -61,7 +64,7 @@ public class CardbaseCLI {
*/
private CardbaseManager cardbaseManager;
/**
- * Printed to the console when the user enter the help command.
+ * Printed to the console when the user enters the help command.
*/
private String help = "Not available, check project page on GitHub.";
/**
@@ -69,6 +72,11 @@ public class CardbaseCLI {
*/
private File cardbaseFile = null;
/**
+ * Debug flag is raised when the DEBUG environment variable is set. This causes additional
+ * information to be printed to the console.
+ */
+ private boolean debug = false;
+ /**
* Save flag is raised when cards are added or removed and causes a prompt to be shown
* if the user tries to exit with unsaved changed.
*/
@@ -84,19 +92,7 @@ public class CardbaseCLI {
* @param args the first argument is the cardbase file. Further arguments are ignored.
*/
public static void main(String... args) {
- try {
- 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.
- e.printStackTrace();
- } catch (JsonMappingException e) {
- System.out.println("Error: unexpected fields found in cardbase, it may be from an old version?");
- e.printStackTrace();
- } catch (IOException e) {
- System.out.println("Error: something went wrong reading a file, abort...");
- e.printStackTrace();
- }
+ new CardbaseCLI(args).startInterface();
}
/**
@@ -105,19 +101,37 @@ public class CardbaseCLI {
* 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 {
+ private CardbaseCLI(String... args) {
System.out.println("Welcome to Cardbase CLI!");
+ // set debug flag if we are debugging
+ if (System.getenv("CB_DEBUG") != null) {
+ System.out.println("Debug mode is on.");
+ debug = true;
+ }
+
// make the CardbaseManager
if (args.length > 0) {
File cardbaseFile = new File(args[0]);
if (cardbaseFile.exists() && cardbaseFile.isFile() && cardbaseFile.canRead()) {
System.out.println("Loading cardbase from \"" + args[0] + "\".");
- cardbaseManager = new CardbaseManager(cardbaseFile);
+ try {
+ cardbaseManager = new CardbaseManager(cardbaseFile);
+ } 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.
+ if (debug) e.printStackTrace();
+ System.exit(1);
+ } catch (JsonMappingException e) {
+ System.out.println("Error: unexpected fields found in cardbase, it may be from an old version?");
+ if (debug) e.printStackTrace();
+ System.exit(1);
+ } catch (IOException e) {
+ System.out.println("Error: something went wrong reading cardbase file, abort...");
+ if (debug) e.printStackTrace();
+ System.exit(1);
+ }
} else {
System.out.println(args[0] + " appears to be invalid.");
System.exit(0);
@@ -128,7 +142,7 @@ public class CardbaseCLI {
}
// load help information
- InputStream is = CardbaseCLI.class.getResourceAsStream("/help");
+ InputStream is = CardbaseCLI.class.getResourceAsStream(HELP_FILE_PATH);
if (is != null) {
help = new Scanner(is).useDelimiter("\\Z").next();
} else {
@@ -178,7 +192,7 @@ public class CardbaseCLI {
}
} catch (IOException e) {
System.out.println("Error: something went wrong with stdin, exiting...");
- e.printStackTrace();
+ if (debug) e.printStackTrace();
}
}
@@ -217,10 +231,10 @@ public class CardbaseCLI {
savePrompt = false;
} catch (JsonGenerationException | JsonMappingException e) {
System.out.println("Error: something terrible happened to the internal cardbase data structure. Oops.");
- e.printStackTrace();
+ if (debug) e.printStackTrace();
} catch (IOException e) {
System.out.println("Error: lost contact with the output file, try again?");
- e.printStackTrace();
+ if (debug) e.printStackTrace();
}
}
} else {
@@ -244,8 +258,8 @@ public class CardbaseCLI {
* Print a list of valid set codes.
*/
public void sets() {
- for (CardSet set : cardbaseManager.getCardSetList()) {
- // CardSet has an overridden toString().
+ for (CardSet set : MTGUniverse.getCardSetList()) {
+ // CardSet has an overridden toString()
System.out.println(set);
}
}
@@ -258,7 +272,7 @@ public class CardbaseCLI {
public void set(String[] args) {
if (args.length > 0) {
try {
- selectedSet = cardbaseManager.getFullCardSet(args[0]);
+ selectedSet = MTGUniverse.getFullCardSet(args[0]);
// if the set code is invalid, null is returned
if (selectedSet != null) {
System.out.println("Selected set: " + selectedSet.getName() + ".");
@@ -269,16 +283,13 @@ public class CardbaseCLI {
}
} catch (JsonParseException e) {
System.out.println("Error: JSON fetched from upstream was not formatted properly.");
- e.printStackTrace();
- return;
+ if (debug) e.printStackTrace();
} catch (JsonMappingException e) {
System.out.println("Error: JSON fetched from upstream does not match the data structure used internally.");
- e.printStackTrace();
- return;
+ if (debug) e.printStackTrace();
} catch (IOException e) {
System.out.println("Error: JSON could not be fetched from upstream.");
- e.printStackTrace();
- return;
+ if (debug) e.printStackTrace();
}
} else {
System.out.println("Please enter a set code (use \"sets\" to see all valid set codes).");
@@ -442,7 +453,7 @@ public class CardbaseCLI {
} else {
System.out.println(card.name + " is not in the cardbase.");
}
-
+
}
/**
diff --git a/src/eu/equalparts/cardbase/utils/IO.java b/src/eu/equalparts/cardbase/utils/IO.java
new file mode 100644
index 0000000..5d4bef5
--- /dev/null
+++ b/src/eu/equalparts/cardbase/utils/IO.java
@@ -0,0 +1,35 @@
+package eu.equalparts.cardbase.utils;
+
+import com.fasterxml.jackson.databind.DeserializationFeature;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+/**
+ * This class simply holds an {@code ObjectMapper} to be used whenever JSON must be parsed.
+ * In the future it may be removed in favour of individual mappers for each function.
+ *
+ * @author Eduardo Pedroni
+ */
+public final class IO {
+
+ /**
+ * The Jackson {@code ObjectMapper} which parses fetched JSON files.
+ */
+ public static final ObjectMapper jsonMapper = createMapper();
+
+ /**
+ * Private constructor, this class is not to be instantiated.
+ */
+ private IO() {}
+
+ /**
+ * Instantiate and configure Jackson mapper statically.
+ *
+ * @return the {@code ObjectMapper}, ready to use.
+ */
+ private static ObjectMapper createMapper() {
+ ObjectMapper objectMapper = new ObjectMapper();
+ // TODO decide what to do about this
+ objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
+ return objectMapper;
+ }
+}
diff --git a/src/eu/equalparts/cardbase/utils/MTGUniverse.java b/src/eu/equalparts/cardbase/utils/MTGUniverse.java
new file mode 100644
index 0000000..7211f47
--- /dev/null
+++ b/src/eu/equalparts/cardbase/utils/MTGUniverse.java
@@ -0,0 +1,152 @@
+package eu.equalparts.cardbase.utils;
+
+import java.io.IOException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.HashMap;
+
+import com.fasterxml.jackson.core.JsonParseException;
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.JsonMappingException;
+
+import eu.equalparts.cardbase.data.Card;
+import eu.equalparts.cardbase.data.CardSet;
+import eu.equalparts.cardbase.data.FullCardSet;
+
+/**
+ * Access point to the complete set of cards that exist in the
+ * MTG universe. This class has a series of utility functions that
+ * query remote databases to acquire card information.
+ * <br>
+ * Conversely, {@code CardbaseManager}'s methods are used solely to
+ * acquire information regarding the loaded cardbase, which will
+ * most likely contain only a subset of the MTG universe.
+ *
+ * @author Eduardo Pedroni
+ */
+public final class MTGUniverse {
+
+ /**
+ * The base URL from where the information is fetched.
+ */
+ private static final String BASE_URL = "http://mtgjson.com/json/";
+ /**
+ * If the upstream set code list can't be loaded, this is loaded instead.
+ */
+ private static final String FALLBACK_LIST_PATH = "/setlist.json";
+ /**
+ * A cache of CardSets to avoid querying the server many times for the same information.
+ */
+ private static ArrayList<CardSet> cardSets;
+
+ /**
+ * A cache of {@code FullCardSets} to avoid querying the server many times for the same information.
+ */
+ private static HashMap<String, FullCardSet> cardSetCache = new HashMap<String, FullCardSet>();
+
+ /**
+ * Private constructor, this class is not to be instantiated.
+ */
+ private MTGUniverse() {}
+
+ /**
+ * Returns the specified card in the form of a {@code Card} object. If the specified number does
+ * not correspond to a card in the set or the specified set code does not correspond to a set,
+ * this returns null.
+ *
+ * @param setCode the set to which the requested card belongs.
+ * @param number the requested card's set number.
+ * @return the requested {@code Card} or null if no card is found.
+ *
+ * @throws JsonParseException if the upstream JSON is not formatted correctly.
+ * @throws JsonMappingException if the upstream JSON does not map to a local class.
+ * @throws IOException if a low-level I/O problem (unexpected end-of-input, network error) occurs.
+ */
+ public static Card getCard(String setCode, String number) throws JsonParseException, JsonMappingException, IOException {
+ Card card = null;
+ FullCardSet fullCardSet = getFullCardSet(setCode);
+
+ if (fullCardSet != null) {
+ card = fullCardSet.getCardByNumber(number);
+ }
+
+ return card;
+ }
+
+ /**
+ * Returns the specified set in the form of a {@code FullCardSet} object. If the specified
+ * set code does not correspond to a set, this returns null.
+ *
+ * @param setCode the code of the set to be returned.
+ * @return the requested {@code FullCardSet} or null if no set matches the given code.
+ *
+ * @throws JsonParseException if the upstream JSON is not formatted correctly.
+ * @throws JsonMappingException if the upstream JSON does not map to {@code FullCardSet}.
+ * @throws IOException if a low-level I/O problem (unexpected end-of-input, network error) occurs.
+ */
+ public static FullCardSet getFullCardSet(String setCode) throws JsonParseException, JsonMappingException, IOException {
+ FullCardSet requestedSet = null;
+ String validCode = validateSetCode(setCode);
+ if (validCode != null) {
+ // if the set is cached, no need to fetch
+ if (cardSetCache.containsKey(validCode)) {
+ requestedSet = cardSetCache.get(validCode);
+ }
+ // not cached; fetch, cache and return it
+ else {
+ requestedSet = IO.jsonMapper.readValue(new URL(BASE_URL + validCode + ".json"), FullCardSet.class);
+ // MTG JSON does not include set code in the card information, but it is useful for sorting
+ for (Card card : requestedSet.getCards()) {
+ card.setCode = validCode;
+ }
+ cardSetCache.put(validCode, requestedSet);
+ }
+ }
+ return requestedSet;
+ }
+
+ /**
+ * @return a list of all card sets in the form of {@code CardSet} objects.
+ */
+ public static ArrayList<CardSet> getCardSetList() {
+ // if the list isn't cached, fetch and cache it
+ if (cardSets == null) {
+ try {
+ cardSets = IO.jsonMapper.readValue(new URL(BASE_URL + "SetList.json"), new TypeReference<ArrayList<CardSet>>() {});
+ } catch (Exception e) {
+ System.out.println("Error: could not fetch/parse set code list from upstream, loading fallback json...");
+ e.printStackTrace();
+
+ try {
+ cardSets = IO.jsonMapper.readValue(MTGUniverse.class.getResourceAsStream(FALLBACK_LIST_PATH), new TypeReference<ArrayList<CardSet>>() {});
+ } catch (Exception f) {
+ System.out.println("Error: could not parse fallback set code list, aborting...");
+ f.printStackTrace();
+ System.exit(1);
+ }
+ }
+ }
+ return cardSets;
+ }
+
+ /**
+ * This method effectively converts different set code spellings
+ * into the format parsed from the set code list.
+ * <br>
+ * For instance, if "m15" is passed as the argument, this returns
+ * "M15", which is the set code as it is stated in the formal list.
+ * If the specified set code does not approximate any entry from
+ * the list, this returns null.
+ *
+ * @param setCode the set code to be validated.
+ * @return the valid form of the set code if any, null otherwise.
+ */
+ public static String validateSetCode(String setCode) {
+ for (CardSet cardSet : getCardSetList()) {
+ if (cardSet.getCode().equalsIgnoreCase(setCode)) {
+ return cardSet.getCode();
+ }
+ }
+ return null;
+ }
+}