#include "ScreenManager.h"

ScreenManager::ScreenManager(void){
	xPixelOffset = TILE_WIDTH / 2;
	yPixelOffset = TILE_HEIGHT / 2;
	// TODO: Make sure these are both even
	xTextureOffset = 63;
	yTextureOffset = 414;
	mapManager = 0;
	spriteRenderer = 0;
}

ScreenManager::~ScreenManager(void){
}

void ScreenManager::setMapManager( MapManager* newMapManager ) {
	mapManager = newMapManager;
}

void ScreenManager::setSpriteRenderer( SpriteRenderer* newSpriteRenderer ) {
	spriteRenderer = newSpriteRenderer;
}

HRESULT ScreenManager::render() {
	int aTexture;
	HRESULT r = S_OK;
    // Loop over the columns
	for ( int column = xTextureOffset - 1; 
		column < xTextureOffset + TILES_PER_ROW; 
		column++ ) {
		// Render column
		for ( int y = yTextureOffset - 2;
			  y < yTextureOffset + TILES_PER_COLUMN;
			  y += 2 ) {
		    // Render first sprite
			aTexture = mapManager->getTextureId( column, y );
			if ( aTexture != -1 ) {
				r = spriteRenderer->renderToScreen( aTexture, 
						( column - xTextureOffset ) * TILE_WIDTH // figure out theoretical x purely based on which texture we are relative to the corner of the screen
							+ xPixelOffset // adjust for shifting world
							- TILE_WIDTH, // adjust for 1 tile padding on left side
						( y - yTextureOffset ) / 2 * TILE_HEIGHT // figure out theoretical y purely based on which texture we are relative to the corner of the screen.  / 2 takes into account the += 2 in the for loop.
							+ yPixelOffset // adjust for shifting world
							- TILE_HEIGHT ); // adjust for 1 tile padding on left side
			}

			// Render second sprite
			aTexture = mapManager->getTextureId( column, y + 1 );
			if ( aTexture != -1 ) {
				r = spriteRenderer->renderToScreen( aTexture, 
						( column - xTextureOffset ) * TILE_WIDTH 
							+ ( TILE_WIDTH / 2 ) // adjust for weird tiling scheme
							+ xPixelOffset 
							- TILE_WIDTH, 
						( y - yTextureOffset ) / 2 * TILE_HEIGHT 
							+ ( TILE_HEIGHT / 2 ) 
							+ yPixelOffset 
							- TILE_HEIGHT );
			}
		}
	}
	return r;
}
/*
HRESULT ScreenManager::render() {
	int aTexture;
	HRESULT r = S_OK;

	// Loop over the columns
	for ( int column = xTextureOffset - 1; 
		column < xTextureOffset + TILES_PER_ROW; 
		column++ ) {
		// Render column
		for ( int y = yTextureOffset - 2;
			  y < yTextureOffset + TILES_PER_COLUMN;
			  y += 2 ) {
		    // Render first sprite
			aTexture = mapManager->getTextureId( column, y );
			if ( aTexture == -1 ) {
				GameError( "Error getting texture from map" );
				return E_FAIL;
			}
			r = spriteRenderer->renderToScreen( aTexture, 
					( column - xTextureOffset ) * TILE_WIDTH // figure out theoretical x purely based on which texture we are relative to the corner of the screen
						+ xPixelOffset // adjust for shifting world
						- TILE_WIDTH, // adjust for 1 tile padding on left side
					( y - yTextureOffset ) / 2 * TILE_HEIGHT // figure out theoretical y purely based on which texture we are relative to the corner of the screen.  / 2 takes into account the += 2 in the for loop.
						+ yPixelOffset // adjust for shifting world
						- TILE_HEIGHT ); // adjust for 1 tile padding on left side
			if ( FAILED( r ) ) {
				GameError( "Error rendering sprite" );
				return r;
			}

			// Render second sprite
			aTexture = mapManager->getTextureId( column, y + 1 );
			if ( aTexture == -1 ) {
				GameError( "Error getting texture from map" );
				return E_FAIL;
			}
			r = spriteRenderer->renderToScreen( aTexture, 
					( column - xTextureOffset ) * TILE_WIDTH 
						+ ( TILE_WIDTH / 2 ) // adjust for weird tiling scheme
						+ xPixelOffset 
						- TILE_WIDTH, 
					( y - yTextureOffset ) / 2 * TILE_HEIGHT 
						+ ( TILE_HEIGHT / 2 ) 
						+ yPixelOffset 
						- TILE_HEIGHT );
			if ( FAILED( r ) ) {
				GameError( "Error rendering sprite" );
				return r;
			}
		}
	}

	return r;
}
*/
// Returns whether the method was able to move down.
// It would not be able to if it caused us to scroll off the map.
bool ScreenManager::moveScreenDown() {
	yPixelOffset += Y_INCREMENT;
	if ( yPixelOffset > TILE_HEIGHT ) {
		yPixelOffset -= TILE_HEIGHT;
		yTextureOffset -= 2;
	}
	return true;
}

