package holo.bolt.states;

import holo.bolt.BoltMain;
import holo.bolt.entity.EntityPlayer;
import holo.bolt.render.Render;
import holo.bolt.world.World;
import holo.bolt.world.map.tile.InteractableTile;

import java.util.ArrayList;

import org.newdawn.slick.Font;
import org.newdawn.slick.GameContainer;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.Image;
import org.newdawn.slick.Input;
import org.newdawn.slick.SlickException;
import org.newdawn.slick.geom.Vector2f;
import org.newdawn.slick.state.BasicGameState;
import org.newdawn.slick.state.StateBasedGame;

public class GameState extends BasicGameState
{
	public World world;
	public ArrayList<Render> renderList;
	public EntityPlayer player;
	public int[] cameraPos;
	public Image heart;
	public Image heart2;
	public boolean canInteract;
	public StateBasedGame game;
	public boolean hasInit = false;
	public int levelScore;
	public int score;
	
	@Override
	public void init(GameContainer gc, StateBasedGame game)
			throws SlickException
	{
		if(!hasInit)
		{
			this.game = game;
			renderList = new ArrayList<Render>();
			cameraPos = new int[2];
			initWorld(false);
			heart = new Image("res/Heart.png");
			heart2 = new Image("res/DeadHeart.png");
			canInteract = false;
			this.hasInit = true;
			score = 0;
			levelScore = 0;
		}
	}
	
	public void initPlayer(EntityPlayer p)
	{
		player = p;
		renderList.add(p.getRender());
	}
	
	@Override
	public void render(GameContainer gc, StateBasedGame game, Graphics g)
			throws SlickException
	{
		Font f = gc.getDefaultFont();
		
		g.clear();
		float cx = -cameraPos[0] + gc.getWidth() / 2;
		float cy = -cameraPos[1] + gc.getHeight()/2;
		g.translate(cx, cy);
		for(Render render : renderList)
		{
			render.draw(gc, game, g, cameraPos);
		}
		
		player.getRender().doDraw(gc, game, g, cameraPos);
		
		g.translate(-cx, -cy);
		
		for(int i = 0; i < player.maxHealth(); ++i)
		{
			if(i < player.health)
				heart.draw(gc.getWidth() - 30 * i, 6.0F);
			else
				heart2.draw(gc.getWidth() - 30 * i, 6.0F);
		}
		
		f.drawString(0, 0, "Score: " + score);
		
		int x = gc.getWidth() / 2;
		int y = gc.getHeight() / 9;
		if(canInteract())
		{
			InteractableTile t = world.getInteractable(player);
			String s = "Press e to: " + t.getDescription();
			f.drawString(x - f.getWidth(s) / 2, y, s);
			y += f.getLineHeight();
			int n = t.uses() - t.used();
			if(n == 1)
				s = n + " use remaining.";
			else
				s = n + " uses ramaining.";
			f.drawString(x - f.getWidth(s) / 2, y, s);
		}
	}

	@Override
	public void update(GameContainer gc, StateBasedGame game, int delta)
			throws SlickException
	{
		world.onUpdate(delta);
		updateCamera(gc);
		updatePlayer(gc, delta);
	}
	
	public void keyPressed(int key, char c) 
	{
		if(key == Input.KEY_E)
		{
			if(canInteract())
			{
				world.getInteractable(player).performUse(player);
			}
		}
	}
	
	public void mouseMoved(int oldx, int oldy, int x, int y) 
	{
		player.lookat(new float[] {x  - BoltMain.ScreenWidth / 2, y - BoltMain.ScreenHeight/2});
	}
	
	public void mousePressed(int button, int x, int y) 
	{
		if(button == Input.MOUSE_LEFT_BUTTON)
			player.attack();
		else if (button == Input.MOUSE_RIGHT_BUTTON)
			player.shoot();
	}

	@Override
	public int getID()
	{
		return BoltMain.GAME_ID;
	}
	
	public void initWorld(boolean load)
	{
		world = new World(this, load);
	}
	
	public void initLevel(int level, int startScore)
	{
		this.score = startScore;
		world.loadLevel(this, world.levels[level], level);
	}
	
	public void reset()
	{
		this.hasInit = false;
	}
	
	public void updatePlayer(GameContainer gc, int delta)
	{
		Vector2f vel = new Vector2f(0,0);
		if (gc.getInput().isKeyDown(Input.KEY_W) || gc.getInput().isKeyDown(Input.KEY_UP))
			vel.y -= 0.01;
		if (gc.getInput().isKeyDown(Input.KEY_S) || gc.getInput().isKeyDown(Input.KEY_DOWN))
			vel.y += 0.01;
		if (gc.getInput().isKeyDown(Input.KEY_D) || gc.getInput().isKeyDown(Input.KEY_RIGHT))
			vel.x += 0.01;
		if (gc.getInput().isKeyDown(Input.KEY_A) || gc.getInput().isKeyDown(Input.KEY_LEFT))
			vel.x -= 0.01;
		player.addVelocity(vel);
		
		if(world.canInteract(player))
			canInteract = true;
		else
			canInteract = false;
	}
	
	public void updateCamera(GameContainer gc)
	{
		cameraPos[0] = (int)player.pos[0];
		cameraPos[1] = (int)player.pos[1];
	}
	
	public void leave(GameContainer gc, StateBasedGame game) throws SlickException 
	{
		super.leave(gc, game);
		((GameOverState)game.getState(BoltMain.GAME_OVER_ID)).updateStats(world.currentLevel, score, levelScore);
		
	}
	
	public boolean canInteract()
	{
		if(world.getInteractable(player) != null)
		{
			return true;
		}
		return false;
	}
}
