#ifndef MAP_H
#define MAP_H

#include <types.h>
#include "GameState.h"
#include "GameTypes.h"
#include "Enemy.h"
#include "Object.h"
#include "MapManager.h"
#include "sprites/InteractableSprites.h"
#include "sprites/ItemSprites.h"
#include "sprites/TileSprites.h"
#include "sprites/WaterSprites.h"

// (x,y) to cell (u8) in map cells array.
#define MAPA(x, y) mapCell(x, y, currentRoomX, currentRoomY)

// The size of the back buffer.
#define BACKBUFFER_SIZE 256

// The default width of the back buffer (two cells wide).
#define BACKBUFFER_WIDTH 8

// The default height of the back buffer (two cells tall).
#define BACKBUFFER_HEIGHT 32

// The map grid.
extern u8 mapCells[MAP_CELL_COUNT];

// Determine when a map redraw should happen.
extern u8 mapRedraw;

// The map index of the current map in the maps array.
extern u8 currentMap;

// The objective type applied to the current map.
extern u8 mapObjective;

// The number of objective actions remaining to complete the level.
extern u8 objectiveActionCount;

// The number of pipes the player is carrying when objective type is collect and place pipes.
extern u8 pipeCount;

// The back buffer where tiles and actors are combined before drawing.
extern u8 backbuffer[BACKBUFFER_SIZE];

// The actual width of the back buffer where tiles and actors are combined before drawing.
extern u8 backbufferWidth;

// Initialises the map grid.
void initMap();

// Draws the contents of the map on screen.
void drawMap();

// Retrieves a pointer to a graphic from a cell x,y position.
u8* graphicFromCellPosition(u8 cellX, u8 cellY);

// Retrieves a pointer to a graphic from a given cell value.
u8* graphicFromCell(u8 cell);

// Draws the content of a cell from the map on screen.
void drawCell(u8 x, u8 y, u8 cell);

// Draws the cell at the specified position in the map on screen.
void drawCellAtPosition(u8 x, u8 y);

// Draws the cell at the specified position in the map on screen (x and y are bound checked).
void drawCellAtPositionSafe(u8 x, u8 y);

// Retrieve the index in the mapCell array for the given position (x,y) and room (x,y).
u16 mapCellPosition(u8 x, u8 y, u8 roomX, u8 roomY);

// Retrieve the cell from the mapCell array for the given position (x,y) and room (x,y).
u8 mapCell(u8 x, u8 y, u8 roomX, u8 roomY);

// Updates the cell in the mapCell array at the given position (x,y) and room (x,y).
void updateMapCell(u8 x, u8 y, u8 roomX, u8 roomY, u8 cell);

// Add the specified sprite to the backbuffer, dimensions are assumed to be the default TILE_WIDTH_BYTES * TILE_HEIGHT.
void addSpriteToBackbuffer(u8 x, u8 y, u8* sprite);

// Draws the content of the backbuffer at the specified location on the screen.
void drawBackbuffer(u8 x, u8 y);

// Populates the backbuffer with 4 cells from the map at the specified position.
void populateBackbufferFromMap(u8 cellX, u8 cellY);

// Indicates whether the specified cell in the current room contains a spike.
u8 cellContainsSpike(u8 x, u8 y);

// Marks all enemies for redrawing on the screen.
void markEnemiesForRedraw();

#endif