package com.pesets.game;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Random;

import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer.ShapeType;
import com.badlogic.gdx.math.Vector2;
import com.pesets.game.map.MapGenerator;
import com.pesets.game.map.PassageMap;
import com.pesets.game.map.SpawnMap;
import com.pesets.resources.TextureGenerator;

public class Map implements IGameObjectCallback {
	public static final int DefaultMapSize = 40;
	public static final int CellSize = 32;
	
	private PassageMap passage;
	private SpawnMap spawns;
	
	private ArrayList<GameObject> objects = new ArrayList<GameObject>();
	
	private OrthographicCamera camera;
	private Player player;
	
	private ShapeRenderer renderer = new ShapeRenderer();
	private SpriteBatch batch = new SpriteBatch();
	
	private int[] tileMap;
	
	public Map(int seed, int minLevel, int maxLevel)
	{
		camera = new OrthographicCamera();
		camera.setToOrtho(false);
		
		passage = MapGenerator.generatePassageMap(seed, DefaultMapSize, DefaultMapSize);
		spawns = MapGenerator.generateSpawnMap(passage, seed, minLevel, maxLevel);
		
		tileMap = new int[passage.getWidth() * passage.getHeight()];
		
		Random rand = new Random();
		for (int i = 0; i < tileMap.length; i++)
		{
			tileMap[i] = rand.nextInt(2);
			if (!passage.isCanPass(i % passage.getWidth(), i / passage.getWidth()))
				tileMap[i] += 2;	
		}
		
		spawnEnemies();
	}
	
	public void spawnEnemies()
	{
		for (SpawnMap.SpawnPoint spawn : spawns.getSpawns())
		{
			Vector2 pos = passage.getRealCoords(spawn.x, spawn.y);
			Enemy enemy = new Enemy(this, spawn.mobType, spawn.level, pos.x, pos.y);
			objects.add(enemy);
		}
	}

	public void render()
	{
		/*renderer.setProjectionMatrix(camera.combined);
		renderer.begin(ShapeType.FilledRectangle);
		for (int x = 0; x < passage.getWidth(); x++)
		{
			for (int y = 0; y < passage.getHeight(); y++)
			{
				if (passage.isCanPass(x, y))
					renderer.setColor(0.19f, 0.8f, 0.19f, 1);
				else
					renderer.setColor(1, 0, 0, 1);
				renderer.filledRect(x * CellSize, y * CellSize, CellSize, CellSize);
			}
		}
		
		renderer.end();*/
		
		batch.setProjectionMatrix(camera.combined);
		batch.begin();
		for (int x = 0; x < passage.getWidth(); x++)
		{
			for (int y = 0; y < passage.getHeight(); y++)
			{
				batch.draw(TextureGenerator.getInstance().getTile(tileMap[y * passage.getWidth() + x]), x * CellSize, y * CellSize);
			}
		}
		
		Collections.sort(objects, new Comparator<GameObject>() {

			@Override
			public int compare(GameObject o1, GameObject o2) {
				return (int) (o2.y - o1.y);
			}
			
		});
		for (GameObject object : objects)
		{
			//if (player == null || player.dist2(object) > Player.VisionRange * Player.VisionRange) continue;
			object.render(batch);
		}
		
		batch.end();
		
		renderer.setProjectionMatrix(camera.combined);
		renderer.begin(ShapeType.FilledRectangle);
		for (GameObject object : objects)
		{
			if (object.isDead()) continue;
			renderer.setColor(0, 0, 0, 1);
			renderer.filledRect(object.x - object.width / 2 - 1, object.y  + object.height - 11, object.width + 2, 6);
			renderer.setColor(1 - 0.5f * object.getHP() / object.getMaxHP(), object.getHP() / object.getMaxHP(), 0, 1);
			renderer.filledRect(object.x - object.width / 2, object.y  + object.height - 10, object.width * object.getHP() / object.getMaxHP(), 4);
		}
		renderer.end();
	}
	
	public void update(float dt)
	{
		for (GameObject object : objects)
		{
			object.update(dt);
		}
		
		if (player != null)
		{
			float px = player.getX();
			float py = player.getY();
			px = Math.max(px, 512);
			py = Math.max(py, 300);
			px = Math.min(px, passage.getWidth() * CellSize - 512);
			py = Math.min(py, passage.getHeight() * CellSize - 300);
				
			camera.position.set(px, py, 0);
			camera.update();
		}
	}

	public Player getPlayer() {
		return player;
	}

	public void setPlayer(Player player) {
		if (player != null)
		objects.remove(player);
		this.player = player;
		if (player == null) return;
		objects.add(player);
		player.setCallback(this);
		float sx = (spawns.getPlayerPos().x + 0.5f) * CellSize;
		float sy = (spawns.getPlayerPos().y + 0.5f) * CellSize;
		player.setPos(sx, sy);
		player.spawn();
		for (GameObject obj : objects)
		{
			if (obj instanceof Enemy)
				((Enemy) obj).resetTarget();
		}
	}

	@Override
	public ArrayList<GameObject> getObjects(GameObject sender, float radius, Class<? extends GameObject> objectClass) {
		ArrayList<GameObject> result = new ArrayList<GameObject>();
		for (GameObject obj : objects)
		{
			if (obj.equals(sender)) continue;
			if (obj.getClass().equals(objectClass) == false) continue;
			if ((sender.x - obj.x) * (sender.x - obj.x) + (sender.y - obj.y) * (sender.y - obj.y) <=
					radius * radius)
				result.add(obj);
		}
		return result;
	}

	@Override
	public PassageMap getPassage() {
		return passage;
	}
}
