/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package org.mage.plugins.card.dl.sources;
import org.apache.log4j.Logger;
import org.mage.plugins.card.images.CardDownloadData;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
*
* @author Quercitron
*/
public enum TokensMtgImageSource implements CardImageSource {
instance;
private static final Logger logger = Logger.getLogger(TokensMtgImageSource.class);
private List<TokenData> tokensData;
private final Object tokensDataSync = new Object();
@Override
public String getSourceName() {
return "tokens.mtg.onl";
}
@Override
public float getAverageSize() {
return 26.7f;
}
@Override
public String getNextHttpImageUrl() {
return null;
}
@Override
public String getFileForHttpImage(String httpImageUrl) {
return null;
}
@Override
public String generateURL(CardDownloadData card) throws Exception {
return null;
}
private static final String[] EMBLEMS = {
"Ajani",
"Arlinn",
"Chandra",
"Dack",
"Daretti",
"Dovin",
"Domri",
"Elspeth",
"Garruk",
"Gideon",
"Jace",
"Kiora",
"Koth",
"Liliana",
"Narset",
"Nixilis",
"Sarkhan",
"Sorin",
"Tamiyo",
"Teferi",
"Venser",};
private static final Map<String, String> SET_NAMES_REPLACEMENT = new HashMap<String, String>() {
{
put("con", "CFX");
put("fnmp", "FNM");
}
};
@Override
public String generateTokenUrl(CardDownloadData card) throws IOException {
String name = card.getName();
String set = card.getSet();
int type = card.getType();
// handle emblems
if (name.toLowerCase().contains("emblem")) {
for (String emblem : EMBLEMS) {
if (name.toLowerCase().contains(emblem.toLowerCase())) {
name = emblem + " Emblem";
break;
}
}
}
// we should replace some set names
if (SET_NAMES_REPLACEMENT.containsKey(set.toLowerCase())) {
set = SET_NAMES_REPLACEMENT.get(set.toLowerCase());
}
// Image URL contains token number
// e.g. http://tokens.mtg.onl/tokens/ORI_010-Thopter.jpg -- token number 010
// We don't know these numbers, but we can take them from a file
// with tokens information that can be downloaded from the site.
List<TokenData> newTokensData = getTokensData();
if (newTokensData.isEmpty()) {
return null;
}
List<TokenData> matchedTokens = new ArrayList<>();
for (TokenData token : newTokensData) {
if (name.equalsIgnoreCase(token.getName()) && set.equalsIgnoreCase(token.getExpansionSetCode())) {
matchedTokens.add(token);
}
}
//
// if (matchedTokens.isEmpty()) {
// logger.info("Could not find data for token " + name + ", set " + set + ".");
// return null;
// }
TokenData tokenData;
if (type == 0) {
if (matchedTokens.size() > 1) {
logger.info("Multiple images were found for token " + name + ", set " + set + '.');
}
tokenData = matchedTokens.get(0);
} else {
if (type > matchedTokens.size()) {
logger.warn("Not enough images for token with type " + type + ", name " + name + ", set " + set + '.');
return null;
}
tokenData = matchedTokens.get(card.getType() - 1);
}
String url = "http://tokens.mtg.onl/tokens/" + tokenData.getExpansionSetCode().trim() + '_'
+ tokenData.getNumber().trim() + '-' + tokenData.getName().trim() + ".jpg";
url = url.replace(' ', '-');
return url;
}
private List<TokenData> getTokensData() throws IOException {
synchronized (tokensDataSync) {
if (tokensData == null) {
tokensData = new ArrayList<>();
// get tokens data from resource file
try(InputStream inputStream = this.getClass().getResourceAsStream("/tokens-mtg-onl-list.csv")) {
List<TokenData> fileTokensData = parseTokensData(inputStream);
tokensData.addAll(fileTokensData);
} catch (Exception exception) {
logger.warn("Failed to get tokens description from resource file tokens-mtg-onl-list.csv", exception);
}
// description on site may contain new information
// try to add it
URL url = new URL("http://tokens.mtg.onl/data/SetsWithTokens.csv");
try(InputStream inputStream = url.openStream()) {
List<TokenData> siteTokensData = parseTokensData(inputStream);
List<TokenData> newTokensData = new ArrayList<>();
for (TokenData siteData : siteTokensData) {
boolean isNew = true;
for (TokenData fileData : tokensData) {
if (siteData.getName().equalsIgnoreCase(fileData.getName())
&& siteData.getNumber().equalsIgnoreCase(fileData.getNumber())
&& siteData.getExpansionSetCode().equalsIgnoreCase(fileData.getExpansionSetCode())) {
isNew = false;
break;
}
}
if (isNew) {
newTokensData.add(siteData);
}
}
tokensData.addAll(newTokensData);
} catch (Exception exception) {
logger.warn("Failed to get tokens description from tokens.mtg.onl", exception);
}
}
}
return tokensData;
}
private List<TokenData> parseTokensData(InputStream inputStream) throws IOException {
List<TokenData> newTokensData = new ArrayList<>();
try(InputStreamReader inputReader = new InputStreamReader(inputStream, "Cp1252");
BufferedReader reader = new BufferedReader(inputReader)) {
// we have to specify encoding to read special comma
reader.readLine(); // skip header
String line = reader.readLine();
// states
// 0 - wait set name
// 1 - wait cards
// 2 - process cards
int state = 0;
String set = null;
while (line != null) {
if (line.trim().isEmpty()) {
if (state == 2) {
state = 0;
}
} else if (state == 0) {
set = line.substring(0, 3);
state = 1;
} else {
if (state == 1) {
state = 2;
}
String[] split = line.split(",");
// replace special comma for cards like 'Ashaya‚ the Awoken World'
String name = split[0].replace('‚', ',');
String number = split[1];
TokenData token = new TokenData(name, number, set);
newTokensData.add(token);
}
line = reader.readLine();
}
}
return newTokensData;
}
static final class TokenData {
final private String name;
final private String number;
final private String expansionSetCode;
public TokenData(String name, String number, String expansionSetCode) {
this.name = name;
this.number = number;
this.expansionSetCode = expansionSetCode;
}
public String getName() {
return name;
}
public String getNumber() {
return number;
}
public String getExpansionSetCode() {
return expansionSetCode;
}
}
@Override
public int getTotalImages() {
return -1;
}
@Override
public boolean isTokenSource() {
return true;
}
@Override
public void doPause(String httpImageUrl) {
}
}