bool ScreenManager::moveScreenUp() {
	yPixelOffset -= Y_INCREMENT;
	if ( yPixelOffset < 0 ) {
		yPixelOffset += TILE_HEIGHT;
		yTextureOffset += 2;
	}
	return true;
}

bool ScreenManager::moveScreenLeft() {
	xPixelOffset -= X_INCREMENT;
	if ( xPixelOffset < 0 ) {
		xPixelOffset += TILE_WIDTH;
		xTextureOffset++;
	}
	return true;	
}

bool ScreenManager::moveScreenRight() {
	xPixelOffset += X_INCREMENT;
	if ( xPixelOffset > TILE_WIDTH ) {
		xPixelOffset -= TILE_WIDTH;
		xTextureOffset--;
	}
	return true;	
}

void ScreenManager::printStatistics() {
	GameError( "XPixelOffset:", xPixelOffset );
	GameError( "YPixelOffset:", yPixelOffset );
	GameError( "XTextureOffset:", xTextureOffset );
	GameError( "YTextureOffset:", yTextureOffset );
}


int ScreenManager::getXPixelOffset() {
	return xPixelOffset;
}

void ScreenManager::setXPixelOffset( int newOffset ) {
	xPixelOffset = newOffset;
}

int ScreenManager::getYPixelOffset() {
	return yPixelOffset;
}

void ScreenManager::setYPixelOffset( int newOffset ) {
	yPixelOffset = newOffset;
}

int ScreenManager::getYTextureOffset() {
	return yTextureOffset;
}

void ScreenManager::setYTextureOffset( int newOffset ) {
	yTextureOffset = newOffset;
}

int ScreenManager::getXTextureOffset() {
	return xTextureOffset;
}

void ScreenManager::setXTextureOffset( int newOffset ) {
	xTextureOffset = newOffset;
}

int ScreenManager::getScreenX() {
	return ( xTextureOffset * TILE_WIDTH ) - xPixelOffset + TILE_WIDTH;
}

int ScreenManager::getScreenY() {
	return ( yTextureOffset / 2 * TILE_HEIGHT ) - yPixelOffset + TILE_HEIGHT;
}

const int ScreenManager::getWindowWidth() {
	return WINDOW_WIDTH;
}

const int ScreenManager::getWindowHeight() {
	return WINDOW_HEIGHT;
}

const int ScreenManager::getWindowBoundLeft() {
	return BOUND_LEFT;
}

const int ScreenManager::getWindowBoundRight() {
	return BOUND_RIGHT;
}

const int ScreenManager::getWindowBoundTop() {
	return BOUND_TOP;
}

const int ScreenManager::getWindowBoundBottom() {
	return BOUND_BOTTOM;
}

