#include "TextManager.h"

using namespace std;

TextManager::TextManager(void){
}

TextManager::~TextManager(void){
}

void TextManager::init(SpriteRenderer* newSpriteRenderer){
    spriteRenderer = newSpriteRenderer;
}

HRESULT TextManager::loadAlphabet( int textureId, int alphabetWidth, int alphabetHeight, int lettersPerRow,  int letterWidth, int letterHeight ) {
    HRESULT r = S_OK;

    // Make sure a path was specified
    if ( textureId == -1 ) {
        return E_FAIL;
    }

    // Make sure all parameters are > 0
    if ( !letterWidth || !letterHeight || !alphabetWidth || !alphabetHeight || !lettersPerRow ) {
        return E_FAIL;
    }

    TextImage* image = new TextImage();
    image->init( textureId, alphabetWidth, alphabetHeight, lettersPerRow,  letterWidth, letterHeight );

    textMap[textureId] = image;

    return r;
}

void TextManager::printChar( int x, int y, char character, int textureId, Text::TEXT_COORDINATES textCoords ) {
    HRESULT r = 0;
    SpriteStamp* textStamp;
    D3DXVECTOR3* oldPosition;
    TextImage* textImage = textMap[ textureId ];

    div_t Result;   // Holds the result of the divisions

    // The offset into the alphabet image
    int offsetX = 0;
    int offsetY = 0;

    POINT letterDestPoint = { 0, 0 }; // The destination point of the letter
    RECT  letterRect = { 0, 0, 0, 0 }; // The source rectangle for the letter

    // If the alphabet has not been loaded yet then exit
    if( !(textImage->isLoaded()) ){
        return;
    }

    // The characters are specified in ASCII code, which begins at 32 so
    // we want to decrement this value by 32 to make it zero based
    character -= 32;

    // Divide the character code by the number of letters per row.
    // The quotient will help get the vertical offset and the
    // remainder will help get the horizontal offset.
    Result = div( character, textImage->getLettersPerRow() );

    // Get the horizontal offset by multiplying the remainder
    // by the width of the letter
    offsetX = Result.rem * textImage->getLetterWidth();

    // Get the vertical offset by multiplying the quotient
    // by the height of the letter
    offsetY = Result.quot * textImage->getLetterHeight();

    RECT charRect = { offsetX, offsetY, offsetX + textImage->getLetterWidth(), offsetY + textImage->getLetterHeight() };

    if ( textImage != NULL ) {
        textStamp = textImage->getSpriteStamp();
        oldPosition = textStamp->getPosition();
        if ( oldPosition ) {
            delete oldPosition;
            oldPosition = 0;
        }
        textStamp->setClippingRect(&charRect);
        textStamp->setPosition( new D3DXVECTOR3( ( float ) x, ( float ) y, 1.0 ) );
    }
	if ( textCoords == Text::WORLD ) {
		spriteRenderer->renderSpriteToWorld( textStamp );
	} else if ( textCoords == Text::SCREEN ) {
		spriteRenderer->renderSpriteToScreen( textStamp );
	} else {
		GameError( "Confused about where you want me to render text.  Skipping text..." );
	}
}

Text* TextManager::addString( int x, int y, char* aString, int textureId, int lifeTime, Text::TEXT_COORDINATES textCoords ){
    return addString( x, y, aString, textureId, lifeTime, 1.0, 1.0, textCoords );
}
Text* TextManager::addString( int x, int y, char* aString, int textureId, int lifeTime, float scale, Text::TEXT_COORDINATES textCoords ){
    return addString( x, y, aString, textureId, lifeTime, scale, scale, textCoords );
}
Text* TextManager::addString( int x, int y, char* aString, int textureId, int lifeTime, float scaleX, float scaleY, Text::TEXT_COORDINATES textCoords ){
    Text* newString = new Text(x,y,aString,textureId,lifeTime,scaleX,scaleY,textCoords);
    strings.insert( strings.end(), newString);
    return newString;
}
Text* TextManager::addString( int x, int y, char* aString, int textureId, int lifeTime, Text::TEXT_COORDINATES textCoords, Text::TEXT_EFFECT effect){
    Text* newString = new Text(x,y,aString,textureId,lifeTime,textCoords,effect);
    strings.insert( strings.end(), newString);
    return newString;
}

