#include "TextureManager.h"
#include <fstream>

TextureManager::TextureManager()
{
	textures.resize(1000);
	textureWalkable.resize( 1000 );
	masks.resize( 200 );
}

TextureManager::~TextureManager()
{
	// Release the textures
	texture* aTexture;
	for(unsigned int index = 0; index < textures.size(); index++){
		aTexture = textures.at(index);
		if(aTexture){
            aTexture->direct3dTexture->Release();
            aTexture->direct3dTexture = NULL;
            if ( aTexture->mask ) {
                delete aTexture->mask;
                aTexture->mask = NULL;
            }
			delete aTexture;
			aTexture = 0;
		}
	}

    char* maskFileName;
	for ( unsigned int index = 0; index < masks.size(); index++){
		maskFileName = masks.at(index);
        if ( maskFileName ) {
            delete maskFileName;
            maskFileName = NULL;
        }
    }

	textureWalkable.clear();
}

HRESULT TextureManager::loadMasks( char* fileName ) {
	HRESULT r = S_OK;

	fstream maskFile( fileName );

	int maskId;
	while ( maskFile.peek() != -1 ) {
        char* buffer = ( char* ) malloc( sizeof( char ) * 256 );  // to hold a specific tile masks file name
		maskFile >> maskId >> buffer;
        masks[ maskId ] = buffer;
	}

	maskFile.close();

	return r;
}

HRESULT TextureManager::loadTexturesFromFile( char* fileName ) 
{
	HRESULT r = S_OK;

	fstream textureFile( fileName );

	int textureId;
	int walkable;
    int maskId;
	char buffer[ 256 ];
	while ( textureFile.peek() != -1 ) {
		textureFile >> textureId >> walkable >> maskId >> buffer;
		LPDIRECT3DTEXTURE9 aTexture = loadTexture( buffer );
		if ( aTexture != NULL ) {
            texture* fullTexture = new texture();
            fullTexture->direct3dTexture = aTexture;

            // Load up mask
            if ( maskId != -1 ) {
                bool* aMask = new bool[ 64 * 32 ];
                fstream aMaskFile( masks[ maskId ] );

				if ( !aMaskFile ) {
					GameError( "Could not open mask" );
					return E_FAIL;
				}
                char maskWalkable;
                int counter = 0;
                while ( aMaskFile.peek() != -1 ) {
                    aMaskFile >> maskWalkable;
					maskWalkable -= 48; // convert to one or zero from ascii values
                    if ( maskWalkable == 1 ) {
                            *( aMask + counter ) = true;
                    } else if ( maskWalkable == 0 ) {
                            *( aMask + counter ) = false;
                    } else {
                            GameError( "Could not load mask pixels" );
                            aMaskFile.close();
                            return E_FAIL;
                    }
                    counter++;
                }

				GameError( "\n" );
                aMaskFile.close();
                fullTexture->mask = aMask;
            } else {
                fullTexture->mask = NULL;
            }

			textures[ textureId ] = fullTexture;
			if( walkable == 0 ) {
				textureWalkable[ textureId ] = false;
			} else {
				textureWalkable[ textureId ] = true;
			}
		} else {
			GameError( "Could not load texture file: " );
			GameError( buffer );
            textureFile.close();
			return E_FAIL;
		}
	}

	textureFile.close();

	return r;
}

LPDIRECT3DTEXTURE9 TextureManager::getTexture( int textureId ) {
    return textures[ textureId ]->direct3dTexture;
}

void TextureManager::setD3DDevice( LPDIRECT3DDEVICE9 newd3dDevice ) {
	pd3dDevice = newd3dDevice;
}

LPDIRECT3DTEXTURE9 TextureManager::loadTexture( char* fileName ) {
	LPDIRECT3DTEXTURE9 aTexture;
	
	HRESULT r = D3DXCreateTextureFromFile(
		pd3dDevice, //LPDIRECT3DDEVICE9 pDevice,
		fileName, //LPCTSTR pSrcFile,
		&aTexture //LPDIRECT3DTEXTURE9 *ppTexture
	);

	if ( FAILED( r ) ) {
		return NULL;
	}

	return aTexture;
}

bool TextureManager::getWalkability( int textureId, RECT* collideRect, bool mainCharacter ) {
    bool walkability = false;

	if(textureId == -1) {
		walkability = false;
	} else {
		walkability = textureWalkable[ textureId ];
		if ( !walkability && mainCharacter) {
			if ( textures[ textureId ] != NULL ) {
				bool* mask = textures[ textureId ]->mask;
				if ( mask != NULL ) {
					int top = clipYToTile( collideRect->top );
					int bottom = clipYToTile( collideRect->bottom );
					int right = clipXToTile( collideRect->right );
					int left = clipXToTile( collideRect->left );
					// Check if we're not even in the tile at all
					if ( left != right && top != bottom ) {
						for ( int i = left; left != right && i <= right; i++ ) {
							for ( int j = top; bottom != top && j <= bottom; j++ ) {
								bool* pixel = mask + i + ( j * 64 ) - 1;
								if ( *pixel == false ) {
									return false;
								}
							}
						}
						return true;
//					} else {
//						return false;
					}
				}
			}
		}
    }

	return walkability;
}

int TextureManager::clipXToTile( int oldX ) {
    if ( oldX < 0 ) {
        return 0;
    } else if ( oldX > 63 ) {
        return 63;
    } else {
        return oldX;
    }
}

int TextureManager::clipYToTile( int oldY ) {
    if ( oldY < 0 ) {
        return 0;
    } else if ( oldY > 31 ) {
        return 31;
    } else {
        return oldY;
    }
}
