package net.demilich.metastone.game.cards;
import java.util.EnumMap;
import net.demilich.metastone.game.Attribute;
import net.demilich.metastone.game.GameContext;
import net.demilich.metastone.game.Player;
import net.demilich.metastone.game.actions.PlayCardAction;
import net.demilich.metastone.game.cards.desc.CardDesc;
import net.demilich.metastone.game.entities.Entity;
import net.demilich.metastone.game.entities.EntityType;
import net.demilich.metastone.game.entities.heroes.HeroClass;
import net.demilich.metastone.game.entities.minions.Race;
import net.demilich.metastone.game.spells.desc.BattlecryDesc;
import net.demilich.metastone.game.spells.desc.valueprovider.ValueProvider;
import net.demilich.metastone.game.targeting.CardLocation;
import net.demilich.metastone.game.targeting.CardReference;
import net.demilich.metastone.game.targeting.IdFactory;
public abstract class Card extends Entity {
private String description = "";
private final CardType cardType;
private final CardSet cardSet;
private final Rarity rarity;
private HeroClass heroClass;
private HeroClass[] heroClasses;
private boolean collectible = true;
private CardLocation location;
private BattlecryDesc battlecry;
private ValueProvider manaCostModifier;
private final String cardId;
public Card(CardDesc desc) {
cardId = desc.id;
setName(desc.name);
setDescription(desc.description);
setCollectible(desc.collectible);
cardType = desc.type;
cardSet = desc.set;
rarity = desc.rarity;
heroClass = desc.heroClass;
if (desc.heroClasses != null) {
heroClasses = desc.heroClasses;
}
setAttribute(Attribute.BASE_MANA_COST, desc.baseManaCost);
if (desc.attributes != null) {
attributes.putAll(desc.attributes);
}
if (desc.manaCostModifier != null) {
manaCostModifier = desc.manaCostModifier.create();
}
if (desc.passiveTrigger != null) {
attributes.put(Attribute.PASSIVE_TRIGGER, desc.passiveTrigger);
}
if (desc.deckTrigger != null) {
attributes.put(Attribute.DECK_TRIGGER, desc.deckTrigger);
}
}
@Override
public Card clone() {
Card clone = (Card) super.clone();
clone.attributes = new EnumMap<>(getAttributes());
return clone;
}
public boolean evaluateExpression(String operator, int value1, int value2) {
switch(operator) {
case "=":
return value1 == value2;
case ">":
return value1 > value2;
case "<":
return value1 < value2;
case ">=":
return value1 >= value2;
case "<=":
return value1 <= value2;
case "!=":
return value1 != value2;
}
return false;
}
public int getBaseManaCost() {
return getAttributeValue(Attribute.BASE_MANA_COST);
}
public BattlecryDesc getBattlecry() {
return battlecry;
}
public String getCardId() {
return cardId;
}
public CardReference getCardReference() {
return new CardReference(getOwner(), getLocation(), getId(), getName());
}
public CardSet getCardSet() {
return cardSet;
}
public CardType getCardType() {
return cardType;
}
public HeroClass getHeroClass() {
return heroClass;
}
public HeroClass[] getHeroClasses() {
return heroClasses;
}
public Card getCopy() {
Card copy = clone();
copy.setId(IdFactory.UNASSIGNED);
copy.setLocation(CardLocation.PENDING);
copy.removeAttribute(Attribute.ATTACK_BONUS);
copy.removeAttribute(Attribute.HP_BONUS);
copy.removeAttribute(Attribute.MANA_COST_MODIFIER);
return copy;
}
public String getDescription() {
return description;
}
@Override
public EntityType getEntityType() {
return EntityType.CARD;
}
public CardLocation getLocation() {
return location;
}
public int getManaCost(GameContext context, Player player) {
int actualManaCost = getBaseManaCost();
if (manaCostModifier != null) {
actualManaCost -= manaCostModifier.getValue(context, player, null, this);
}
return actualManaCost;
}
public Rarity getRarity() {
return rarity;
}
public Race getRace() {
return hasAttribute(Attribute.RACE) ? (Race) getAttribute(Attribute.RACE) : Race.NONE;
}
public boolean hasBattlecry() {
return this.battlecry != null;
}
public boolean hasHeroClass(HeroClass heroClass) {
if (getHeroClasses() != null) {
for (HeroClass h : getHeroClasses()) {
if (heroClass.equals(h)) {
return true;
}
}
} else if (heroClass == getHeroClass()) {
return true;
}
return false;
}
public boolean isCollectible() {
return collectible;
}
public boolean matchesFilter(String filter) {
if (filter == null || filter == "") {
return true;
}
String[] filters = filter.split(" ");
for (String splitString : filters) {
if (!matchesSplitFilter(splitString)) {
return false;
}
}
return true;
}
public boolean matchesSplitFilter(String filter) {
filter = filter.toLowerCase();
String[] split = filter.split("((<|>)=?)|(!?=)");
if (split.length >= 2) {
int value;
try {
value = Integer.parseInt(split[1]);
} catch (Exception e) {
return false;
}
String operator = filter.substring(split[0].length(), filter.indexOf(split[1], split[0].length() + 1));
if ((split[0].contains("mana") || split[0].contains("cost")) &&
evaluateExpression(operator, getBaseManaCost(), value)) {
return true;
}
if (split[0].contains("attack") && hasAttribute(Attribute.BASE_ATTACK) &&
evaluateExpression(operator, getAttributeValue(Attribute.BASE_ATTACK), value)) {
return true;
}
if ((split[0].contains("health") || split[0].contains("hp")) && hasAttribute(Attribute.BASE_HP) &&
evaluateExpression(operator, getAttributeValue(Attribute.BASE_HP), value)) {
return true;
}
}
if (getRarity().toString().toLowerCase().contains(filter)) {
return true;
}
if (getRace() != Race.NONE && getRace().toString().toLowerCase().contains(filter)) {
return true;
}
String cardType = getCardType() == CardType.CHOOSE_ONE ? "SPELL" : getCardType().toString();
if (cardType.toLowerCase().contains(filter)) {
return true;
}
if ((getHeroClass() == HeroClass.ANY && "neutral".contains(filter))
|| (getHeroClass() != HeroClass.ANY && (getHeroClass().toString().toLowerCase().contains(filter)
|| "class".contains(filter)))) {
return true;
}
String lowerCaseName = getName().toLowerCase();
if (lowerCaseName.contains(filter)) {
return true;
}
String regexName = lowerCaseName.replaceAll("[:,\'\\- ]+", "");
if (regexName.contains(filter)) {
return true;
}
if (getDescription() != null) {
String lowerCaseDescription = getDescription().toLowerCase();
if (lowerCaseDescription.contains(filter)) {
return true;
}
}
return false;
}
public abstract PlayCardAction play();
public void setBattlecry(BattlecryDesc battlecry) {
this.battlecry = battlecry;
}
public void setCollectible(boolean collectible) {
this.collectible = collectible;
}
public void setDescription(String description) {
this.description = description;
}
public void setLocation(CardLocation location) {
this.location = location;
}
@Override
public String toString() {
return String.format("[%s '%s' %s Manacost:%d]", getCardType(), getName(), getReference(), getBaseManaCost());
}
}