void TextManager::removeString(Text* string){
    list<Text*>::iterator iter;

    iter = strings.begin();
    while( (( *iter ) != string) && (iter != strings.end()) ){
        iter++;
    }
    if(iter != strings.end()){
        strings.remove( *iter );
        if(string){
//            delete string;
            string = 0;
        }
    }
}

int TextManager::getStringWidth( char* aString, int textureId ){
    return getStringWidth(aString, textureId, 1.0);
}
int TextManager::getStringWidth( char* aString, int textureId, float scaleX){
    int maxLength = 0;
    int current = 0;

    // find length of longest string between line breaks
    for(int index = 0; aString[index] != '\0'; index++){
        if(aString[index] == '\n'){
            if(current > maxLength){
                maxLength = current;
            }
            current = 0;
        }
        else{
            current++;
        }
    }
    if(current > maxLength){
        maxLength = current;
    }
    return (int)(maxLength * textMap[textureId]->getLetterWidth() * scaleX);
}
int TextManager::getStringHeight( char* aString, int textureId ){
    return getStringHeight(aString, textureId, 1.0);
}
int TextManager::getStringHeight( char* aString, int textureId, float scaleY ){
    int numLines = 1;

    // find length of longest string between line breaks
    for(int index = 0; aString[index] != '\0'; index++){
        if(aString[index] == '\n'){
            numLines++;
        }
    }
    return (int)(numLines * textMap[textureId]->getLetterHeight() * scaleY);
}

void TextManager::makeStringFitInWidth(Text* string, int width){
    int charWidth    = textMap[string->getTextureId()]->getLetterWidth();
    int maxChars     = width / charWidth;
    int maxWidth     = 0;
    int current      = 0;
    int stringLength = 0;

    // find max width in string
    for(int index = 0; string->getString()[index] != '\0'; index++){
        if(string->getString()[index] == '\n'){
            if(current > maxWidth){
                maxWidth = current;
            }
            current = 0;
        }
        else{
            current++;
        }
        stringLength++;
    }
    string->getString()[stringLength-1] = '\0';
    if(current > maxWidth){
        maxWidth = current;
    }
    // add newlines to string if it is too long
    if(maxWidth*charWidth > width){
        // remove all new lines and replace with spaces
        for(int index = 0; string->getString()[index] != '\0'; index++){
            if(string->getString()[index] == '\n'){
                string->getString()[index] = ' ';
            }
        }
        current = maxChars;
        while(current > 0 && current < stringLength){
            if( string->getString()[current] == ' '){
                string->getString()[current] = '\n';
                current += maxChars+1;
            }
            else{
                current--;
            }
        }
    }
}

void TextManager::render(){
    list<Text*>::iterator iter;
    TextImage* textImage;
    size_t     length = 0;
    int        row = 0;
    int        col = 0;

    for(iter = strings.begin(); iter != strings.end(); iter++){
        col = 0;
        row = 0;
        length = strlen( ( *iter )->getString());
        textImage = textMap[( *iter )->getTextureId()];
        spriteRenderer->setScaleMatrix( ( *iter )->getScaleX(), ( *iter )->getScaleY() );
        // Loop for each character in the string
        for ( unsigned int i = 0; i < length; i++ ){
            if(( *iter )->getString()[i] == '\n'){
                row++;
                col = 0;
            }
            else{
                // Print the current character
                printChar( ( *iter )->getX() + (textImage->getLetterWidth()  * col++),
                           ( *iter )->getY() + (textImage->getLetterHeight() * row),
                           ( *iter )->getString()[i],
                           ( *iter )->getTextureId(),
    					   ( *iter )->getTextCoordinates());
            }
        }
        spriteRenderer->setIdentityMatrix();
        if( (*iter)->getTextEffect() == Text::TEXT_EFFECT::GRAVITY ){
            (*iter)->gravityEffect();
        }
    }
}

void TextManager::tick(){
    list<Text*>::iterator iter;
    for(iter = strings.begin(); iter != strings.end(); iter++){
        // test to see if string should disappear
        if ( ( *iter )->dead() ){
            Text* string = ( *iter );
            strings.remove( *iter-- );
            if(string){
                delete string;
                string = 0;
            }
        } else {
            ( *iter )->tick();
        }
    }
}
