#include ".\gamegrid.h"

GameGrid::GameGrid(Surface *surf, int cols, int rows, int cellwidth, int cellheight)
{
	int a,b;

	COLS=cols;
	ROWS=rows;
	CELLWIDTH=cellwidth;
	CELLHEIGHT=cellheight;
	WorldX(0);
	WorldY(0);
	this->surf=surf;

	// alloca celle
	CELLS=(CELL ***)malloc(sizeof(CELL **) * COLS);
	for (a=0; a < COLS; a++)
		CELLS[a]=(CELL **)malloc(sizeof(CELL *) * ROWS);

	for (a=0; a < COLS; a++) {
		for (b=0; b < ROWS; b++) {
			CELLS[a][b]=new CELL;
			CELLS[a][b]->cellIndex=-1;
		}
	}

	FillGrid(-1);
}

GameGrid::~GameGrid(void)
{
	// libera la griglia allocata
	int a, b;

	for (a=0; a < COLS; a++)
		for (b=0; b < ROWS; b++)
			delete CELLS[a][b];

	for (a=0; a < COLS; a++)
		free(CELLS[a]);

	free(CELLS);
}

void GameGrid::ClearGrid(int index)
{
	int a,b;

	for (a=0; a < COLS; a++)
		for (b=0; b < ROWS; b++)
			CELLS[a][b]->cellIndex=index;
}

bool GameGrid::SetCell(int col, int row, int index)
{
	if (col < COLS && row < ROWS) {
		CELLS[col][row]->cellIndex=index;
		return true;
	}
	return false;
}

int GameGrid::GetCell(int col, int row)
{
	if (col < COLS && row < ROWS)
		return CELLS[col][row]->cellIndex;
	else
		return -1;
}

int GameGrid::WorldX() { return WORLDX; }
int GameGrid::WorldY() { return WORLDY; }
void GameGrid::WorldX(int x) { 
	WORLDX=x; 
	// ricalcola cella X da cui inizia il disegno
	STARTCOL=(int)(WORLDX / CELLWIDTH);
	// ricalcola offset reale cella (between startcol and 0,0)
	COLOFFSET = (int)(WORLDX % CELLWIDTH);
}
void GameGrid::WorldY(int y) { 
	WORLDY=y; 
	// ricalcola cella Y da cui inizia il disegno
	STARTROW=(int)(WORLDY / CELLHEIGHT);
	// ricalcola offset reale cella (between startcol and 0,0)
	ROWOFFSET = (int)(WORLDY % CELLHEIGHT);
}

void GameGrid::_FillGrid(int cellindex, int x1, int y1, int x2, int y2)
{
	int fx1=x1;
	int fy1=y1;
	int fx2=x2;
	int fy2=y2;

	// bound fixes
	if (fx1 < 0 || fx1 > COLS-1) fx1=0;
	if (fy1 < 0 || fy1 > ROWS-1) fy1=0;
	if (fx2 < 0 || fx2 > COLS-1) fx2=0;
	if (fy2 < 0 || fy2 > ROWS-1) fy2=0;

	for (int x=fx1; x <= fx2; x++) 
		for (int y=fy1; y <= fy2; y++)
			CELLS[x][y]->cellIndex=cellindex;
}
void GameGrid::FillGrid(int cellindex, int x1, int y1, int x2, int y2) { _FillGrid(cellindex, x1, y1, x2, y2); }
void GameGrid::FillGrid(int cellindex) { _FillGrid(cellindex, 0, 0, COLS-1, ROWS-1); }

void GameGrid::draw(Display *display, int x, int y, int width, int height)
{
	if (!this->surf)
		return;	// sanity

	int CLIPBOTTOM=y+height;
	int CLIPRIGHT=x+width;
	int CLIPLEFT=x;
	int CLIPTOP=y;

	// salva e setta nuovo clipping
	Rect oldclip=display->GetClipping();
	display->SetClipping(Rect(CLIPLEFT,CLIPTOP,CLIPRIGHT,CLIPBOTTOM));

	// where we must draw current cell
	int startX = x - COLOFFSET;
	int startY = y - ROWOFFSET;


	// draw until when we reach grid limits
	int mx,my,cellindex,strip_X;

	int drawedCol;
	int drawedRow = this->STARTROW;

	my=startY;
	//while (my <= startY+height+this->CELLHEIGHT) {
	while (my <= CLIPBOTTOM) {

		// new line, set current col as first col we must draw!
		drawedCol = this->STARTCOL;


		mx=startX;
		//while (mx<=startX+width+this->CELLWIDTH) {
		while (mx<=CLIPRIGHT) {

			// get current cell index (strip image index)
			if (drawedCol > -1 && drawedCol < COLS && drawedRow > -1 && drawedRow < ROWS) {
				// Take cell index
				cellindex = CELLS[drawedCol][drawedRow]->cellIndex;

				// we draw only cells with positive indexes
				if (cellindex > -1) {
					//where me must take blit on strip?
					strip_X = cellindex * this->CELLWIDTH;

					// draw cell 
					// we will clip correct image from strip
					display->Blit(mx, my, surf, &Rect(strip_X,0,strip_X+this->CELLWIDTH,this->CELLHEIGHT));
				}
			}

			// increment our col number (if we can)
			if (drawedCol < this->COLS) 
				++drawedCol;
			else
				break;	// break for statement if we reached matrix limits

			mx += this->CELLWIDTH;
		}

		// increment our row number (if we can)
		if (drawedRow < this->ROWS-1)
			++drawedRow;
		else
			break;	// break for statement if we reached matrix limits

		my += this->CELLHEIGHT;
	}

	// resetta vecchio clipping
	display->SetClipping(oldclip);
}

