package net.demilich.metastone.game.cards;
import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Predicate;
import org.jsoup.Jsoup;
import org.jsoup.Connection.Response;
import org.jsoup.nodes.Document;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import net.demilich.metastone.BuildConfig;
import net.demilich.metastone.game.Attribute;
import net.demilich.metastone.game.cards.desc.CardDesc;
import net.demilich.metastone.game.decks.DeckFormat;
import net.demilich.metastone.game.entities.heroes.HeroClass;
import net.demilich.metastone.utils.MetastoneProperties;
import net.demilich.metastone.utils.ResourceInputStream;
import net.demilich.metastone.utils.ResourceLoader;
import net.demilich.metastone.utils.UserHomeMetastone;
public class CardCatalogue {
public static final String CARDS_FOLDER = "cards";
public static final String LOCAL_CARDS_FOLDER = "../cards/src/main/resources/cards/";
public static final String CARDS_FOLDER_PATH = UserHomeMetastone.getPath() + File.separator + CARDS_FOLDER;
public static final String CARDS_COPIED_PROPERTY = "cardRevision";
private static Logger logger = LoggerFactory.getLogger(CardCatalogue.class);
private final static CardCollection cards = new CardCollection();
public static void add(Card card) {
cards.add(card);
}
public static CardCollection getAll() {
CardCollection result = new CardCollection();
for (Card card : cards) {
result.add(card);
}
return result;
}
public static Card getCardById(String id) {
for (Card card : cards) {
if (card.getCardId() != null && card.getCardId().equalsIgnoreCase(id)) {
return card.clone();
}
}
return null;
}
public static Card getCardByName(String name) {
for (Card card : cards) {
if (card.isCollectible() && card.getName().equals(name)) {
return card.clone();
}
}
return null;
}
public static Card getCardByBlizzardId(String id) throws IOException{
Response response= Jsoup.connect("http://metastats.net/cardstats/" + id.toUpperCase() + "/")
.ignoreContentType(true)
.userAgent("Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:25.0) Gecko/20100101 Firefox/25.0")
.referrer("http://www.google.com")
.timeout(12000)
.followRedirects(true)
.execute();
Document doc = response.parse();
return getCardByName(doc.getElementsByTag("h3").get(0).text());
}
public static CardCollection getHeroes() {
return query(null, card -> card.isCollectible() && card.getCardType() == CardType.HERO);
}
public static CardCollection getHeroPowers(DeckFormat deckFormat) {
return query(deckFormat, card -> card.isCollectible() && card.getCardType() == CardType.HERO_POWER);
}
public static CardCollection query(DeckFormat deckFormat) {
return query(deckFormat, (CardType) null, (Rarity) null, (HeroClass) null, (Attribute) null);
}
public static CardCollection query(DeckFormat deckFormat, CardType cardType) {
return query(deckFormat, cardType, (Rarity) null, (HeroClass) null, (Attribute) null);
}
public static CardCollection query(DeckFormat deckFormat, HeroClass heroClass) {
return query(deckFormat, (CardType) null, (Rarity) null, heroClass, (Attribute) null);
}
public static CardCollection query(DeckFormat deckFormat, CardType cardType, Rarity rarity, HeroClass heroClass) {
return query(deckFormat, cardType, rarity, heroClass, (Attribute) null);
}
public static CardCollection query(DeckFormat deckFormat, CardType cardType, Rarity rarity, HeroClass heroClass, Attribute tag) {
CardCollection result = new CardCollection();
for (Card card : cards) {
if (!deckFormat.isInFormat(card)) {
continue;
}
if (!card.isCollectible()) {
continue;
}
if (cardType != null && !card.getCardType().isCardType(cardType)) {
continue;
}
// per default, do not include heroes or hero powers
if (card.getCardType().isCardType(CardType.HERO_POWER) || card.getCardType().isCardType(CardType.HERO)) {
continue;
}
if (rarity != null && !card.getRarity().isRarity(rarity)) {
continue;
}
if (heroClass != null && !card.hasHeroClass(heroClass)) {
continue;
}
if (tag != null && !card.hasAttribute(tag)) {
continue;
}
result.add(card.clone());
}
return result;
}
public static CardCollection query(DeckFormat deckFormat, Predicate<Card> filter) {
CardCollection result = new CardCollection();
for (Card card : cards) {
if (deckFormat != null && !deckFormat.isInFormat(card)) {
continue;
}
if (filter.test(card)) {
result.add(card);
}
}
return result;
}
public static void loadLocalCards() throws IOException, URISyntaxException, CardParseException {
// load cards from ~/metastone/cards on the file system
Collection<ResourceInputStream> inputStreams = ResourceLoader.loadJsonInputStreams(CARDS_FOLDER, false);
loadCards(inputStreams);
}
public static void loadCards() throws IOException, URISyntaxException, CardParseException {
// load cards from ~/metastone/cards on the file system
Collection<ResourceInputStream> inputStreams = ResourceLoader.loadJsonInputStreams(CARDS_FOLDER_PATH, true);
loadCards(inputStreams);
}
private static void loadCards(Collection<ResourceInputStream> inputStreams) throws IOException, URISyntaxException, CardParseException {
Map<String, CardDesc> cardDesc = new HashMap<String, CardDesc>();
ArrayList<String> badCards = new ArrayList<>();
CardParser cardParser = new CardParser();
for (ResourceInputStream resourceInputStream : inputStreams) {
try {
CardDesc desc = cardParser.parseCard(resourceInputStream);
if (cardDesc.containsKey(desc.id)) {
logger.error("Card id {} is duplicated!", desc.id);
}
cardDesc.put(desc.id, desc);
} catch (Exception e) {
//logger.error("Error parsing card '{}'", resourceInputStream.fileName);
logger.error(e.toString());
badCards.add(resourceInputStream.fileName);
}
}
for (CardDesc desc : cardDesc.values()) {
Card instance = desc.createInstance();
CardCatalogue.add(instance);
logger.debug("Adding {} to CardCatalogue", instance);
}
if (!badCards.isEmpty()) {
throw new CardParseException(badCards);
}
}
public static void copyCardsFromResources() throws IOException, URISyntaxException {
// if we have not copied cards to the USER_HOME_METASTONE cards folder,
// then do so now
int cardRevision = MetastoneProperties.getInt(CARDS_COPIED_PROPERTY, 0);
System.out.println("Existing card revision = " + cardRevision);
if (BuildConfig.CARD_REVISION > cardRevision) {
logger.info("Card update required: MetaStone card revision is: {}, last card update was with revision {}", BuildConfig.CARD_REVISION, cardRevision);
ResourceLoader.copyFromResources(CARDS_FOLDER, CARDS_FOLDER_PATH);
// set a property to indicate that we have copied the cards with current version
MetastoneProperties.setProperty(CARDS_COPIED_PROPERTY, String.valueOf(BuildConfig.CARD_REVISION));
} else {
logger.info("Cards in user home folder are up-to-date: rev {}", cardRevision);
}
}
}