#include ".\collisionmanager.h"

CollisionManager::CollisionManager(void)
{
}

CollisionManager::~CollisionManager(void)
{
}

bool CollisionManager::checkForCollision( RECT* rect1, RECT* rect2 ) {
	if (rect1->bottom < rect2->top) {
		return(false);
	}
	if (rect1->top > rect2->bottom) {
		return(false);
	}
	if (rect1->right < rect2->left) {
		return(false);
	}
	if (rect1->left > rect2->right) {
		return(false);
	}

	return true;
}

bool CollisionManager::checkForCollision( POINT* aPoint, RECT* aRect ) {
	if ( aPoint->y >= aRect->top &&
		 aPoint->y <= aRect->bottom &&
		 aPoint->x >= aRect->left &&
		 aPoint->x <= aRect->right ) {
		return true;
	} else {
		return false;
	}
}

bool CollisionManager::checkForCollision(POINT* movingA, POINT* movingB, POINT* checkA, POINT* checkB) {
	float slope = 0;
	int originX = 0, originY = 0;
	int x1 = 0, y1 = 0, x2 = 0, y2 = 0;
	int pointX = 0, pointY = 0;

	//figure out the slope and the middle "origin" point
	if( checkB->x > checkA->x ) {
		originX = (checkB->x - checkA->x) / 2 + checkA->x;
	} else {
		originX = (checkA->x - checkB->x) / 2 + checkB->x;
	}
	if( checkB->y < checkA->y ) {
		if( checkB->x < checkA->x ) {
			slope = -.5;
		} else {
			slope = .5;
		}
		originY = (checkA->y - checkB->y) / 2+ checkB->y;
	} else {
		if( checkB->x < checkA->x ) {
			slope = .5;
		} else {
			slope = -.5;
		}
		originY = (checkB->y - checkA->y) / 2 + checkA->y;
	}

	//Normalize the moving points to the origin
	x1 = movingA->x - originX;
	x2 = movingB->x - originX;
	y1 = originY - movingA->y;
	y2 = originY - movingB->y;

	//if  the two moving points are on opposite sides of the slope, the lines intersect, so return true
	//it's a vertical line
	if( x1 == x2 ) {
		//figure out the y value along the slope
		pointY = (int)(slope * x1);
		//check if the y values are on opposite sides
		if( ( y1 >= pointY && y2 <= pointY ) || (y1 <= pointY && y2 >= pointY ) ) {
			return true;
		}
	}
	//it's a horizontal line
	if( y1 == y2 ) {
		//figure out the x value along the slope
		pointX = (int)((float)y1 / slope);
		//check if the x values are on opposite sides
		if( ( x1 >= pointX && x2 <= pointX ) || (x1 <= pointX && x2 >= pointX ) ) {
			return true;
		}
	}
	return false;
}

TilePoints* CollisionManager::getTilePoints( int tileX, int tileY ) {
	TilePoints* tilePoints = new TilePoints();

	//TODO: memory leak for points

	// Create left point
	POINT* left = new POINT();
	left->x = tileX * TILE_WIDTH;
	left->y = ( tileY / 2 ) * TILE_HEIGHT + ( TILE_HEIGHT / 2 );
	if ( tileY % 2 == 1 ) {
		left->x += ( TILE_WIDTH / 2 );
		left->y += ( TILE_HEIGHT / 2 );
	}
	tilePoints->setLeft( left );

	// Create top point
	POINT* top = new POINT();
	top->x = tileX * TILE_WIDTH + ( TILE_WIDTH / 2 );
	top->y = ( tileY / 2 ) * TILE_HEIGHT;
	if ( tileY % 2 == 1 ) {
		top->x += ( TILE_WIDTH / 2 );
		top->y += ( TILE_HEIGHT / 2 );
	}
	tilePoints->setTop( top );

	// Create right point
	POINT* right = new POINT();
	right->x = tileX * TILE_WIDTH + TILE_WIDTH;
	right->y = ( tileY / 2 ) * TILE_HEIGHT + ( TILE_HEIGHT / 2 );
	if ( tileY % 2 == 1 ) {
		right->x += ( TILE_WIDTH / 2 );
		right->y += ( TILE_HEIGHT / 2 );
	}
	tilePoints->setRight( right );

	// Create bottom point
	POINT* bottom = new POINT();
	bottom->x = tileX * TILE_WIDTH + ( TILE_WIDTH / 2 );
	bottom->y = ( tileY / 2 ) * TILE_HEIGHT + TILE_HEIGHT;
	if ( tileY % 2 == 1 ) {
		bottom->x += ( TILE_WIDTH / 2 );
		bottom->y += ( TILE_HEIGHT / 2 );
	}
	tilePoints->setBottom( bottom );

	return tilePoints;
}

