package game;

import MapDesc.TileDesc;
import MapDesc;
import game.mobs.Ghost;
import game.mobs.Mob;
import game.obj.Coin;
import game.obj.GhostSpawn;
import game.tiles.DestructableTile;
import haxe.Json;
import openfl.Assets;
import openfl.display.BitmapData;
import openfl.geom.Point;
import raycaster.MapInterface;

class GameMap implements MapInterface {
	public var defaultWallTexture:BitmapData;
	public var defaultFloorTexture:BitmapData;
	public var defaultCeilTexture:BitmapData;
	public var cameraPosition:Point;

	public var mapWidth:Int;
	public var mapHeight:Int;

	public var tiles:Array<Array<MapTile>>;

	public var mobs:Array<Mob> = [];

	public var sprites:Array<GameSprite> = [];

	public var numCoins:Int = 0;
	public var collectedCoins:Int = 0;

	private function new() {}

	public function getSize():MapSize {
		return {
			mapWidth: mapWidth,
			mapHeight: mapHeight
		};
	}

	public function getTile(cellX:Int, cellY:Int):MapTileDesc {
		if (cellX >= 0 && cellX < mapWidth && cellY >= 0 && cellY < mapHeight) {
			var tile = tiles[cellX][cellY];

			if (tile != null)
				return {
					wallTexture: tile.wallTexture,
					floorTexture: tile.floorTexture,
					ceilTexture: tile.ceilTexture,
					collision: tile.collision
				};
		}

		return null;
	}

	public static function fromJson(json:String):GameMap {
		var map:MapDesc = Json.parse(json);

		var loadedMap = new GameMap();

		loadedMap.mapWidth = map.mapWidth;
		loadedMap.mapHeight = map.mapHeight;

		loadedMap.tiles = [
			for (tx in 0...map.tiles.length) [
				for (ty in 0...map.tiles[tx].length)
					((tileDesc:TileDesc) -> {
						var newtile:MapTile = (tileDesc.wallTextureID != null
							&& map.textures[tileDesc.wallTextureID] == 'bricks.png') ? new DestructableTile() : new MapTile();
						newtile.floorTexture = tileDesc.floorTextureID != null ? Assets.getBitmapData('assets/textures/'
							+ map.textures[tileDesc.floorTextureID]) : null;
						newtile.wallTexture = tileDesc.wallTextureID != null ? Assets.getBitmapData('assets/textures/' +
							map.textures[tileDesc.wallTextureID]) : null;
						newtile.ceilTexture = tileDesc.ceilTextureID != null ? Assets.getBitmapData('assets/textures/' +
							map.textures[tileDesc.ceilTextureID]) : null;
						newtile.collision = tileDesc.collision;
						newtile.cell = {cellX: tx, cellY: ty};
						return newtile;
					})
				(map.tiles[tx][ty])
			]

		];

		for (mob in map.mobs) {
			var mobSprite:Mob = null;
			switch (mob.type) {
				case 'player':
					loadedMap.cameraPosition = new Point(mob.x, mob.y);
				case 'ghost':
					mobSprite = new Ghost();
				case 'ghost_spawn':
					var ghostSpawn = new GhostSpawn();
					ghostSpawn.x = mob.x;
					ghostSpawn.y = mob.y;
					loadedMap.sprites.push(ghostSpawn);
				case 'coin':
					var coin = new Coin();
					coin.x = mob.x;
					coin.y = mob.y;
					loadedMap.sprites.push(coin);
					loadedMap.numCoins++;
			}

			if (mobSprite != null) {
				mobSprite.x = mob.x;
				mobSprite.y = mob.y;
				loadedMap.mobs.push(mobSprite);
			}
		}

		if (loadedMap.cameraPosition == null) {
			for (tx in 0...loadedMap.tiles.length) {
				for (ty in 0...loadedMap.tiles[tx].length) {
					if (!loadedMap.tiles[tx][ty].collision) {
						loadedMap.cameraPosition = new Point(tx + 0.5, ty + 0.5);
						break;
					}
				}

				if (loadedMap.cameraPosition != null)
					break;
			}
		}

		return loadedMap;
	}

	public static function emptyRoom(roomWidth:Int, roomHeight:Int):GameMap {
		var room:GameMap = new GameMap();

		room.mapWidth = roomWidth;
		room.mapHeight = roomHeight;

		room.defaultFloorTexture = Assets.getBitmapData('assets/textures/floor.png');
		room.defaultCeilTexture = Assets.getBitmapData('assets/textures/ceiling.png');

		room.tiles = [];

		for (tx in 0...roomWidth) {
			var row:Array<MapTile> = [];
			room.tiles.push(row);
			for (ty in 0...roomHeight) {
				var tile = new MapTile();

				if (tx == 0 || ty == 0 || tx == roomWidth - 1 || ty == roomHeight - 1) {
					tile.collision = true;
					tile.wallTexture = Assets.getBitmapData('assets/textures/bricks.png');
				}

				row.push(tile);
			}
		}

		room.tiles[Std.int(roomWidth / 2)][Std.int(roomHeight / 2)].ceilTexture = Assets.getBitmapData('assets/textures/metal.png');

		return room;
	}
}
