package com.hearthsim.util;

import com.hearthsim.card.Card;
import com.hearthsim.exception.HSInvalidCardException;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

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

    public static Card getCard(String cardName) throws HSInvalidCardException {
        String cleanedString = cardName.trim();
        try {
            Class<?> clazz = Class.forName("com.hearthsim.card.minion.concrete." + cleanedString);
            Constructor<?> ctor = clazz.getConstructor();
            Object object = ctor.newInstance();
            return (Card)object;
        } catch (ClassNotFoundException e) {
            try {
                Class<?> clazz = Class.forName("com.hearthsim.card.spellcard.concrete." + cleanedString);
                Constructor<?> ctor = clazz.getConstructor();
                Object object = ctor.newInstance();
                return (Card)object;
            } catch (ClassNotFoundException | NoSuchMethodException | SecurityException | InvocationTargetException | InstantiationException | IllegalAccessException | IllegalArgumentException e2) {
                throw new HSInvalidCardException("Unknown card: " + cleanedString);
            }
        } catch (NoSuchMethodException | SecurityException | InvocationTargetException | InstantiationException | IllegalAccessException | IllegalArgumentException e) {
            throw new HSInvalidCardException("Unknown card: " + cleanedString);
        }
    }
}

@@ -109,16 +109,89 @@
 eption;%0A
+import org.json.JSONArray;%0Aimport org.json.JSONObject;%0A%0Aimport java.io.*;
 %0Aimport 
@@ -272,16 +272,64 @@
 ception;
+%0Aimport java.util.HashMap;%0Aimport java.util.Map;
 %0A%0A/**%0A *
@@ -439,21 +439,22 @@
    p
-ublic
+rivate
  static 
 Card
@@ -453,289 +453,417 @@
 tic 
-Card getCard(
+Map%3CString, 
 String
+%3E
  card
-Name) throws HSInvalidCardException %7B%0A        String cleanedString = cardName.trim();%0A        try %7B%0A            Class%3C?%3E clazz = Class.forName(%22com.hearthsim.card.minion.concrete.%22 + cleanedString);%0A            Constructor%3C?%3E ctor = clazz.getConstructo
+Cache;%0A%0A    private static void loadCardData() %7B%0A        JSONArray implementedCards;%0A        try %7B%0A            InputStream stream = CardFactory.class.getClassLoader().getResourceAsStream(%22implemented_cards.json%22);%0A            BufferedReader streamReader = new BufferedReader(new InputStreamReader(stream, %22UTF-8%22));%0A            StringBuilder responseStrBuilder = new StringBuilde
 r();%0A
+%0A
     
@@ -874,75 +874,218 @@
     
-Object object = ctor.newInstance();%0A            return (Card)object
+String inputStr;%0A            while ((inputStr = streamReader.readLine()) != null)%0A                responseStrBuilder.append(inputStr);%0A            implementedCards = new JSONArray(responseStrBuilder.toString())
 ;%0A  
@@ -1095,37 +1095,26 @@
    %7D catch (
-ClassNotFound
+IO
 Exception e)
@@ -1120,37 +1120,56 @@
 ) %7B%0A            
-try %7B
+implementedCards = null;
 %0A               
@@ -1161,24 +1161,26 @@
         
+%7D%0A
         
 Class%3C?%3E
@@ -1175,159 +1175,198 @@
     
-Class%3C?%3E clazz = Class.forName(%22com.hearthsim.card.spellcard.concrete.%22 + cleanedString);%0A                Constructor%3C?%3E ctor = clazz.getConstructor();
+if (implementedCards != null) %7B%0A            cardCache = new HashMap%3C%3E();%0A            synchronized (cardCache) %7B%0A                for (int indx = 0; indx %3C implementedCards.length(); ++indx) %7B
 %0A   
@@ -1378,16 +1378,24 @@
         
+    JSON
 Object o
@@ -1400,71 +1400,133 @@
  obj
-ect = ctor.newInstance();%0A                return (Card)object;%0A
+ = implementedCards.getJSONObject(indx);%0A                    String%5B%5D cardName = obj.optString(%22class%22).split(%22%5C%5C.%22);%0A       
     
@@ -1537,263 +1537,512 @@
     
-%7D
  ca
-tch (ClassNotFoundException %7C NoSuchMethodException %7C SecurityException %7C InvocationTargetException %7C InstantiationException %7C IllegalAccessException %7C IllegalArgumentException e2) %7B%0A                throw new HSInvalidCardException(%22Unknown card: %22 + 
+rdCache.put(cardName%5BcardName.length - 1%5D.trim(), obj.optString(%22class%22));%0A                %7D%0A            %7D%0A        %7D%0A    %7D%0A%0A    public static Card getCard(String cardName) throws HSInvalidCardException %7B%0A        if (cardCache == null)%0A            loadCardData();%0A        String cleanedString = cardName.trim();%0A        if (cardCache == null)%0A            throw new HSInvalidCardException(%22Unable to open implemented_cards.json%22);%0A%0A        try %7B%0A            Class%3C?%3E clazz = Class.forName(cardCache.get(
 clea
@@ -2043,32 +2043,33 @@
 t(cleanedString)
+)
 ;%0A            %7D%0A
@@ -2058,33 +2058,158 @@
 ));%0A            
-%7D
+Constructor%3C?%3E ctor = clazz.getConstructor();%0A            Object object = ctor.newInstance();%0A            return (Card)object;
 %0A        %7D catch
@@ -2214,19 +2214,20 @@
 ch (
-NoSuchMetho
+ClassNotFoun
 dExc
@@ -2239,16 +2239,20 @@
 n %7C 
-Security
+NoSuchMethod
 Exce
@@ -2339,35 +2339,8 @@
 ion 
-%7C IllegalArgumentException 
 e) %7B

fix CardFactory