package engine;

import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import javafx.scene.input.KeyEvent;
import util.reflection.Reflection;
import authoringEnvironment.GameManager;
import authoringEnvironment.InstanceManager;
import engine.element.Game;
import engine.element.sprites.Enemy;
import engine.element.sprites.Projectile;
import engine.element.sprites.Sprite;
import engine.element.sprites.Tower;


/**
 * This class contains the main game loop which runs the game and updates the Scene. The constructor
 * is given an ObservableList of nodes in the scene, as well as a list of the towers, enemies and
 * map created by the authoring environment. A new version of this class must be created by the
 * player whenever a new game is loaded. The player calls this class when it loads a new game, and
 * this class then runs the game.
 * 
 * @author Qian Wang
 */

public class GameController {
    /**
     * Holds an instance of an entire game
     */
    Game myGame;
    /**
     * Holds a map of a part name to the package to use to reflect
     */
    Map<String, String> myPartTypeToPackage = new HashMap<>();

    public GameController (String filepath) {
        myGame = new Game();
        loadGame(filepath, myGame);
        fillPackageMap();
    }

    private void fillPackageMap () {
        myPartTypeToPackage.put("Tower", "engine.element.sprites.Tower");
        myPartTypeToPackage.put("Enemy", "engine.element.sprites.Enemy");
        myPartTypeToPackage.put("Projectile", "engine.element.sprites.Projectile");
        myPartTypeToPackage.put("GridCell", "engine.element.sprites.GridCell");
        myPartTypeToPackage.put("Game", "engine.element.Game");
        myPartTypeToPackage.put("Level", "engine.element.Level");
        myPartTypeToPackage.put("Round", "engine.element.Round");
        myPartTypeToPackage.put("Wave", "engine.element.Wave");
        myPartTypeToPackage.put("Layout", "engine.element.Layout");
    }

    /**
     * Given a location of a game file, the {@link GameManager#loadGame(String)} method if called,
     * which generates a map of objects names to the parameters which those objects should contain.
     * Those objects are then instantiated and their parameter lists are set.
     * 
     * @param filepath String of location of the game file
     */
    public void loadGame (String filepath, Game game) {
        Collection<Tower> towerObjects = new HashSet<Tower>();
        Collection<Enemy> enemyObjects = new HashSet<Enemy>();
        Collection<Projectile> projectileObjects = new HashSet<Projectile>();
        List<Map<String, Object>> allDataObjects = GameManager.loadGame(filepath);

        for (Map<String, Object> obj : allDataObjects) {
            String partType = (String) obj.get(InstanceManager.partTypeKey);
            String packageLocation = myPartTypeToPackage.get(partType);
            Sprite currentObject = (Sprite) Reflection.createInstance(packageLocation);
            currentObject.setParameterMap(obj);
            
        }

    }

    // Will handle hotkeys
    public void handleKeyInput (KeyEvent k) {

    }

}

@@ -969,16 +969,73 @@
 oller %7B%0A
+    private static final String PARAMETER_GUID = %22GUID%22;%0A
     /**%0A
@@ -1389,24 +1389,77 @@
 p();%0A    %7D%0A%0A
+    // TODO replace this with loading from data file%0A
     private 
@@ -2545,32 +2545,35 @@
  game) %7B%0A       
+ //
  Collection%3CTowe
@@ -2611,32 +2611,35 @@
 ower%3E();%0A       
+ //
  Collection%3CEnem
@@ -2685,16 +2685,19 @@
 %0A       
+ //
  Collect
@@ -2755,24 +2755,320 @@
 jectile%3E();%0A
+        Map%3CString, Map%3CString, Map%3CString, Object%3E%3E%3E myObjects = new HashMap%3C%3E();%0A        for (String s : myPartTypeToPackage.keySet()) %7B%0A            myObjects.put(s, new HashMap%3C%3E());%0A        %7D%0A%0A        // Get list of parameters maps for all objects%0A        // TODO change to collection or set%0A
         List
@@ -3135,24 +3135,60 @@
 filepath);%0A%0A
+        // Organize parameters maps%0A
         for 
@@ -3312,32 +3312,35 @@
 ey);%0A           
+ //
  String packageL
@@ -3395,16 +3395,19 @@
         
+ //
  Sprite 
@@ -3486,16 +3486,19 @@
         
+ //
  current
@@ -3538,27 +3538,361 @@
         
-%0A        %7D%0A
+myObjects.get(partType).put((String) obj.get(PARAMETER_GUID), obj);%0A        %7D%0A%0A        // Send right sets of objects to the right objects%0A        myGame.addTowers(myObjects.get(%22Tower%22));%0A        myGame.addTowers(myObjects.get(%22Enemy%22));%0A        myGame.addTowers(myObjects.get(%22Projectile%22));%0A        myGame.addTowers(myObjects.get(%22GridCell%22));
 %0A    %7D%0A%0A

Update GameController to load in sprites