package com.fundynamic.d2tm.game.entities;


import com.fundynamic.d2tm.game.entities.structures.Structure;
import com.fundynamic.d2tm.game.entities.units.Unit;
import com.fundynamic.d2tm.game.map.Map;
import com.fundynamic.d2tm.math.Vector2D;
import org.newdawn.slick.Image;
import org.newdawn.slick.SlickException;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;

public class EntityRepository {

    public static int TRIKE = 0;
    public static int QUAD = 1;

    public static int CONSTRUCTION_YARD = 0;
    public static int REFINERY = 1;

    private final Map map;

    private HashMap<String, EntityData> entitiesData;

    private Set<Entity> entities;

    public EntityRepository(Map map) throws SlickException {
        this(map, new HashMap<String, EntityData>());

        // TODO: read this data from an external (XML/JSON/YML/INI) file
        createUnit(QUAD, "units/quad.png", 32, 32);
        createUnit(TRIKE, "units/trike.png", 28, 26);
        createStructure(CONSTRUCTION_YARD, "structures/2x2_constyard.png", 64, 64);
        createStructure(REFINERY, "structures/3x2_refinery.png", 96, 64);
    }

    public EntityRepository(Map map, HashMap<String, EntityData> entitiesData) throws SlickException {
        this.map = map;
        this.entitiesData = entitiesData;
        this.entities = new HashSet<>();
    }

    public void placeUnitOnMap(Vector2D topLeft, int id) {
        placeOnMap(topLeft, EntityType.UNIT, id);
    }

    public void placeStructureOnMap(Vector2D topLeft, int id) {
        placeOnMap(topLeft, EntityType.STRUCTURE, id);
    }

    public void placeOnMap(Vector2D topLeft, EntityType entityType, int id) {
        EntityData entityData = getEntityData(entityType, id);
        System.out.println("Placing " + entityData + " on map at " + topLeft);
        switch (entityType) {
            case STRUCTURE:
                entities.add(map.placeStructure(new Structure(topLeft, entityData.image, entityData.width, entityData.height)));
                break;
            case UNIT:
                entities.add(map.placeUnit(new Unit(topLeft, entityData.image, entityData.width, entityData.height)));
                break;
        }
    }

    public void createUnit(int id, String pathToImage, int widthInPixels, int heightInPixels) throws SlickException {
        if (tryGetEntityData(EntityType.UNIT, id)) {
            throw new IllegalArgumentException("Entity of type UNIT already exists with id " + id + ". Known entities are:\n" + entitiesData);
        }
        EntityData entityData = createData(pathToImage, widthInPixels, heightInPixels);
        entityData.type = EntityType.UNIT;
        entitiesData.put(constructKey(EntityType.UNIT, id), entityData);
    }

    public void createStructure(int id, String pathToImage, int widthInPixels, int heightInPixels) throws SlickException {
        if (tryGetEntityData(EntityType.STRUCTURE, id)) {
            throw new IllegalArgumentException("Entity of type STRUCTURE already exists with id " + id + ". Known entities are:\n" + entitiesData);
        }
        EntityData entityData = createData(pathToImage, widthInPixels, heightInPixels);
        entityData.type = EntityType.STRUCTURE;
        entitiesData.put(constructKey(EntityType.STRUCTURE, id), entityData);
    }

    private EntityData createData(String pathToImage, int widthInPixels, int heightInPixels) throws SlickException {
        EntityData entityData = new EntityData();
        entityData.image = loadImage(pathToImage);
        entityData.width = widthInPixels;
        entityData.height = heightInPixels;
        return entityData;
    }

    protected Image loadImage(String pathToImage) throws SlickException {
        return new Image(pathToImage);
    }

    protected EntityData getEntityData(EntityType entityType, int id) {
        EntityData entityData = entitiesData.get(constructKey(entityType, id));
        if (entityData == null) throw new EntityNotFoundException("Entity not found for entityType " + entityType + " and ID " + id + ". Known entities are:\n" + entitiesData);
        return entityData;
    }

    private boolean tryGetEntityData(EntityType entityType, int id) {
        try {
            getEntityData(entityType, id);
            return true;
        } catch (EntityNotFoundException e) {
            return false;
        }
    }

    public String constructKey(EntityType entityType, int id) {
        return entityType.toString() + "-" + id;
    }

    public Set<Entity> getEntities() {
        return entities;
    }

    public enum EntityType {
        STRUCTURE, UNIT
    }

    public class EntityData {
        public EntityType type;
        public Image image;
        public int width;
        public int height;

        @Override
        public String toString() {
            return "EntityData{" +
                    "type=" + type +
                    ", image=" + image +
                    ", width=" + width +
                    ", height=" + height +
                    '}';
        }
    }
}

@@ -2342,37 +2342,77 @@
         
-if (tryGetEntityData(
+createEntity(id, pathToImage, widthInPixels, heightInPixels, 
 EntityTy
@@ -2422,371 +2422,230 @@
 UNIT
-, id)) %7B
+);
 %0A    
-   
+%7D%0A%0A
     
- throw new IllegalArgumentException(%22Entity of type UNIT already exists
+public void createStructure(int id, String pathToImage, int
  wi
+d
 th
- id %22 + id + %22. Known entities are:%5Cn%22 + entitiesData);%0A        %7D%0A        EntityData entityData = createData(pathToImage, widthInPixels, heightInPixels);%0A        entityData.type = EntityType.UNIT;%0A        entitiesData.put(constructKey(EntityType.UNIT, id), entityData
+InPixels, int heightInPixels) throws SlickException %7B%0A        createEntity(id, pathToImage, widthInPixels, heightInPixels, EntityType.STRUCTURE
 );%0A 
@@ -2647,37 +2647,38 @@
 E);%0A    %7D%0A%0A    p
-ublic
+rivate
  void createStru
@@ -2669,33 +2669,30 @@
  void create
-Structure
+Entity
 (int id, Str
@@ -2737,32 +2737,55 @@
 t heightInPixels
+, EntityType entityType
 ) throws SlickEx
@@ -2815,33 +2815,33 @@
 ryGetEntityData(
-E
+e
 ntityType.STRUCT
@@ -2829,34 +2829,24 @@
 a(entityType
-.STRUCTURE
 , id)) %7B%0A   
@@ -2905,25 +2905,34 @@
 of type 
-STRUCTURE
+%22 + entityType + %22
  already
@@ -3013,346 +3013,8 @@
   %7D%0A
-        EntityData entityData = createData(pathToImage, widthInPixels, heightInPixels);%0A        entityData.type = EntityType.STRUCTURE;%0A        entitiesData.put(constructKey(EntityType.STRUCTURE, id), entityData);%0A    %7D%0A%0A    private EntityData createData(String pathToImage, int widthInPixels, int heightInPixels) throws SlickException %7B%0A
     
@@ -3196,39 +3196,32 @@
 Pixels;%0A        
-return 
 entityData;%0A    
@@ -3206,32 +3206,118 @@
       entityData
+.type = entityType;%0A        entitiesData.put(constructKey(entityType, id), entityData)
 ;%0A    %7D%0A%0A    pro

refactor duplicate concept into one