Refactored DeckImporter and obsoleted DeckImporterUtil. Added/refactored a PlainTestDeckImporter as a base class for text formatted importers to extend.

This commit is contained in:
John Hitchings 2019-01-10 08:27:05 -08:00
parent 48e9585970
commit 58e629dca6
21 changed files with 389 additions and 160 deletions

View file

@ -14,7 +14,6 @@ import mage.cards.Sets;
import mage.cards.decks.Deck;
import mage.cards.decks.DeckCardLists;
import mage.cards.decks.importer.DeckImporter;
import mage.cards.decks.importer.DeckImporterUtil;
import mage.cards.repository.CardInfo;
import mage.cards.repository.CardRepository;
import mage.client.MageFrame;
@ -798,7 +797,7 @@ public class DeckEditorPanel extends javax.swing.JPanel {
MageFrame.getDesktop().setCursor(new Cursor(Cursor.WAIT_CURSOR));
try {
newDeck = Deck.load(DeckImporterUtil.importDeck(dialog.getTmpPath(), errorMessages), true, true);
newDeck = Deck.load(DeckImporter.importDeckFromFile(dialog.getTmpPath(), errorMessages), true, true);
processAndShowImportErrors(errorMessages);
if (newDeck != null) {
@ -831,7 +830,7 @@ public class DeckEditorPanel extends javax.swing.JPanel {
MageFrame.getDesktop().setCursor(new Cursor(Cursor.WAIT_CURSOR));
try {
deckToAppend = Deck.load(DeckImporterUtil.importDeck(dialog.getTmpPath(), errorMessages), true, true);
deckToAppend = Deck.load(DeckImporter.importDeckFromFile(dialog.getTmpPath(), errorMessages), true, true);
processAndShowImportErrors(errorMessages);
if (deckToAppend != null) {
@ -878,7 +877,7 @@ public class DeckEditorPanel extends javax.swing.JPanel {
Deck newDeck = null;
StringBuilder errorMessages = new StringBuilder();
newDeck = Deck.load(DeckImporterUtil.importDeck(file.getPath(), errorMessages), true, true);
newDeck = Deck.load(DeckImporter.importDeckFromFile(file.getPath(), errorMessages), true, true);
processAndShowImportErrors(errorMessages);
if (newDeck != null) {
@ -977,7 +976,7 @@ public class DeckEditorPanel extends javax.swing.JPanel {
File file = fcImportDeck.getSelectedFile();
MageFrame.getDesktop().setCursor(new Cursor(Cursor.WAIT_CURSOR));
try {
DeckImporter importer = DeckImporterUtil.getDeckImporter(file.getPath());
DeckImporter importer = DeckImporter.getDeckImporter(file.getPath());
if (importer != null) {
StringBuilder errorMessages = new StringBuilder();
@ -1048,7 +1047,7 @@ public class DeckEditorPanel extends javax.swing.JPanel {
try {
MageFrame.getDesktop().setCursor(new Cursor(Cursor.WAIT_CURSOR));
String path = DeckGenerator.generateDeck();
deck = Deck.load(DeckImporterUtil.importDeck(path), true, true);
deck = Deck.load(DeckImporter.importDeckFromFile(path), true, true);
} catch (GameException ex) {
JOptionPane.showMessageDialog(MageFrame.getDesktop(), ex.getMessage(), "Error loading generated deck", JOptionPane.ERROR_MESSAGE);
} catch (DeckGeneratorException ex) {
@ -1120,7 +1119,11 @@ class ImportFilter extends FileFilter {
ext = s.substring(i + 1).toLowerCase(Locale.ENGLISH);
}
if (ext != null) {
if (ext.toLowerCase(Locale.ENGLISH).equals("dec") || ext.toLowerCase(Locale.ENGLISH).equals("mwdeck") || ext.toLowerCase(Locale.ENGLISH).equals("txt") || ext.toLowerCase(Locale.ENGLISH).equals("dek")) {
if (ext.toLowerCase(Locale.ENGLISH).equals("dec")
|| ext.toLowerCase(Locale.ENGLISH).equals("mwdeck")
|| ext.toLowerCase(Locale.ENGLISH).equals("txt")
|| ext.toLowerCase(Locale.ENGLISH).equals("dek")
|| ext.toLowerCase(Locale.ENGLISH).equals("cod")) {
return true;
}
}
@ -1129,7 +1132,7 @@ class ImportFilter extends FileFilter {
@Override
public String getDescription() {
return "*.dec | *.mwDeck | *.txt | *.dek";
return "*.dec | *.mwDeck | *.txt | *.dek | *.cod";
}
}

View file

@ -1,7 +1,7 @@
package mage.client.dialog;
import mage.cards.decks.importer.DeckImporterUtil;
import mage.cards.decks.importer.DeckImporter;
import mage.client.MageFrame;
import mage.client.SessionHandler;
import mage.players.PlayerType;
@ -119,9 +119,9 @@ public class JoinTableDialog extends MageDialog {
try {
PreferencesDialog.saveValue(PreferencesDialog.KEY_NEW_TABLE_PASSWORD_JOIN, txtPassword.getText());
if (isTournament) {
joined = session.joinTournamentTable(roomId, tableId, this.newPlayerPanel.getPlayerName(), PlayerType.HUMAN, 1, DeckImporterUtil.importDeck(this.newPlayerPanel.getDeckFile()), this.txtPassword.getText());
joined = session.joinTournamentTable(roomId, tableId, this.newPlayerPanel.getPlayerName(), PlayerType.HUMAN, 1, DeckImporter.importDeckFromFile(this.newPlayerPanel.getDeckFile()), this.txtPassword.getText());
} else {
joined = session.joinTable(roomId, tableId, this.newPlayerPanel.getPlayerName(), PlayerType.HUMAN, 1, DeckImporterUtil.importDeck(this.newPlayerPanel.getDeckFile()), this.txtPassword.getText());
joined = session.joinTable(roomId, tableId, this.newPlayerPanel.getPlayerName(), PlayerType.HUMAN, 1, DeckImporter.importDeckFromFile(this.newPlayerPanel.getDeckFile()), this.txtPassword.getText());
}
} catch (Exception ex) {

View file

@ -7,7 +7,8 @@ import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import javax.swing.*;
import mage.cards.decks.importer.DeckImporterUtil;
import mage.cards.decks.importer.DeckImporter;
import mage.client.MageFrame;
import mage.client.SessionHandler;
import mage.client.components.MageComponents;
@ -425,7 +426,7 @@ public class NewTableDialog extends MageDialog {
table.getTableId(),
this.player1Panel.getPlayerName(),
PlayerType.HUMAN, 1,
DeckImporterUtil.importDeck(this.player1Panel.getDeckFile()),
DeckImporter.importDeckFromFile(this.player1Panel.getDeckFile()),
this.txtPassword.getText())) {
for (TablePlayerPanel player : players) {
if (player.getPlayerType() != PlayerType.HUMAN) {

View file

@ -18,7 +18,7 @@ import java.util.UUID;
import javax.swing.*;
import javax.swing.filechooser.FileFilter;
import mage.cards.decks.Deck;
import mage.cards.decks.importer.DeckImporterUtil;
import mage.cards.decks.importer.DeckImporter;
import mage.cards.repository.ExpansionInfo;
import mage.cards.repository.ExpansionRepository;
import mage.client.MageFrame;
@ -557,7 +557,7 @@ public class NewTournamentDialog extends MageDialog {
if (!(cubeFromDeckFilename.isEmpty())) {
Deck cubeFromDeck = new Deck();
try {
cubeFromDeck = Deck.load(DeckImporterUtil.importDeck(cubeFromDeckFilename), true, true);
cubeFromDeck = Deck.load(DeckImporter.importDeckFromFile(cubeFromDeckFilename), true, true);
} catch (GameException e1) {
JOptionPane.showMessageDialog(MageFrame.getDesktop(), e1.getMessage(), "Error loading deck", JOptionPane.ERROR_MESSAGE);
}
@ -631,11 +631,11 @@ public class NewTournamentDialog extends MageDialog {
table.getTableId(),
this.player1Panel.getPlayerName(),
PlayerType.HUMAN, 1,
DeckImporterUtil.importDeck(this.player1Panel.getDeckFile()),
DeckImporter.importDeckFromFile(this.player1Panel.getDeckFile()),
tOptions.getPassword())) {
for (TournamentPlayerPanel player : players) {
if (player.getPlayerType().getSelectedItem() != PlayerType.HUMAN) {
if (!player.joinTournamentTable(roomId, table.getTableId(), DeckImporterUtil.importDeck(this.player1Panel.getDeckFile()))) {
if (!player.joinTournamentTable(roomId, table.getTableId(), DeckImporter.importDeckFromFile(this.player1Panel.getDeckFile()))) {
// error message must be send by sever
SessionHandler.removeTable(roomId, table.getTableId());
table = null;

View file

@ -20,7 +20,8 @@ import javax.swing.JPopupMenu;
import javax.swing.LayoutStyle.ComponentPlacement;
import javax.swing.MenuSelectionManager;
import javax.swing.event.ChangeListener;
import mage.cards.decks.importer.DeckImporterUtil;
import mage.cards.decks.importer.DeckImporter;
import mage.client.MageFrame;
import mage.client.SessionHandler;
import mage.client.cards.BigCard;
@ -569,7 +570,7 @@ public class PlayAreaPanel extends javax.swing.JPanel {
}
private void btnCheatActionPerformed(java.awt.event.ActionEvent evt) {
SessionHandler.cheat(gameId, playerId, DeckImporterUtil.importDeck("cheat.dck"));
SessionHandler.cheat(gameId, playerId, DeckImporter.importDeckFromFile("cheat.dck"));
}
public boolean isSmallMode() {

View file

@ -8,7 +8,7 @@
package mage.client.table;
import mage.cards.decks.importer.DeckImporterUtil;
import mage.cards.decks.importer.DeckImporter;
import mage.client.SessionHandler;
import mage.client.util.Config;
import mage.client.util.Event;
@ -53,7 +53,7 @@ public class TablePlayerPanel extends javax.swing.JPanel {
public boolean joinTable(UUID roomId, UUID tableId) throws IOException, ClassNotFoundException {
if (this.cbPlayerType.getSelectedItem() != PlayerType.HUMAN) {
return SessionHandler.joinTable(roomId, tableId, this.newPlayerPanel.getPlayerName(), (PlayerType) this.cbPlayerType.getSelectedItem(), this.newPlayerPanel.getLevel(), DeckImporterUtil.importDeck(this.newPlayerPanel.getDeckFile()), "");
return SessionHandler.joinTable(roomId, tableId, this.newPlayerPanel.getPlayerName(), (PlayerType) this.cbPlayerType.getSelectedItem(), this.newPlayerPanel.getLevel(), DeckImporter.importDeckFromFile(this.newPlayerPanel.getDeckFile()), "");
}
return true;
}

View file

@ -1,6 +1,6 @@
package mage.client.table;
import mage.cards.decks.importer.DeckImporterUtil;
import mage.cards.decks.importer.DeckImporter;
import mage.client.MageFrame;
import mage.client.SessionHandler;
import mage.client.chat.ChatPanelBasic;
@ -1263,8 +1263,8 @@ public class TablesPanel extends javax.swing.JPanel {
options.setBannedUsers(IgnoreList.ignoreList(serverAddress));
table = SessionHandler.createTable(roomId, options);
SessionHandler.joinTable(roomId, table.getTableId(), "Human", PlayerType.HUMAN, 1, DeckImporterUtil.importDeck("test.dck"), "");
SessionHandler.joinTable(roomId, table.getTableId(), "Computer", PlayerType.COMPUTER_MAD, 5, DeckImporterUtil.importDeck("test.dck"), "");
SessionHandler.joinTable(roomId, table.getTableId(), "Human", PlayerType.HUMAN, 1, DeckImporter.importDeckFromFile("test.dck"), "");
SessionHandler.joinTable(roomId, table.getTableId(), "Computer", PlayerType.COMPUTER_MAD, 5, DeckImporter.importDeckFromFile("test.dck"), "");
SessionHandler.startMatch(roomId, table.getTableId());
} catch (HeadlessException ex) {
handleError(ex);

View file

@ -0,0 +1,44 @@
package mage.cards.decks.importer;
import static org.junit.Assert.assertEquals;
import org.junit.Test;
import mage.cards.decks.DeckCardInfo;
import mage.cards.decks.DeckCardLists;
public class CodDeckImportTest {
@Test
public void testImportCod() {
StringBuilder errors = new StringBuilder();
DeckCardLists deck = new CodDeckImporter().importDeck(
"src/test/java/mage/cards/decks/importer/testdeck.cod", errors);
assertEquals("Deck Name", deck.getName());
assertEquals(113, deck.getCards().size());
assertEquals(3, deck.getSideboard().size());
int index = 0;
for (int i = 0; i < 12; i++) {
assertCardSame("Forest", deck.getCards().get(index++));
}
for (int i = 0; i < 100; i++) {
assertCardSame("Razorverge Thicket", deck.getCards().get(index++));
}
assertCardSame("Avacyn's Pilgrim", deck.getCards().get(index++));
assertEquals(index, deck.getCards().size());
index = 0;
for (int i = 0; i < 3; i++) {
assertCardSame("War Priest of Thune", deck.getSideboard().get(index++));
}
assertEquals(index, deck.getSideboard().size());
assertEquals("Could not find card: '@#$NOT A REAL CARD NAME@#$'\n", errors.toString());
}
private static void assertCardSame(String name, DeckCardInfo card) {
assertEquals(name, card.getCardName());
assertEquals(1, card.getQuantity());
}
}

View file

@ -0,0 +1,20 @@
package mage.cards.decks.importer;
import static org.junit.Assert.assertEquals;
import org.junit.Test;
import mage.cards.decks.DeckCardLists;
public class DecDeckImportTest {
@Test
public void testImport() {
StringBuilder errors = new StringBuilder();
DeckCardLists deck = new DecDeckImporter().importDeck(
"src/test/java/mage/cards/decks/importer/testdeck.dec", errors);
assertEquals(60, deck.getCards().size());
assertEquals(15, deck.getSideboard().size());
}
}

View file

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<cockatrice_deck version="1">
<deckname>Deck Name </deckname>
<comments>Some comments in here.</comments>
<zone name="main">
<card number="12" name="Forest"/>
<card number="101" price="0" name="Razorverge Thicket"/>
<card price="0" name="Avacyn's Pilgrim"/>
<card number="1" price="0" name="@#$NOT A REAL CARD NAME@#$"/>
</zone>
<zone name="side">
<card number="3" price="0" name="War Priest of Thune"/>
</zone>
</cockatrice_deck>

View file

@ -0,0 +1,28 @@
// Name: Mono-Blue Tinker from MTGSalvation.com via mtgtrice mtg-decks
// Creatures
4 Masticore
4 Metalworker
1 Phyrexian Colossus
// Artifacts
1 Crumbling Sanctuary
4 Grim Monolith
1 Mishra's Helix
4 Phyrexian Processor
4 Tangle Wire
4 Thran Dynamo
4 Voltaic Key
// Sorceries
4 Tinker
// Instants
4 Brainstorm
// Lands
4 Crystal Vein
9 Island
4 Rishadan Port
4 Saprazzan Skerry
// Sideboard
SB: 4 Annul
SB: 4 Chill
SB: 4 Miscalculation
SB: 1 Mishra's Helix
SB: 2 Rising Waters

View file

@ -6,7 +6,7 @@ import mage.abilities.Ability;
import mage.cards.Card;
import mage.cards.decks.Deck;
import mage.cards.decks.DeckCardLists;
import mage.cards.decks.importer.DeckImporterUtil;
import mage.cards.decks.importer.DeckImporter;
import mage.cards.repository.CardInfo;
import mage.cards.repository.CardRepository;
import mage.cards.repository.CardScanner;
@ -189,7 +189,7 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
if (loadedDeckCardLists.containsKey(deckName)) {
list = loadedDeckCardLists.get(deckName);
} else {
list = DeckImporterUtil.importDeck(deckName);
list = DeckImporter.importDeckFromFile(deckName);
loadedDeckCardLists.put(deckName, list);
}
Deck deck = Deck.load(list, false, false);

View file

@ -0,0 +1,116 @@
package mage.cards.decks.importer;
import static javax.xml.xpath.XPathConstants.NODESET;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import mage.cards.decks.DeckCardInfo;
import mage.cards.decks.DeckCardLists;
import mage.cards.repository.CardInfo;
import mage.cards.repository.CardRepository;
public class CodDeckImporter extends DeckImporter {
private XPathFactory xpathFactory = XPathFactory.newInstance();
private DocumentBuilder builder = getDocumentBuilder();
@Override
public DeckCardLists importDeck(String filename, StringBuilder errorMessages) {
try {
Document doc = getXmlDocument(filename);
DeckCardLists decklist = new DeckCardLists();
List<Node> mainCards = getNodes(doc, "/cockatrice_deck/zone[@name='main']/card");
decklist.setCards(mainCards.stream()
.flatMap(toDeckCardInfo(errorMessages))
.collect(Collectors.toList()));
List<Node> sideboardCards = getNodes(doc, "/cockatrice_deck/zone[@name='side']/card");
decklist.setSideboard(sideboardCards.stream()
.flatMap(toDeckCardInfo(errorMessages))
.collect(Collectors.toList()));
getNodes(doc, "/cockatrice_deck/deckname")
.forEach(n -> decklist.setName(n.getTextContent().trim()));
return decklist;
} catch (Exception e) {
logger.error("Error loading deck", e);
errorMessages.append("There was an error loading the deck.");
return new DeckCardLists();
}
}
private static int getQuantityFromNode(Node node) {
Node numberNode = node.getAttributes().getNamedItem("number");
if (numberNode == null) {
return 1;
}
try {
return Math.min(100, Math.max(0, Integer.parseInt(numberNode.getNodeValue())));
} catch (NumberFormatException e) {
return 1;
}
}
private static Function<Node, Stream<DeckCardInfo>> toDeckCardInfo(StringBuilder errors) {
return node -> {
String name = node.getAttributes().getNamedItem("name").getNodeValue().trim();
CardInfo cardInfo = CardRepository.instance.findPreferedCoreExpansionCard(name, true);
if (cardInfo != null) {
return Collections.nCopies(
getQuantityFromNode(node),
new DeckCardInfo(cardInfo.getName(), cardInfo.getCardNumber(), cardInfo.getSetCode()))
.stream();
} else {
errors.append("Could not find card: '").append(name).append("'\n");
}
return Stream.empty();
};
}
private List<Node> getNodes(Document doc, String xpathExpression) throws XPathExpressionException {
NodeList nodes = (NodeList) xpathFactory.newXPath().evaluate(xpathExpression, doc, NODESET);
ArrayList<Node> list = new ArrayList<>();
for (int i = 0; i < nodes.getLength(); i++) {
list.add(nodes.item(i));
}
return list;
}
private DocumentBuilder getDocumentBuilder() {
try {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
return factory.newDocumentBuilder();
} catch (ParserConfigurationException e) {
throw new RuntimeException();
}
}
protected Document getXmlDocument(String filename) throws IOException {
try {
return builder.parse(new File(filename));
} catch (SAXException e) {
throw new IOException(e);
}
}
}

View file

@ -15,7 +15,7 @@ import mage.cards.repository.CardRepository;
*
* @author North
*/
public class DckDeckImporter extends DeckImporter {
public class DckDeckImporter extends PlainTextDeckImporter {
private static final Pattern pattern = Pattern.compile("(SB:)?\\s*(\\d*)\\s*\\[([^]:]+):([^]:]+)\\]\\s*(.*)\\s*$");

View file

@ -10,7 +10,7 @@ import mage.cards.repository.CardRepository;
*
* @author BetaSteward_at_googlemail.com
*/
public class DecDeckImporter extends DeckImporter {
public class DecDeckImporter extends PlainTextDeckImporter {
@Override
protected void readLine(String line, DeckCardLists deckList) {

View file

@ -1,74 +1,80 @@
package mage.cards.decks.importer;
import mage.cards.decks.DeckCardLists;
import org.apache.log4j.Logger;
import java.io.File;
import java.util.Locale;
import java.util.Scanner;
/**
*
* @author BetaSteward_at_googlemail.com
*/
import mage.cards.decks.DeckCardLists;
public abstract class DeckImporter {
private static final Logger logger = Logger.getLogger(DeckImporter.class);
protected static final Logger logger = Logger.getLogger(DeckImporter.class);
protected StringBuilder sbMessage = new StringBuilder(); //TODO we should stop using this not garbage collectable StringBuilder. It just bloats
protected int lineCount;
private static final String[] SIDEBOARD_MARKS = new String[]{"//sideboard", "sb: "};
public static DeckImporter getDeckImporter(String file) {
if (file == null) {
return null;
} if (file.toLowerCase(Locale.ENGLISH).endsWith("dec")) {
return new DecDeckImporter();
} else if (file.toLowerCase(Locale.ENGLISH).endsWith("mwdeck")) {
return new MWSDeckImporter();
} else if (file.toLowerCase(Locale.ENGLISH).endsWith("txt")) {
return new TxtDeckImporter(haveSideboardSection(file));
} else if (file.toLowerCase(Locale.ENGLISH).endsWith("dck")) {
return new DckDeckImporter();
} else if (file.toLowerCase(Locale.ENGLISH).endsWith("dek")) {
return new DekDeckImporter();
} else if (file.toLowerCase(Locale.ENGLISH).endsWith("cod")) {
return new CodDeckImporter();
} else {
return null;
}
}
/**
*
* @param file file to import
* @param errorMessages you can setup output messages to showup to user (set null for fatal exception on messages.count > 0)
* @return decks list
*/
public DeckCardLists importDeck(String file, StringBuilder errorMessages) {
File f = new File(file);
DeckCardLists deckList = new DeckCardLists();
if (!f.exists()) {
logger.warn("Deckfile " + file + " not found.");
return deckList;
public static DeckCardLists importDeckFromFile(String file) {
return importDeckFromFile(file, new StringBuilder());
}
public static DeckCardLists importDeckFromFile(String file, StringBuilder errorMessages) {
DeckImporter deckImporter = getDeckImporter(file);
if (deckImporter != null) {
return deckImporter.importDeck(file, errorMessages);
} else {
return new DeckCardLists();
}
}
public abstract DeckCardLists importDeck(String file, StringBuilder errorMessages);
public DeckCardLists importDeck(String file) {
return importDeck(file, new StringBuilder());
}
private static boolean haveSideboardSection(String file) {
// search for sideboard section:
// or //sideboard
// or SB: 1 card name -- special deckstats.net
File f = new File(file);
try (Scanner scanner = new Scanner(f)) {
while (scanner.hasNextLine()) {
String line = scanner.nextLine().trim().toLowerCase(Locale.ENGLISH);
for (String mark : SIDEBOARD_MARKS) {
if (line.startsWith(mark)) {
return true;
}
}
lineCount = 0;
sbMessage.setLength(0);
try {
try (Scanner scanner = new Scanner(f)) {
while (scanner.hasNextLine()) {
String line = scanner.nextLine().trim();
lineCount++;
readLine(line, deckList);
}
if (sbMessage.length() > 0) {
if(errorMessages != null) {
// normal output for user
errorMessages.append(sbMessage);
}else{
// fatal error
logger.fatal(sbMessage);
}
}
} catch (Exception ex) {
logger.fatal(null, ex);
}
} catch (Exception ex) {
logger.fatal(null, ex);
}
return deckList;
}
} catch (Exception e) {
// ignore error, deckimporter will process it
}
public DeckCardLists importDeck(String file) {
return importDeck(file, null);
}
// not found
return false;
}
public String getErrors(){
return sbMessage.toString();
}
protected abstract void readLine(String line, DeckCardLists deckList);
}

View file

@ -1,71 +0,0 @@
package mage.cards.decks.importer;
import java.io.File;
import java.util.Locale;
import java.util.Scanner;
import mage.cards.decks.DeckCardLists;
/**
*
* @author North
*/
public final class DeckImporterUtil {
private static final String[] SIDEBOARD_MARKS = new String[]{"//sideboard", "sb: "};
public static boolean haveSideboardSection(String file) {
// search for sideboard section:
// or //sideboard
// or SB: 1 card name -- special deckstats.net
File f = new File(file);
try (Scanner scanner = new Scanner(f)) {
while (scanner.hasNextLine()) {
String line = scanner.nextLine().trim().toLowerCase(Locale.ENGLISH);
for (String mark : SIDEBOARD_MARKS) {
if (line.startsWith(mark)) {
return true;
}
}
}
} catch (Exception e) {
// ignore error, deckimporter will process it
}
// not found
return false;
}
public static DeckImporter getDeckImporter(String file) {
if (file == null) {
return null;
} if (file.toLowerCase(Locale.ENGLISH).endsWith("dec")) {
return new DecDeckImporter();
} else if (file.toLowerCase(Locale.ENGLISH).endsWith("mwdeck")) {
return new MWSDeckImporter();
} else if (file.toLowerCase(Locale.ENGLISH).endsWith("txt")) {
return new TxtDeckImporter(haveSideboardSection(file));
} else if (file.toLowerCase(Locale.ENGLISH).endsWith("dck")) {
return new DckDeckImporter();
} else if (file.toLowerCase(Locale.ENGLISH).endsWith("dek")) {
return new DekDeckImporter();
} else {
return null;
}
}
public static DeckCardLists importDeck(String file, StringBuilder errorMessages) {
DeckImporter deckImporter = getDeckImporter(file);
if (deckImporter != null) {
return deckImporter.importDeck(file, errorMessages);
} else {
return new DeckCardLists();
}
}
public static DeckCardLists importDeck(String file) {
return importDeck(file, null);
}
}

View file

@ -8,7 +8,7 @@ import mage.cards.repository.CardRepository;
/**
* Created by royk on 11-Sep-16.
*/
public class DekDeckImporter extends DeckImporter {
public class DekDeckImporter extends PlainTextDeckImporter {
@Override
protected void readLine(String line, DeckCardLists deckList) {

View file

@ -14,7 +14,7 @@ import mage.util.RandomUtil;
*
* @author BetaSteward_at_googlemail.com
*/
public class MWSDeckImporter extends DeckImporter {
public class MWSDeckImporter extends PlainTextDeckImporter {
@Override
protected void readLine(String line, DeckCardLists deckList) {

View file

@ -0,0 +1,67 @@
package mage.cards.decks.importer;
import java.io.File;
import java.util.Scanner;
import mage.cards.decks.DeckCardLists;
/**
*
* @author BetaSteward_at_googlemail.com
*/
public abstract class PlainTextDeckImporter extends DeckImporter {
protected StringBuilder sbMessage = new StringBuilder(); //TODO we should stop using this not garbage collectable StringBuilder. It just bloats
protected int lineCount;
/**
*
* @param file file to import
* @param errorMessages you can setup output messages to showup to user (set null for fatal exception on messages.count > 0)
* @return decks list
*/
public DeckCardLists importDeck(String file, StringBuilder errorMessages) {
File f = new File(file);
DeckCardLists deckList = new DeckCardLists();
if (!f.exists()) {
logger.warn("Deckfile " + file + " not found.");
return deckList;
}
lineCount = 0;
sbMessage.setLength(0);
try {
try (Scanner scanner = new Scanner(f)) {
while (scanner.hasNextLine()) {
String line = scanner.nextLine().trim();
lineCount++;
readLine(line, deckList);
}
if (sbMessage.length() > 0) {
if(errorMessages != null) {
// normal output for user
errorMessages.append(sbMessage);
}else{
// fatal error
logger.fatal(sbMessage);
}
}
} catch (Exception ex) {
logger.fatal(null, ex);
}
} catch (Exception ex) {
logger.fatal(null, ex);
}
return deckList;
}
public DeckCardLists importDeck(String file) {
return importDeck(file, null);
}
protected abstract void readLine(String line, DeckCardLists deckList);
}

View file

@ -14,7 +14,7 @@ import mage.cards.repository.CardRepository;
*
* @author BetaSteward_at_googlemail.com
*/
public class TxtDeckImporter extends DeckImporter {
public class TxtDeckImporter extends PlainTextDeckImporter {
private static final String[] SET_VALUES = new String[]{"lands", "creatures", "planeswalkers", "other spells", "sideboard cards",
"Instant", "Land", "Enchantment", "Artifact", "Sorcery", "Planeswalker", "Creature"};