package net.robertboehm.ld22;

import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;

import org.newdawn.slick.Color;
import org.newdawn.slick.GameContainer;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.Input;
import org.newdawn.slick.SlickException;
import org.newdawn.slick.geom.Rectangle;
import org.newdawn.slick.geom.Shape;
import org.newdawn.slick.state.BasicGameState;
import org.newdawn.slick.state.StateBasedGame;

public abstract class IngameState extends BasicGameState implements
		IEnvironment {

	public static final String ASSET_PLAYER = "/assets/player.png";
	public static final String ASSET_MAPFORMAT = "/maps/intro.dat";

	public Player player;
	private MapRenderer mapRenderer;
	private GameMap map;
	private final int spawnX, spawnY;
	private final Map<String, NPC> npcs = new HashMap<String, NPC>();

	public IngameState() {
		this(null, 320, 240);
	}

	public IngameState(GameMap map, int spawnX, int spawnY) {
		this.map = map;
		this.spawnX = spawnX;
		this.spawnY = spawnY;
	}
	
	public void addNpc(String id, NPC npc) {
		synchronized(npcs) {
			npcs.put(id, npc);
		}
	}
	
	public NPC getNpc(String id) {
		synchronized(npcs) {
			return npcs.get(id);
		}
	}
	
	public void deleteNpc(String id) {
		synchronized(npcs) {
			npcs.remove(id);
		}
	}

	public void enterMap(GameMap map, float x, float y) {
		this.map = map;
		this.mapRenderer.setMap(map);
		this.player.setPosition(x, y);
		
		GameScript script = new GameScript(AreYouStillThere.getInstance(), "mapenter_" + map.name, this);
		script.start();
	}

	public void enterMap(GameMap map, int x, int y) {
		this.map = map;
		this.mapRenderer.setMap(map);
		this.player.setPosition(x, y);
		
		GameScript script = new GameScript(AreYouStillThere.getInstance(), "mapenter_" + map.name, this);
		script.start();
	}

	public GameMap getCurrentMap() {
		return map;
	}

	@Override
	public void init(GameContainer container, StateBasedGame game)
			throws SlickException {
		mapRenderer = new MapRenderer(map);

		player = new Player(this);
		player.setPosition(spawnX, spawnY);
	}

	public Rectangle getMapBoundings() {
		return new Rectangle(0, 0, this.getCurrentMap().width
				* map.tileset.tileWidth, this.getCurrentMap().height
				* map.tileset.tileHeight);
	}

	@Override
	public void render(GameContainer container, StateBasedGame game, Graphics g)
			throws SlickException {
		g.clear();
		g.setColor(new Color(getGravity() / 1800f * 0.05f, 0f,
				getFriction() / 0.2f * 0.03f));
		g.fillRect(0, 0, container.getWidth(), container.getHeight());
		mapRenderer.draw(0, 0);
		synchronized (npcs) {
			for (Entry<String, NPC> npc : npcs.entrySet()) {
				npc.getValue().draw(0, 0);
			}
		}
		player.draw(0, 0);
		if(AreYouStillThere.showEnding)
			GameAssets.getImage("ending").draw(0, 0);
	}

	@Override
	public void update(GameContainer container, StateBasedGame game, int delta)
			throws SlickException {
		if (AreYouStillThere.movementAllowed
				&& (container.getInput().isKeyDown(Input.KEY_A)
				^ container.getInput().isKeyDown(Input.KEY_D))) {
			player.setMode(container.getInput().isKeyDown(Input.KEY_D) ? Player.MOVING_RIGHT
					: Player.MOVING_LEFT);
			player.forceX(650f
					* (container.getInput().isKeyDown(Input.KEY_D) ? 1 : -1)
					* (player.isStanding() ? 1.0f : 0.5f) * (delta / 1000f));
		} else {
			player.setMode(Player.MOVING_NONE);
			player.multiplyX(0.8f);
		}
		if (AreYouStillThere.movementAllowed
				&& container.getInput().isKeyDown(Input.KEY_W)
				&& player.isStanding()) {
			player.forceY(-600f);
			player.jump();
		}
		
		player.update(delta / 1000.0f);
		
		synchronized (npcs) {
			for (Entry<String, NPC> npc : npcs.entrySet()) {
				npc.getValue().update(delta / 1000f);
			}
		}
	}

	@Override
	public boolean intersects(Shape s) {
		return map != null && map.intersects(s);
	}

	@Override
	public float getGravity() {
		return map == null ? DEFAULT_GRAVITY : map.getGravity();
	}

	@Override
	public float getFriction() {
		return map == null ? DEFAULT_FRICTION : map.getFriction();
	}

}
