diff --git a/src/main/java/forge/deck/DeckRecognizer.java b/src/main/java/forge/deck/DeckRecognizer.java
index fe29e30de42..4fc8ebefa58 100644
--- a/src/main/java/forge/deck/DeckRecognizer.java
+++ b/src/main/java/forge/deck/DeckRecognizer.java
@@ -1,7 +1,10 @@
package forge.deck;
-import java.util.Map.Entry;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import org.apache.commons.lang3.StringUtils;
+import forge.item.CardDb;
import forge.item.CardPrinted;
/**
@@ -58,9 +61,63 @@ public class DeckRecognizer {
public int getNumber() { return number; }
}
- public static Token recognizeLine(String line)
+// Let's think about it numbers in the back later
+// private static final Pattern searchNumbersInBack = Pattern.compile("(.*)[^A-Za-wyz]*\\s+([\\d]{1,2})");
+ private static final Pattern searchNumbersInFront = Pattern.compile("([\\d]{1,2})[^A-Za-wyz]*\\s+(.*)");
+ public static Token recognizeLine(String raw_line)
{
- return new Token(TokenType.Unknown, 0, line);
+ if (StringUtils.isBlank(raw_line)) { return new Token(TokenType.Comment, 0, raw_line); }
+ String line = raw_line.trim();
+
+ Token result = null;
+ Matcher foundNumbersInFront = searchNumbersInFront.matcher(line);
+ // Matcher foundNumbersInBack = searchNumbersInBack.matcher(line);
+ if (foundNumbersInFront.matches()) {
+ String cardName = foundNumbersInFront.group(2);
+ int amount = Integer.parseInt(foundNumbersInFront.group(1));
+ result = recognizePossibleNameAndNumber(cardName, amount);
+ } /* else if (foundNumbersInBack.matches()) {
+ String cardName = foundNumbersInBack.group(1);
+ int amount = Integer.parseInt(foundNumbersInBack.group(2));
+ return new Token(cardName, amount);
+ } */else {
+ if ( CardDb.instance().isCardSupported(line)) {
+ return new Token( CardDb.instance().getCard(line), 1);
+ }
+ result = recognizeNonCard(line, 1);
+ }
+ return result != null ? result : new Token(TokenType.Unknown, 0, line);
+ }
+
+ private static Token recognizePossibleNameAndNumber(String name, int n) {
+ if ( CardDb.instance().isCardSupported(name))
+ return new Token( CardDb.instance().getCard(name), n);
+
+ Token known = recognizeNonCard(name, n);
+ return null == known ? new Token(name, n) : known;
+ }
+
+ private static Token recognizeNonCard(String text, int n) {
+ if (isDecoration(text)) { return new Token(TokenType.Comment, n, text); }
+ if (isSectionName(text)) { return new Token(TokenType.SectionName, n, text); }
+ return null;
+ }
+
+ private final static String[] knownComments = new String[] {
+ "lands", "creatures", "creature", "spells", "enchancements", "other spells", "artifacts", "cards" };
+ private static boolean isDecoration(String line) {
+ for (String s : knownComments) {
+ if (line.equalsIgnoreCase(s)) { return true; }
+ }
+ return false;
}
+ private static boolean isSectionName(String line) {
+ if (line.equalsIgnoreCase("sideboard")) { return true; }
+ if (line.equalsIgnoreCase("MAIN BOARD")) { return true; }
+ if (line.equalsIgnoreCase("MAIN")) { return true; }
+ return false;
+ }
+
+
}
diff --git a/src/main/java/forge/gui/deckeditor/DeckImport.java b/src/main/java/forge/gui/deckeditor/DeckImport.java
index 8cdc30e5aae..ef6b11cf3ea 100644
--- a/src/main/java/forge/gui/deckeditor/DeckImport.java
+++ b/src/main/java/forge/gui/deckeditor/DeckImport.java
@@ -3,7 +3,6 @@ package forge.gui.deckeditor;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
-import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.ArrayList;
import java.util.List;
@@ -12,7 +11,7 @@ import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JEditorPane;
-import javax.swing.JFrame;
+import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
@@ -28,6 +27,7 @@ import net.miginfocom.swing.MigLayout;
import forge.Singletons;
import forge.deck.Deck;
import forge.deck.DeckRecognizer;
+import forge.deck.DeckRecognizer.TokenType;
import forge.gui.GuiUtils;
/**
@@ -38,9 +38,30 @@ public class DeckImport extends JDialog {
private static final long serialVersionUID = -5837776824284093004L;
private JTextArea txtInput = new JTextArea();
- private JEditorPane htmlOutput = new JEditorPane("text/html", "
Expect result here
");
+ private static final String stylesheet = "";
+ private static final String htmlWelcomeText = ""+stylesheet+"You'll see recognized cards here
" +
+ "Legend
" +
+ "" +
+ "- Recognized cards will be shown in green. These cards will be auto-imported into a new deck
" +
+ "- Lines which seem to see cards but could not be recognized, are shown in red
" +
+ "" +
+ "
" +
+ "" +
+ "" +
+ "";
+
+ private JEditorPane htmlOutput = new JEditorPane("text/html", htmlWelcomeText);
private JScrollPane scrollInput = new JScrollPane(txtInput);
private JScrollPane scrollOutput = new JScrollPane(htmlOutput);
+ private JLabel summaryMain = new JLabel("Imported deck summary will appear here");
+ private JLabel summarySide = new JLabel("This is second line");
private JButton cmdAccept = new JButton("Import Deck");
private JButton cmdCancel = new JButton("Cancel");
@@ -78,10 +99,14 @@ public class DeckImport extends JDialog {
scrollOutput.setViewportBorder(BorderFactory.createLoweredBevelBorder());
getContentPane().setLayout(new MigLayout("fill"));
- getContentPane().add(scrollInput, "cell 0 0, w 50%, growy, pushy");
+ getContentPane().add(scrollInput, "cell 0 0, w 50%, sy 4, growy, pushy");
getContentPane().add(scrollOutput, "cell 1 0, w 50%, growy, pushy");
- getContentPane().add(cmdAccept, "cell 0 1, w 100, align r");
- getContentPane().add(cmdCancel, "cell 1 1, w 100, align l");
+
+ getContentPane().add(summaryMain, "cell 1 1, label");
+ getContentPane().add(summarySide, "cell 1 2, label");
+
+ getContentPane().add(cmdAccept, "cell 1 3, split 2, w 100, align c");
+ getContentPane().add(cmdCancel, "w 100");
cmdCancel.addActionListener(new ActionListener() {
@Override public void actionPerformed(ActionEvent e) {
@@ -113,18 +138,9 @@ public class DeckImport extends JDialog {
}
}
- private static String stylesheet = "";
+
- private void displayTokens()
- {
+ private void displayTokens() {
StringBuilder sbOut = new StringBuilder("");
sbOut.append(stylesheet);
for (DeckRecognizer.Token t : tokens) {
@@ -134,13 +150,25 @@ public class DeckImport extends JDialog {
htmlOutput.setText(sbOut.toString());
}
- private Deck buildDeck()
- {
+ private void updateSummaries() {
+ int[] cardsOk = new int[2];
+ int[] cardsUnknown = new int[2];
+ int idx = 0;
+ for (DeckRecognizer.Token t : tokens) {
+ if (t.getType() == TokenType.KnownCardWithNumber) { cardsOk[idx] += t.getNumber(); }
+ if (t.getType() == TokenType.UnknownCardWithNumber) { cardsUnknown[idx] += t.getNumber(); }
+ if (t.getType() == TokenType.SectionName && t.getText().toLowerCase().contains("side") ) { idx = 1; }
+ }
+ summaryMain.setText(String.format("Main: %d cards recognized, %d unknown cards", cardsOk[0], cardsUnknown[0]));
+ summarySide.setText(String.format("Sideboard: %d cards recognized, %d unknown cards", cardsOk[1], cardsUnknown[1]));
+ }
+
+ private Deck buildDeck(){
return new Deck();
}
protected class OnChangeTextUpdate implements DocumentListener {
- private void onChange() { readInput(); displayTokens(); }
+ private void onChange() { readInput(); displayTokens(); updateSummaries(); }
@Override public void insertUpdate(DocumentEvent e) { onChange(); }
@Override public void removeUpdate(DocumentEvent e) { onChange(); }
@Override public void changedUpdate(DocumentEvent e) { } // Happend only on ENTER pressed
@@ -149,11 +177,17 @@ public class DeckImport extends JDialog {
private String makeHtmlViewOfToken(DeckRecognizer.Token token) {
switch(token.getType())
{
+ case KnownCardWithNumber:
+ return String.format("%s * %s [%s]
", token.getNumber(), token.getCard().getName(), token.getCard().getSet());
+ case UnknownCardWithNumber:
+ return String.format("%s * %s
", token.getNumber(), token.getText());
+ case SectionName:
+ return String.format("%s
", token.getText());
case Unknown:
- return String.format("%s
", token.getText());
- default:
- return String.format("%s
", token.getType(), token.getText());
+ case Comment:
+ return String.format("", token.getText());
}
+ return "";
}
}
diff --git a/src/main/java/forge/item/CardDb.java b/src/main/java/forge/item/CardDb.java
index 33f3fed6fd4..488d2e440de 100644
--- a/src/main/java/forge/item/CardDb.java
+++ b/src/main/java/forge/item/CardDb.java
@@ -11,7 +11,7 @@ import java.util.Map.Entry;
import net.slightlymagic.braids.util.lambda.Lambda1;
import org.apache.commons.lang3.StringUtils;
-
+import org.apache.commons.lang3.tuple.ImmutablePair;
import forge.Card;
import forge.card.CardInSet;
import forge.card.CardRules;
@@ -102,24 +102,42 @@ public final class CardDb {
uniqueCards.put(cardName, lastAdded);
}
- public boolean isCardSupported(final String cardName) { return uniqueCards.containsKey(cardName.toLowerCase()); }
-
+ public boolean isCardSupported(final String cardName) {
+ ImmutablePair nameWithSet = splitCardName(cardName);
+ if ( nameWithSet.right == null ) { return uniqueCards.containsKey(nameWithSet.left.toLowerCase()); }
+ // Set exists?
+ Map cardsFromset = allCardsBySet.get(nameWithSet.right.toUpperCase());
+ if (cardsFromset == null) return false;
+ // Card exists?
+ CardPrinted[] cardCopies = cardsFromset.get(nameWithSet.left.toLowerCase());
+ return cardCopies != null && cardCopies.length > 0;
+ }
+ /**
+ * Splits cardname into Name and set whenever deck line reads as name|set
+ */
+ private static ImmutablePair splitCardName(final String name) {
+ String cardName = name; // .trim() ?
+ int pipePos = cardName.indexOf('|');
+
+ if (pipePos >= 0) {
+ String setName = cardName.substring(pipePos + 1).trim();
+ cardName = cardName.substring(0, pipePos);
+ // only if set is not blank try to load it
+ if (StringUtils.isNotBlank(setName) && !"???".equals(setName)) {
+ return new ImmutablePair(cardName, setName);
+ }
+ }
+ return new ImmutablePair(cardName, null);
+ }
+
// Single fetch
public CardPrinted getCard(final String name) {
// Sometimes they read from decks things like "CardName|Set" - but we can handle it
- int pipePos = name.indexOf('|');
- String cardName = name;
- if (pipePos >= 0) {
- cardName = name.substring(0, pipePos);
- String setName = name.substring(pipePos + 1).trim();
- // only if set is not blank try to load it
- if (StringUtils.isNotBlank(setName) && !"???".equals(setName)) {
- return getCard(cardName, setName);
- }
- }
+ ImmutablePair nameWithSet = splitCardName(name);
+ if (nameWithSet.right != null) { return getCard(nameWithSet.left, nameWithSet.right); }
// OK, plain name here
- CardPrinted card = uniqueCards.get(cardName.toLowerCase());
+ CardPrinted card = uniqueCards.get(nameWithSet.left.toLowerCase());
if (card != null) { return card; }
throw new NoSuchElementException(String.format("Card '%s' not found in our database.", name));
}