/*
 * Map
 * 
 * Draw and move a tile map in a canvas.
 * Provide path and teleporters positions for the player.
 */
 
/**
 * Constructor.
 */
function Map()
{
	//Constants
	this.SPRITES_FOLDER = 'game/images/sprites/gif';
	this.SPRITE_SIZE = 32;
	this.WATER_SPRITE = 45;
	this.PLAYER_AREA = 4*this.SPRITE_SIZE; // Allowed distance between the map center and the player
	this.PRECOMPUTED_MAP_PATH = 'game/images/tilemap.png';

	//Initialize attributes
	this.sprites = [];
	this.canvas = null;
	this.mapdata = null;
	this.mapWidth = 0; //number of sprites per line
	this.mapHeight = 0; //number of sprites per column
	this.paddingV = 0; //vertical padding: space on top and on the bottom of the map which must be filled with water sprite.
	this.paddingH = 0; //horizontal padding: space in the left and right side of the map which must be filled with water sprite.
}

/**
 * Load the tiles and draw them.
 *
 * @param gameContainer html element which will contain the canvas.
 * @param callbackReady callback function called when the map is loaded.
 */
Map.prototype.load = function(gameContainer, callbackReady)
{
	//Load the map data
	var map = this;
	$.getJSON("game/map_data.js",function(mapdata)
	{
		map.mapdata = mapdata;
		
		//Load the sprites
		map.loadSprites(mapdata.sprites, function()
		{
			//Create the canvas
			map.mapHeight = mapdata.tilemap.length;
			map.mapWidth = (map.mapHeight == 0 ? 0 : mapdata.tilemap[0].length);
			map.paddingV = Math.ceil($(gameContainer).height()/(2*map.SPRITE_SIZE));// The empty space around the map
			map.paddingH = Math.ceil($(gameContainer).width()/(2*map.SPRITE_SIZE)); // must be filled with water sprites.
			
			$(gameContainer).css('overflow', 'hidden');
			$(gameContainer).append('<canvas id="map" width="'+(map.mapWidth+2*map.paddingH)*map.SPRITE_SIZE+
													 '" height="'+(map.mapHeight+2*map.paddingV)*map.SPRITE_SIZE+'"></canvas>');
			map.canvas = $("canvas#map").get(0);
			
			//Draw the sprites
			map.drawSprites(mapdata.tilemap);
			
			//Call the callback function
			callbackReady();
		});
	});
}

/**
 * Load the tiles.
 * @param sprites sprite list
 * @callback function called when all the images are downloaded
 */
Map.prototype.loadSprites = function(sprites, callback)
{
	this.sprites = [];
	var nbSpritesToLoad = sprites.length;
	
	for(index in sprites)
	{
		this.sprites[index] = new Image();
		this.sprites[index].onload = function()
		{
			nbSpritesToLoad--;
			if(nbSpritesToLoad == 0) callback();
		};
		this.sprites[index].src = this.SPRITES_FOLDER+'/'+sprites[index];
	}
}

/**
 * Display the tilemap.
 * @param tilemap array of sprite index
 */