bool CollisionManager::checkForCollision( RECT* rect, TILE* tile, GameCore::DIRECTION aDirection ) {
    // bottom and top are reversed
    TilePoints* tilePoints = getTilePoints(tile->x, tile->y);
    int b1 = 16+32*(tile->y/2)-32*tile->x;
    int b2 = 16+32*((tile->y+1)/2)+32*tile->x;
    int b3 = -16+32*(tile->y/2)-32*tile->x;
    int b4 = 48+32*((tile->y+1)/2)+32*tile->x;

    switch (aDirection){
        case GameCore::DIRECTION ::UP   :
            // test tile against character
            if( tilePoints->getBottom()->y >= rect->top   &&
                tilePoints->getBottom()->x >= rect->left  &&
                tilePoints->getBottom()->x <= rect->right ){
                return true;
            }
            // test character againts tile
            if( (rect->top <= (rect->left/  2 + b1)   &&
                 rect->top <= (rect->left/ -2 + b4))  ||
                (rect->top <= (rect->right/ 2 + b1)   &&
                 rect->top <= (rect->right/-2 + b4)) ){
                return true;
            }
            break;
        case GameCore::DIRECTION ::DOWN :
            // test tile against character
            if( tilePoints->getTop()->y <= rect->bottom &&
                tilePoints->getTop()->x >= rect->left   &&
                tilePoints->getTop()->x <= rect->right  ){
                return true;
            }
            // test character againts tile
            if( (rect->bottom >= (rect->left/ -2 + b2)  &&
                 rect->bottom >= (rect->left/  2 + b3)) ||
                (rect->bottom >= (rect->right/-2 + b2)  &&
                 rect->bottom >= (rect->right/ 2 + b3)) ){
                return true;
            }
            break;
        case GameCore::DIRECTION ::LEFT :
            // test tile against character
            if( tilePoints->getRight()->y >= rect->top    &&
                tilePoints->getRight()->y <= rect->bottom &&
                tilePoints->getRight()->x >= rect->left  ){
                return true;
            }
            // test character againts tile
            if( (rect->top    >= (rect->left/ 2 + b3)  &&
                 rect->top    <= (rect->left/-2 + b4)) ||
                (rect->bottom >= (rect->left/ 2 + b3)  &&
                 rect->bottom <= (rect->left/-2 + b4)) ){
                return true;
            }
            break;
        case GameCore::DIRECTION ::RIGHT:
            // test tile against character
            if( tilePoints->getLeft()->y >= rect->top    &&
                tilePoints->getLeft()->y <= rect->bottom &&
                tilePoints->getLeft()->x <= rect->right  ){
                return true;
            }
            // test character againts tile
            if( (rect->top    <= (rect->right/ 2 + b1)  &&
                 rect->top    >= (rect->right/-2 + b2)) ||
                (rect->bottom <= (rect->right/ 2 + b1)  &&
                 rect->bottom >= (rect->right/-2 + b2)) ){
                return true;
            }
            break;
    }
	if (tilePoints){
		delete tilePoints;
		tilePoints = 0;
	}
    return false;
}

bool CollisionManager::checkForCollision( RECT* rect, TilePoints* tilePoints, GameCore::DIRECTION aDirection ) {
    /* top -> on screen (top < bottom)
       1 refers to bottom left line
       2 refers to top left line
       3 refers to top right line
       4 refers to bottom right line*/

    // slope info
    float m1 = (float)(tilePoints->getBottom()->y - tilePoints->getLeft()->y) /(tilePoints->getBottom()->x - tilePoints->getLeft()->x);
    float m2 = (float)(tilePoints->getTop()->y    - tilePoints->getLeft()->y) /(tilePoints->getTop()->x    - tilePoints->getLeft()->x);
    float m3 = (float)(tilePoints->getTop()->y    - tilePoints->getRight()->y)/(tilePoints->getTop()->x    - tilePoints->getRight()->x);
    float m4 = (float)(tilePoints->getBottom()->y - tilePoints->getRight()->y)/(tilePoints->getBottom()->x - tilePoints->getRight()->x);
    // intercept info
    float b1 = tilePoints->getBottom()->y - m1 * tilePoints->getBottom()->x;
    float b2 = tilePoints->getTop()->y    - m2 * tilePoints->getTop()->x;
    float b3 = tilePoints->getTop()->y    - m3 * tilePoints->getTop()->x;
    float b4 = tilePoints->getBottom()->y - m4 * tilePoints->getBottom()->x;

    switch (aDirection){
        case GameCore::DIRECTION ::UP   :
            // test tile against character
            if( tilePoints->getBottom()->y >= rect->top   &&
                tilePoints->getBottom()->x >= rect->left  &&
                tilePoints->getBottom()->x <= rect->right ){
                return true;
            }
            // test character againts tile
            if( (rect->top <= (rect->left  * m1 + b1)  &&
                 rect->top <= (rect->left  * m4 + b4)) ||
                (rect->top <= (rect->right * m1 + b1)  &&
                 rect->top <= (rect->right * m4 + b4)) ){
                return true;
            }
            break;
        case GameCore::DIRECTION ::DOWN :
            // test tile against character
            if( tilePoints->getTop()->y <= rect->bottom &&
                tilePoints->getTop()->x >= rect->left   &&
                tilePoints->getTop()->x <= rect->right  ){
                return true;
            }
            // test character againts tile
            if( (rect->bottom >= (rect->left  * m2 + b2)  &&
                 rect->bottom >= (rect->left  * m3 + b3)) ||
                (rect->bottom >= (rect->right * m2 + b2)  &&
                 rect->bottom >= (rect->right * m3 + b3)) ){
                return true;
            }
            break;
        case GameCore::DIRECTION ::LEFT :
            // test tile against character
            if( tilePoints->getRight()->y >= rect->top    &&
                tilePoints->getRight()->y <= rect->bottom &&
                tilePoints->getRight()->x >= rect->left   ){
                return true;
            }
            // test character againts tile
            if( (rect->top    >= (rect->left * m3 + b3)  &&
                 rect->top    <= (rect->left * m4 + b4)) ||
                (rect->bottom >= (rect->left * m3 + b3)  &&
                 rect->bottom <= (rect->left * m4 + b4)) ){
                return true;
            }
            break;
        case GameCore::DIRECTION ::RIGHT:
            // test tile against character
            if( tilePoints->getLeft()->y >= rect->top    &&
                tilePoints->getLeft()->y <= rect->bottom &&
                tilePoints->getLeft()->x <= rect->right  ){
                return true;
            }
            // test character againts tile
            if( (rect->top    <= (rect->right * m1 + b1)  &&
                 rect->top    >= (rect->right * m2 + b2)) ||
                (rect->bottom <= (rect->right * m1 + b1)  &&
                 rect->bottom >= (rect->right * m2 + b2)) ){
                return true;
            }
            break;
    }
    return false;
}

