/*
 * controller.c
 *
 *  Created on: Dec 24, 2009
 *      Author: ÓHerman van der MeulenÓ
 */

#include "controller.h"

// in route?
int inRoute = 0;

// route already correct?
int routeCorrect = 0;

// the current pen status (0 = up, 1 = down)
int penStatus = 0;

char* warningText = "";

// keep track of the position of the user placed no go area
Position placedPosition =
{ -1, -1 };

// keep track of the positions (what block is the user in?)
Position lastPosition =
{ 0, 0 };
Position currentPosition =
{ 0, 0 };
Position newPosition =
{ 0, 0 };

// simple vars for blocks[currentPosition.x][currentPosition.y] and blocks[lastPosition.x][lastPosition.y]
int currentBlock, lastBlock;

/*
 * reset the route vars (but not visual)
 */
void resetRoute()
{
	inRoute = 0;
	routeCorrect = 0;
	currentPosition.x = 0;
	currentPosition.y = 0;
}

/*
 * check if the route drawn by the user is correct
 */
void checkCorrectRoute()
{
	routeCorrect = 1;
	int x, y;
	for (x = 1; x <= 9; x++)
	{
		for (y = 1; y <= 6; y++)
		{
			if (blocks[x][y] > 3)
			{
				routeCorrect = 0;
			}
		}
	}
	extendRoute();
	if (routeCorrect)
	{
		stopLoop();
		playWin();
		int tempLevel = ++currentLevel;
		wait((u8) 25);
		currentLevel = 0;
		placedPosition.x = -1;
		placedPosition.y = -1;
		resetField(1);
		wait((u8) 50);
		currentLevel = tempLevel;
		if (currentLevel < 18)
		{
			resetField(1);
			resetRoute();
			drawLevel();
		}
		else
		{
			drawBitmap(0, 0, ((u16*) youwon_img_bin), 0, 0, 256, 192);
		}
		startLoop();
	}
	else
	{
		warningText = "That is not a correct route";
	}
}

/*
 * set the new block position, determined from the touchscreen x,y points
 */
void setNewPosition(touchPosition* touchXY)
{
	// calculate which block the user is touching.
	if (pointInRangeLimit(touchXY->px, touchXY->py))
	{
		newPosition.x = 1 + (touchXY->px - 11) / 26;
		newPosition.y = 1 + (touchXY->py - 11) / 26;

		// in route and went to new block? validate move!
		if (inRoute && currentLevel < 18 && (newPosition.x != currentPosition.x || newPosition.y != currentPosition.y))
			validateMove();
	}
	else // Out of the limited range results in 0,0.
	{
		newPosition.x = 0;
		newPosition.y = 0;
	}
}

/*
 * validate the move from the last block to the new block
 */
void validateMove()
{
	int valid = 0;

	lastPosition = currentPosition;
	currentPosition = newPosition;
	currentBlock = blocks[currentPosition.x][currentPosition.y];
	lastBlock = blocks[lastPosition.x][lastPosition.y];

	// check if user went out of the limited range
	if (lastPosition.x != 0 && currentPosition.x == 0)
	{
		warningText = "You went off the playfield";
	}
	// check if user moved only 1 block, not more!
	else if (abs(lastPosition.x - currentPosition.x) > 1 || abs(lastPosition.y - currentPosition.y) > 1)
	{
		warningText = "You moved more than one block";
	}
	// check if user did not move diagonal
	else if ((lastPosition.x != 0 && currentPosition.x != 0) && (abs(lastPosition.x - currentPosition.x) > 0 && abs(lastPosition.y - currentPosition.y) > 0))
	{
		warningText = "You moved diagonally";
	}
	// check if user went to a 'no go block'
	else if (currentBlock == 0 || currentBlock == 1)
	{
		warningText = "Do not go over those blocks";
	}
	// check if user went to a block he already went to
	else if (currentBlock < 0 || (currentBlock == 2 && lastBlock != 2))
	{
		warningText = "You went backwards";
	}
	// check if user went to the END block
	else if (currentBlock == 3)
	{
		checkCorrectRoute();
	}
	else
	{
		extendRoute();
		valid = 1;
	}

	if (valid == 0 && routeCorrect == 0 && inRoute == 1)
	{
		playWrong();
		drawWarning(warningText);
		resetRoute();
		resetField(0);
	}
}

/*
 * extend the route, if needed, correct the last block first
 */
void extendRoute()
{
	// vertical
	if (currentPosition.x == lastPosition.x)
	{
		// down
		if (currentPosition.y > lastPosition.y)
		{
			// set the current block status
			blocks[currentPosition.x][currentPosition.y] = -1;
			// correct the last block if needed
			if (lastBlock == -2)
				drawLastBlockTurn(lastPosition.x, lastPosition.y, 2);
			else if (lastBlock == -4)
				drawLastBlockTurn(lastPosition.x, lastPosition.y, 4);
		}
		// up
		else
		{
			blocks[currentPosition.x][currentPosition.y] = -3;
			// correct the last block if needed
			if (lastBlock == -2)
				drawLastBlockTurn(lastPosition.x, lastPosition.y, 1);
			else if (lastBlock == -4)
				drawLastBlockTurn(lastPosition.x, lastPosition.y, 3);
		}
	}
	else // horizontal
	{
		// right
		if (currentPosition.x > lastPosition.x)
		{
			blocks[currentPosition.x][currentPosition.y] = -4;
			// correct the last block if needed
			if (lastBlock == -1)
				drawLastBlockTurn(lastPosition.x, lastPosition.y, 1);
			else if (lastBlock == -3)
				drawLastBlockTurn(lastPosition.x, lastPosition.y, 2);
		}
		// left
		else
		{
			blocks[currentPosition.x][currentPosition.y] = -2;
			// correct the last block if needed
			if (lastBlock == -1)
				drawLastBlockTurn(lastPosition.x, lastPosition.y, 3);
			else if (lastBlock == -3)
				drawLastBlockTurn(lastPosition.x, lastPosition.y, 4);
		}
	}

	// draw the current block (if not at the end yet)
	if (!routeCorrect)
		drawBlock(currentPosition.x, currentPosition.y);

	playBuild();
}

void setUserBlock(Position position)
{
	if (blocks[position.x][position.y] == 4)
	{
		blocks[position.x][position.y] = 1;
		blocksBackground[position.x][position.y] = 1;
		placedPosition.x = position.x;
		placedPosition.y = position.y;
	}
	else if (blocks[position.x][position.y] == 1)
	{
		blocks[position.x][position.y] = 4;
		blocksBackground[position.x][position.y] = 4;
		placedPosition.x = -1;
		placedPosition.y = -1;
	}
}

/*
 * change the pen status if it really changed from the penStatus var, up (0) or down (1).
 */
void changePenStatus(int newPenStatus)
{
	if (!penStatus && newPenStatus)
	{
		penStatus = 1;

		// placing?
		if (placing && penStatus && currentLevel > 1)
		{
			setUserBlock(newPosition);
			resetField(0);
		}
		else
		{
			if (blocks[newPosition.x][newPosition.y] == 2)
			{
				inRoute = 1;
				drawLevel();
			}
			else
			{
				warningText = "Begin at the start point";
				drawWarning(warningText);
			}
		}
	}
	else if (penStatus && !newPenStatus && !routeCorrect)
	{
		penStatus = 0;
		resetRoute();
		resetField(0);
	}
}