TILE* ScreenManager::getTileFromWorldPoint( POINT* aPoint ) {
	TILE* aTile = new TILE();

	// Figure out which virtual box we're in
	int boxX = aPoint->x / ( TILE_WIDTH / 2 );
	int boxY = aPoint->y / ( TILE_HEIGHT / 2 );
/*
	// x and y world coordinates of the origin
	int boxXFromNewOrigin = aPoint->x - ( boxX * ( TILE_WIDTH / 2 ) );
	int boxYFromNewOrigin = aPoint->y - ( boxY * ( TILE_WIDTH / 2 ) );

	// Figure out which way our line is
	int yOfLine; // at our points x
	if ( ( boxX % 2 == 1 && boxY % 2 == 0 ) ||
		 ( boxX % 2 == 0 && boxY % 2 == 1 ) ) {
		// slope positive =  1/2
		// odd x and even y -or- even x and odd y

		// y = mx + b
	   // TODO: replace with bitshifting
		yOfLine = boxXFromNewOrigin / 2;

		if ( boxYFromNewOrigin < yOfLine ) {
			// We're above the line on the screen
			aTile->x = boxX / 2;
			aTile->y = boxY - 1;
		} else {
			// We're below the line on the screen
			aTile->x = boxX / 2;
			// If it's even, subtract one
			if ( boxX % 2 == 0 ) {
				aTile->x--;
			}
			aTile->y = boxY;
		}
	} else {
		// slope negative = -1/2
		yOfLine = boxXFromNewOrigin / -2 + ( TILE_HEIGHT / 2 );

		if ( boxYFromNewOrigin < yOfLine ) {
			// We're above the line on the screen
			aTile->x = boxX / 2;
			// If it's even, subtract one
			if ( boxX % 2 == 0 ) {
				aTile->x--;
			}
			aTile->y = boxY - 1;
		} else {
			// We're below the line on the screen
			aTile->x = boxX / 2;
			aTile->y = boxY;
		}
	}
*/
	bool evenX = false;
	bool evenY = false;

	if( boxX % 2 == 0 ) {
		evenX = true;
	}
	if( boxY % 2 == 0 ) {
		evenY = true;
	}

	int isoX = 0, isoY = 0;
	int slopeY = 0;

	//middle of box our point is in
	int originX = (boxX * TILE_WIDTH / 2 ) + TILE_WIDTH / 4;
	int originY = (boxY * TILE_HEIGHT / 2 ) + TILE_HEIGHT / 4;

	//our point relative to origin
	int pointX = aPoint->x - originX;
	int pointY = originY - aPoint->y;

	//if the box has a / slope
	if( evenX == evenY ) {
		slopeY = (int)(pointX * .5);
		//if our point is above the line
		if( pointY > slopeY ) {
			if( evenX ) {
				isoX = (boxX/2) - 1;
				isoY = boxY - 1;
			} else {
				isoX = boxX / 2;
				isoY = boxY - 1;
			}
		//if our point is below the line
		} else {
			if( evenX ) {
				isoX = boxX / 2;
				isoY = boxY;
			} else {
				isoX = boxX / 2;
				isoY = boxY;
			}
		}
	} else {
		slopeY = (int)(pointX * -.5);
		//if our point is above the line
		if( pointY > slopeY ) {
			if( evenX ) {
				isoX = (boxX/2);
				isoY = boxY - 1;
			} else {
				isoX = boxX / 2;
				isoY = boxY - 1;
			}
		//if our point is below the line
		} else {
			if( evenX ) {
				isoX = (boxX / 2) - 1;
				isoY = boxY;
			} else {
				isoX = boxX / 2;
				isoY = boxY;
			}
		}
	}

	aTile->x = isoX;
	aTile->y = isoY;

	return aTile;
}

int ScreenManager::getTextureId( TILE* aTile ) {
	return mapManager->getTextureId( aTile->x, aTile->y );
}

bool ScreenManager::getWalkability( int textureId, RECT* collideRect, bool mainCharacter ){
    return spriteRenderer->getTextureManager()->getWalkability(textureId, collideRect, mainCharacter);
}
