package com.hearthsim.util;

import com.hearthsim.card.Card;
import com.hearthsim.exception.HSInvalidCardException;
import org.json.JSONArray;
import org.json.JSONObject;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;

/**
 * A utility class to convert a card name into a Card class instance
 *
 */
public class CardFactory {

    private static Map<String, String> cardCache;

    private static void loadCardData() {
        JSONArray implementedCards;
        try {
            InputStream stream = CardFactory.class.getClassLoader().getResourceAsStream("implemented_cards.json");
            BufferedReader streamReader = new BufferedReader(new InputStreamReader(stream, "UTF-8"));
            StringBuilder responseStrBuilder = new StringBuilder();

            String inputStr;
            while ((inputStr = streamReader.readLine()) != null)
                responseStrBuilder.append(inputStr);
            implementedCards = new JSONArray(responseStrBuilder.toString());
        } catch (IOException e) {
            implementedCards = null;
        }
        if (implementedCards != null) {
            cardCache = new HashMap<>();
            synchronized (cardCache) {
                for (int indx = 0; indx < implementedCards.length(); ++indx) {
                    JSONObject obj = implementedCards.getJSONObject(indx);
                    String[] cardName = obj.optString("class").split("\\.");
                    cardCache.put(cardName[cardName.length - 1].trim(), obj.optString("class"));
                }
            }
        }
    }

    public static Card getCard(String cardName) throws HSInvalidCardException {
        if (cardCache == null)
            loadCardData();
        String cleanedString = cardName.trim();
        if (cardCache == null)
            throw new HSInvalidCardException("Unable to open implemented_cards.json");

        try {
            Class<?> clazz = Class.forName(cardCache.get(cleanedString));
            Constructor<?> ctor = clazz.getConstructor();
            Object object = ctor.newInstance();
            return (Card)object;
        } catch (ClassNotFoundException | NoSuchMethodException | InvocationTargetException | InstantiationException | IllegalAccessException e) {
            throw new HSInvalidCardException("Unknown card: " + cleanedString);
        }
    }
}

@@ -582,16 +582,68 @@
 rdCache;
+%0A    private static Map%3CString, String%3E cardIdCache;
 %0A%0A    pr
@@ -1395,24 +1395,67 @@
 ashMap%3C%3E();%0A
+            cardIdCache = new HashMap%3C%3E();%0A
             
@@ -1805,24 +1805,106 @@
 (%22class%22));%0A
+                    cardIdCache.put(obj.getString(%22id%22), obj.optString(%22class%22));%0A
             
@@ -2710,16 +2710,800 @@
       %7D%0A
-
     %7D%0A
+%0A    public static Card getCardById(String cardId) throws HSInvalidCardException %7B%0A        if (cardIdCache == null)%0A            loadCardData();%0A        String cleanedString = cardId.trim();%0A        if (cardIdCache == null)%0A            throw new HSInvalidCardException(%22Unable to open implemented_cards.json%22);%0A%0A        try %7B%0A            Class%3C?%3E clazz = Class.forName(cardIdCache.get(cleanedString));%0A            Constructor%3C?%3E ctor = clazz.getConstructor();%0A            Object object = ctor.newInstance();%0A            return (Card)object;%0A        %7D catch (ClassNotFoundException %7C NoSuchMethodException %7C InvocationTargetException %7C InstantiationException %7C IllegalAccessException e) %7B%0A            throw new HSInvalidCardException(%22Unknown card: %22 + cleanedString);%0A        %7D%0A    %7D%0A%0A
 %7D%0A

Allow getting card by ID