bool CollisionManager::checkForCollision( RECT* rect, TilePoints* tilePoints) {
    /* top -> on screen (top < bottom)
       1 refers to bottom left line
       2 refers to top left line
       3 refers to top right line
       4 refers to bottom right line*/

    // slope info
    float m1 = (float)(tilePoints->getBottom()->y - tilePoints->getLeft()->y) /(tilePoints->getBottom()->x - tilePoints->getLeft()->x);
    float m2 = (float)(tilePoints->getTop()->y    - tilePoints->getLeft()->y) /(tilePoints->getTop()->x    - tilePoints->getLeft()->x);
    float m3 = (float)(tilePoints->getTop()->y    - tilePoints->getRight()->y)/(tilePoints->getTop()->x    - tilePoints->getRight()->x);
    float m4 = (float)(tilePoints->getBottom()->y - tilePoints->getRight()->y)/(tilePoints->getBottom()->x - tilePoints->getRight()->x);
    // intercept info
    float b1 = tilePoints->getBottom()->y - m1 * tilePoints->getBottom()->x;
    float b2 = tilePoints->getTop()->y    - m2 * tilePoints->getTop()->x;
    float b3 = tilePoints->getTop()->y    - m3 * tilePoints->getTop()->x;
    float b4 = tilePoints->getBottom()->y - m4 * tilePoints->getBottom()->x;

    // test bottom tile point againt character
    if( tilePoints->getBottom()->y >= rect->top    &&
        tilePoints->getBottom()->y <= rect->bottom &&
        tilePoints->getBottom()->x >= rect->left   &&
        tilePoints->getBottom()->x <= rect->right  ){
        return true;
    }
    // test top tile point againt character
    if( tilePoints->getTop()->y >= rect->top    &&
        tilePoints->getTop()->y <= rect->bottom &&
        tilePoints->getTop()->x >= rect->left   &&
        tilePoints->getTop()->x <= rect->right  ){
        return true;
    }
    // test left tile point againt character
    if( tilePoints->getLeft()->y >= rect->top    &&
        tilePoints->getLeft()->y <= rect->bottom &&
        tilePoints->getLeft()->x <= rect->right  &&
        tilePoints->getLeft()->x >= rect->left   ){
        return true;
    }
    // test right tile point againt character
    if( tilePoints->getRight()->y >= rect->top    &&
        tilePoints->getRight()->y <= rect->bottom &&
        tilePoints->getRight()->x <= rect->right  &&
        tilePoints->getRight()->x >= rect->left   ){
        return true;
    }

    // test char bottom againts tile
    if( (rect->top <= (rect->left * m1 + b1) && rect->top >= (rect->left * m2 + b2)) &&
        (rect->top >= (rect->left * m3 + b3) && rect->top <= (rect->left * m4 + b4)) ){
        return true;
    }
    // test char bottom againts tile
    if( (rect->top <= (rect->right * m1 + b1) && rect->top >= (rect->right * m2 + b2)) &&
        (rect->top >= (rect->right * m3 + b3) && rect->top <= (rect->right * m4 + b4)) ){
        return true;
    }
    // test char bottom againts tile
    if( (rect->bottom <= (rect->left * m1 + b1) && rect->bottom >= (rect->left * m2 + b2)) &&
        (rect->bottom >= (rect->left * m3 + b3) && rect->bottom <= (rect->left * m4 + b4)) ){
        return true;
    }
    // test char bottom againts tile
    if( (rect->bottom <= (rect->right * m1 + b1) && rect->bottom >= (rect->right * m2 + b2)) &&
        (rect->bottom >= (rect->right * m3 + b3) && rect->bottom <= (rect->right * m4 + b4)) ){
        return true;
    }
    return false;
}
