package net.demilich.metastone.game.cards;
import java.io.FileNotFoundException;
import java.io.InputStreamReader;
import java.lang.reflect.Type;
import java.util.Map;
import net.demilich.metastone.utils.ResourceInputStream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonElement;
import com.google.gson.reflect.TypeToken;
import net.demilich.metastone.game.Attribute;
import net.demilich.metastone.game.cards.desc.AttributeDeserializer;
import net.demilich.metastone.game.cards.desc.AuraDeserializer;
import net.demilich.metastone.game.cards.desc.CardCostModifierDeserializer;
import net.demilich.metastone.game.cards.desc.CardDesc;
import net.demilich.metastone.game.cards.desc.ChooseBattlecryCardDesc;
import net.demilich.metastone.game.cards.desc.ChooseOneCardDesc;
import net.demilich.metastone.game.cards.desc.ConditionDeserializer;
import net.demilich.metastone.game.cards.desc.HeroCardDesc;
import net.demilich.metastone.game.cards.desc.HeroPowerCardDesc;
import net.demilich.metastone.game.cards.desc.MinionCardDesc;
import net.demilich.metastone.game.cards.desc.PermanentCardDesc;
import net.demilich.metastone.game.cards.desc.QuestCardDesc;
import net.demilich.metastone.game.cards.desc.SecretCardDesc;
import net.demilich.metastone.game.cards.desc.SpellCardDesc;
import net.demilich.metastone.game.cards.desc.SpellDeserializer;
import net.demilich.metastone.game.cards.desc.ValueProviderDeserializer;
import net.demilich.metastone.game.cards.desc.WeaponCardDesc;
import net.demilich.metastone.game.entities.heroes.HeroClass;
import net.demilich.metastone.game.spells.desc.SpellDesc;
import net.demilich.metastone.game.spells.desc.aura.AuraDesc;
import net.demilich.metastone.game.spells.desc.condition.ConditionDesc;
import net.demilich.metastone.game.spells.desc.manamodifier.CardCostModifierDesc;
import net.demilich.metastone.game.spells.desc.trigger.EventTriggerDesc;
import net.demilich.metastone.game.spells.desc.trigger.EventTriggerDeserializer;
import net.demilich.metastone.game.spells.desc.valueprovider.ValueProviderDesc;
public class CardParser {
private static Logger logger = LoggerFactory.getLogger(CardParser.class);
private final Gson gson;
public CardParser() {
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.registerTypeAdapter(SpellDesc.class, new SpellDeserializer());
Type mapType = new TypeToken<Map<Attribute, Object>>() {
}.getType();
gsonBuilder.registerTypeAdapter(mapType, new AttributeDeserializer());
gsonBuilder.registerTypeAdapter(ConditionDesc.class, new ConditionDeserializer());
gsonBuilder.registerTypeAdapter(EventTriggerDesc.class, new EventTriggerDeserializer());
gsonBuilder.registerTypeAdapter(AuraDesc.class, new AuraDeserializer());
gsonBuilder.registerTypeAdapter(ValueProviderDesc.class, new ValueProviderDeserializer());
gsonBuilder.registerTypeAdapter(CardCostModifierDesc.class, new CardCostModifierDeserializer());
gson = gsonBuilder.create();
}
public CardDesc parseCard(ResourceInputStream resourceInputStream) throws FileNotFoundException {
JsonElement jsonData = gson.fromJson(new InputStreamReader(resourceInputStream.inputStream), JsonElement.class);
String id = resourceInputStream.fileName.split("(\\.json)")[0];
jsonData.getAsJsonObject().addProperty("id", id);
if (!jsonData.getAsJsonObject().has("name")) {
throw new RuntimeException(resourceInputStream.fileName + " is missing 'name' attribute!");
}
if (!jsonData.getAsJsonObject().has("type")) {
throw new RuntimeException(resourceInputStream.fileName + " is missing 'type' attribute!");
}
if (!jsonData.getAsJsonObject().has("heroClass")) {
throw new RuntimeException(resourceInputStream.fileName + " is missing 'heroClass' attribute!");
} else {
boolean check = false;
for (HeroClass heroClass : HeroClass.values()) {
if (jsonData.getAsJsonObject().get("heroClass").getAsString().equalsIgnoreCase(heroClass.toString())) {
check = true;
}
}
if (!check) {
throw new RuntimeException(resourceInputStream.fileName + " has corrupted 'heroClass' attribute!");
}
}
if (!jsonData.getAsJsonObject().has("rarity")) {
throw new RuntimeException(resourceInputStream.fileName + " is missing 'rarity' attribute!");
} else {
boolean check = false;
for (Rarity rarity : Rarity.values()) {
if (jsonData.getAsJsonObject().get("rarity").getAsString().equalsIgnoreCase(rarity.toString())) {
check = true;
}
}
if (!check) {
throw new RuntimeException(resourceInputStream.fileName + " has corrupted 'rarity' attribute!");
}
}
if (!jsonData.getAsJsonObject().has("collectible")) {
throw new RuntimeException(resourceInputStream.fileName + " is missing 'collectible' attribute!");
}
if (!jsonData.getAsJsonObject().has("set")) {
throw new RuntimeException(resourceInputStream.fileName + " is missing 'set' attribute!");
}
CardType type = CardType.valueOf((String) jsonData.getAsJsonObject().get("type").getAsString());
switch (type) {
case SPELL:
if (!jsonData.getAsJsonObject().has("baseManaCost")) {
throw new RuntimeException(resourceInputStream.fileName + " is missing 'baseManaCost' attribute!");
}
if (!jsonData.getAsJsonObject().has("description")) {
throw new RuntimeException(resourceInputStream.fileName + " is missing 'description' attribute!");
}
if (!jsonData.getAsJsonObject().has("spell")) {
throw new RuntimeException(resourceInputStream.fileName + " is missing 'spell' attribute!");
}
if (jsonData.getAsJsonObject().has("trigger")) {
return gson.fromJson(jsonData, SecretCardDesc.class);
} else if (jsonData.getAsJsonObject().has("quest")) {
return gson.fromJson(jsonData, QuestCardDesc.class);
} else {
if (!jsonData.getAsJsonObject().has("targetSelection")) {
throw new RuntimeException(resourceInputStream.fileName + " is missing 'targetSelection' attribute!");
}
return gson.fromJson(jsonData, SpellCardDesc.class);
}
case CHOOSE_ONE:
if (!jsonData.getAsJsonObject().has("baseManaCost")) {
throw new RuntimeException(resourceInputStream.fileName + " is missing 'baseManaCost' attribute!");
}
if (!jsonData.getAsJsonObject().has("description")) {
throw new RuntimeException(resourceInputStream.fileName + " is missing 'description' attribute!");
}
if (!jsonData.getAsJsonObject().has("options")) {
throw new RuntimeException(resourceInputStream.fileName + " is missing 'options' attribute!");
}
if (!jsonData.getAsJsonObject().has("bothOptions")) {
throw new RuntimeException(resourceInputStream.fileName + " is missing 'bothOptions' attribute!");
}
return gson.fromJson(jsonData, ChooseOneCardDesc.class);
case MINION:
if (!jsonData.getAsJsonObject().has("baseManaCost")) {
throw new RuntimeException(resourceInputStream.fileName + " is missing 'baseManaCost' attribute!");
}
if (!jsonData.getAsJsonObject().has("baseAttack")) {
throw new RuntimeException(resourceInputStream.fileName + " is missing 'baseAttack' attribute!");
}
if (!jsonData.getAsJsonObject().has("baseHp")) {
throw new RuntimeException(resourceInputStream.fileName + " is missing 'baseHp' attribute!");
}
if (!jsonData.getAsJsonObject().has("description") && (jsonData.getAsJsonObject().has("battlecry") ||
jsonData.getAsJsonObject().has("deathrattle") ||jsonData.getAsJsonObject().has("attributes") ||
jsonData.getAsJsonObject().has("trigger") || jsonData.getAsJsonObject().has("passiveTrigger") ||
jsonData.getAsJsonObject().has("deckTrigger") || jsonData.getAsJsonObject().has("options"))) {
throw new RuntimeException(resourceInputStream.fileName + " is missing 'description' attribute!");
}
if (jsonData.getAsJsonObject().has("options")) {
return gson.fromJson(jsonData, ChooseBattlecryCardDesc.class);
} else {
return gson.fromJson(jsonData, MinionCardDesc.class);
}
case PERMANENT:
if (!jsonData.getAsJsonObject().has("description") && (jsonData.getAsJsonObject().has("battlecry") ||
jsonData.getAsJsonObject().has("deathrattle") ||jsonData.getAsJsonObject().has("attributes") ||
jsonData.getAsJsonObject().has("trigger") || jsonData.getAsJsonObject().has("passiveTrigger") ||
jsonData.getAsJsonObject().has("deckTrigger") || jsonData.getAsJsonObject().has("options"))) {
throw new RuntimeException(resourceInputStream.fileName + " is missing 'description' attribute!");
}
return gson.fromJson(jsonData, PermanentCardDesc.class);
case WEAPON:
if (!jsonData.getAsJsonObject().has("baseManaCost")) {
throw new RuntimeException(resourceInputStream.fileName + " is missing 'baseManaCost' attribute!");
}
if (!jsonData.getAsJsonObject().has("damage")) {
throw new RuntimeException(resourceInputStream.fileName + " is missing 'damage' attribute!");
}
if (!jsonData.getAsJsonObject().has("durability")) {
throw new RuntimeException(resourceInputStream.fileName + " is missing 'durability' attribute!");
}
if (!jsonData.getAsJsonObject().has("description") && (jsonData.getAsJsonObject().has("battlecry") ||
jsonData.getAsJsonObject().has("deathrattle") ||jsonData.getAsJsonObject().has("attributes") ||
jsonData.getAsJsonObject().has("trigger") || jsonData.getAsJsonObject().has("passiveTrigger") ||
jsonData.getAsJsonObject().has("deckTrigger") || jsonData.getAsJsonObject().has("onEquip") ||
jsonData.getAsJsonObject().has("onUnequip"))) {
throw new RuntimeException(resourceInputStream.fileName + " is missing 'description' attribute!");
}
return gson.fromJson(jsonData, WeaponCardDesc.class);
case HERO_POWER:
if (!jsonData.getAsJsonObject().has("baseManaCost")) {
throw new RuntimeException(resourceInputStream.fileName + " is missing 'baseManaCost' attribute!");
}
if (!jsonData.getAsJsonObject().has("description")) {
throw new RuntimeException(resourceInputStream.fileName + " is missing 'description' attribute!");
}
if (!jsonData.getAsJsonObject().has("spell") && !jsonData.getAsJsonObject().has("options")) {
throw new RuntimeException(resourceInputStream.fileName + " is missing 'spell' or 'options' attribute!");
}
if (!jsonData.getAsJsonObject().has("targetSelection")) {
throw new RuntimeException(resourceInputStream.fileName + " is missing 'targetSelection' attribute!");
}
return gson.fromJson(jsonData, HeroPowerCardDesc.class);
case HERO:
return gson.fromJson(jsonData, HeroCardDesc.class);
default:
logger.error("Unknown cardType: " + type);
break;
}
return null;
}
}