Map.prototype.drawSprites = function(tilemap)
{
	//Check if the browser support canvas
	if (document.createElement('canvas').getContext)
	{
		var ctx = this.canvas.getContext('2d');
		
		//Fill the padding space with water
		for(var x = 0; x < 2*this.paddingH+this.mapWidth; x++)
		{
			for(var y = 0; y < 2*this.paddingV+this.mapHeight; y++)
			{
				if(x < this.paddingH || x >= this.paddingH+this.mapWidth || y < this.paddingV || y >= this.paddingV+this.mapHeight)
					ctx.drawImage(this.sprites[this.WATER_SPRITE],
								  x*this.SPRITE_SIZE,
								  y*this.SPRITE_SIZE,
								  this.SPRITE_SIZE,
								  this.SPRITE_SIZE);
			}
		}
		
		//Draw the map in the center
		for(linesIndex in tilemap)
		{
			var line = tilemap[linesIndex];
			
			for(tileIndex in line)
			{
				var tile = line[tileIndex];
				var x = Number(tileIndex)+this.paddingH;
				var y = Number(linesIndex)+this.paddingV;
				
				ctx.drawImage(this.sprites[tile],x*this.SPRITE_SIZE,y*this.SPRITE_SIZE, this.SPRITE_SIZE, this.SPRITE_SIZE);
			}
		}
	}
	else
	{
		//The browser doesn't support <canvas> (Like IE8).
		//Replace this tag by a div and load every sprite in an image tag.
		//
		
		//Replace the canvas by a div with the same attributes
		var id = $(this.canvas).attr('id');
		var width = $(this.canvas).attr('width');
		var height = $(this.canvas).attr('height');
		var canvasParent = $(this.canvas).parent();
		$(this.canvas).remove();
		canvasParent.append('<div id="'+id+'"></div>');
		var divcanvas = $('div#'+id);
		divcanvas.width(width);
		divcanvas.height(height);
		this.canvas = divcanvas.get(0);
		
		//Set the background
		divcanvas.css('background', 'url('+this.sprites[this.WATER_SPRITE].src+')');
		
		//Set the pre-computed tilemap
		divcanvas.append('<img id="precomputed_map" alt="tilemap" src="'+this.PRECOMPUTED_MAP_PATH+'"/>');
		divcanvas.children('#precomputed_map').css('position', 'relative');
		divcanvas.children('#precomputed_map').css('top', this.paddingV*this.SPRITE_SIZE);
		divcanvas.children('#precomputed_map').css('left', this.paddingH*this.SPRITE_SIZE);
	}
}

/**
 * Get the map paths.
 *
 * @return map paths
 */
Map.prototype.getPaths = function()
{
	return this.mapdata.paths;
}

/**
 * Get the map teleporters.
 *
 * @return map teleporters
 */
Map.prototype.getTeleporters = function()
{
	return this.mapdata.teleporters;
}

/**
 * Get the map stations.
 *
 * @return map stations
 */
Map.prototype.getStations = function()
{
	return this.mapdata.stations;
}

/**
 * Move the map in order to show the player.
 *
 * @param player to show
 */
Map.prototype.showPlayer = function(player)
{
	var mapCenterPosition = this.getCenterPosition();
	
	//Compute the new position of the map center
	if(mapCenterPosition.x+this.PLAYER_AREA-this.SPRITE_SIZE < player.position.x)
		mapCenterPosition.x = player.position.x-this.PLAYER_AREA+this.SPRITE_SIZE;
	if(mapCenterPosition.y+this.PLAYER_AREA-this.SPRITE_SIZE < player.position.y)
		mapCenterPosition.y = player.position.y-this.PLAYER_AREA+this.SPRITE_SIZE;
	if(mapCenterPosition.x-this.PLAYER_AREA > player.position.x)
		mapCenterPosition.x = player.position.x+this.PLAYER_AREA;
	if(mapCenterPosition.y-this.PLAYER_AREA > player.position.y)
		mapCenterPosition.y = player.position.y+this.PLAYER_AREA;
	
	//Move the map
	this.setCenterPosition(mapCenterPosition);
}

/**
 * Move the map in order to show the player in the center.
 *
 * @param player to show
 */
Map.prototype.showPlayerInTheCenter = function(player)
{
	this.setCenterPosition(player.position);
}

/**
 * Get the map center position. The origin is the first sprite of the tilemap.
 *
 * @return an point object {x,y}
 */
Map.prototype.getCenterPosition = function()
{
	var top = $("#game").scrollTop()-this.paddingV*this.SPRITE_SIZE+$("#game").height()/2;
	var left = $("#game").scrollLeft()-this.paddingH*this.SPRITE_SIZE+$("#game").width()/2;
	
	return {"x":left, "y":top};
}

/**
 * Set the map center position. The origin is the first sprite of the tilemap.
 *
 * @position center position
 */
Map.prototype.setCenterPosition = function(position)
{
	$("#game").scrollTop(position.y+this.paddingV*this.SPRITE_SIZE-$("#game").height()/2);
	$("#game").scrollLeft(position.x+this.paddingH*this.SPRITE_SIZE-$("#game").width()/2);
}
