#include "DevLib.h"
/******************************************************************************
 * Application.cpp                                                            *
 ******************************************************************************
 * Project      : Futura (DevLib Demo)                                        *
 * License      : LGPL (full notice can be found at root directory)           *
 * Created by   : Arnaud Storq (norecess@devlib-central.org)                  *
 ******************************************************************************/
#include "Application.h"
#include "DisplayableFactory.h"
#include "Menu.h"
#include "Game.h"

// ---------------------------------------------------------------------------- LOCAL DEFINES
#define FILE_ZIP_ARCHIVE    "futura.zip"
#define FILE_XML_CONTENT    "content.xml"

// ---------------------------------------------------------------------------- INSTANCE MEMBER
Application *Application::m_instance = 0;

// ---------------------------------------------------------------------------- GET INSTANCE
Application *Application::getInstance( )
{ 
    if ( m_instance )
        return m_instance;

    m_instance = new Application( );

    return m_instance;
}

// ---------------------------------------------------------------------------- DESTROY
void Application::destroy( )
{
    assert( m_instance );

    if ( m_instance )
        delete m_instance;

    m_instance = 0;
}

// ---------------------------------------------------------------------------- CONSTRUCTOR
Application::Application( )
{
    m_resourceReader = 0;
    m_soundSystem = 0;

    m_xml = 0;
    m_littleFont = 0;
    m_bigFont = 0;
    m_hud = 0;
    m_detail = 0;

    m_clickSelect = 0;
    m_clickValidate = 0;
    m_death = 0;
    m_go = 0;
    m_jump = 0;
    
    m_fade = 0;

    m_elapsedTime = 0.0f;
    m_time = 0.0f;

    m_player1 = 0;
    m_player2 = 0;

    m_level = 0;
    m_levelIndex = 0;

    m_background = 0;
    m_loading = 0;

    m_languageType = LANGUAGE_FRENCH;
}

// ---------------------------------------------------------------------------- DESTRUCTOR
Application::~Application( )
{
}

// ---------------------------------------------------------------------------- CREATE
void Application::create( )
{
    m_resourceReader = ResourceReaderZip::createReader( FILE_ZIP_ARCHIVE );
    ResourceManager::setReader( m_resourceReader );

    m_soundSystem = SoundSystemFMOD::createSoundSystem( 44100, true );
    SoundSystemManager::setSoundSystem( m_soundSystem );

    m_xml = XML::createXML( FILE_XML_CONTENT );

    XMLNode *shipsNode = getXML( )->getRoot( )->getChildElement( "common" )->getChildElement( "ships" );
    for ( int shipChild = 0; shipChild < shipsNode->getAttribute( "count" )->getInt( ); ++shipChild )
    {
        XMLNode *shipNode = shipsNode->getChildElement( shipChild );

        string name = shipNode->getChildElement( "name" )->getChildElement( )->getString( );
        float scale = shipNode->getChildElement( "scale" )->getChildElement( )->getFloat( );
        float lenghtJump = shipNode->getChildElement( "lenghtJump" )->getChildElement( )->getFloat( );
        float grip = shipNode->getChildElement( "grip" )->getChildElement( )->getFloat( );
        float maxSpeed = shipNode->getChildElement( "maxSpeed" )->getChildElement( )->getFloat( );
        string meshFilename = shipNode->getChildElement( "mesh" )->getChildElement( )->getString( );

        Ship *ship = Ship::createShip( name, meshFilename, scale, grip, maxSpeed, lenghtJump );
        m_ships.push_back( ship );
    }

    XMLNode *littleFontNode = getXML( )->getRoot( )->getChildElement( "common" )->getChildElement( "fonts" )->getChildElement( "little" );
    int littleFontSize = littleFontNode->getAttribute( "size" )->getInt( );
    string littleFontFilename = littleFontNode->getChildElement( )->getString( );
    m_littleFont = Font::createFont( littleFontFilename, "", 0, littleFontSize );

    XMLNode *bigFontNode = getXML( )->getRoot( )->getChildElement( "common" )->getChildElement( "fonts" )->getChildElement( "big" );
    int bigFontSize = bigFontNode->getAttribute( "size" )->getInt( );
    string bigFontFilename = bigFontNode->getChildElement( )->getString( );
    m_bigFont = Font::createFont( bigFontFilename, "", 0, bigFontSize );

    string hudFilename = getXML( )->getRoot( )->getChildElement( "common" )->getChildElement( "hud" )->getChildElement( )->getString( );
    m_hud = Texture::createTexture( false, hudFilename );

    string detailFilename = getXML( )->getRoot( )->getChildElement( "common" )->getChildElement( "detail" )->getChildElement( )->getString( );
    m_detail = Texture::createTexture( false, detailFilename );

    m_tickTime = getXML( )->getRoot( )->getChildElement( "common" )->getChildElement( "tickTime" )->getChildElement( )->getFloat( );
    
    XMLNode *soundsNode = getXML( )->getRoot( )->getChildElement( "common" )->getChildElement( "sounds" );
    string clickSelectFilename = soundsNode->getChildElement( "clickSelect" )->getChildElement( )->getString( );
    m_clickSelect = Sound::createSound( clickSelectFilename );
    string clickValidateFilename = soundsNode->getChildElement( "clickValidate" )->getChildElement( )->getString( );
    m_clickValidate = Sound::createSound( clickValidateFilename );
    string goFilename = soundsNode->getChildElement( "go" )->getChildElement( )->getString( );
    m_go = Sound::createSound( goFilename );
    string deathFilename = soundsNode->getChildElement( "death" )->getChildElement( )->getString( );
    m_death = Sound::createSound( deathFilename );
    string jumpFilename = soundsNode->getChildElement( "jump" )->getChildElement( )->getString( );
    m_jump = Sound::createSound( jumpFilename );

    // tile speed
    XMLNode *speedNode = getXML( )->getRoot( )->getChildElement( "game" )->getChildElement( "tile" )->getChildElement( "speed" );
    m_tileSpeedSlow = speedNode->getChildElement( "slow" )->getChildElement( )->getFloat( );
    m_tileSpeedNormal = speedNode->getChildElement( "normal" )->getChildElement( )->getFloat( );
    m_tileSpeedFast = speedNode->getChildElement( "fast" )->getChildElement( )->getFloat( );
    m_tileSpeedVeryFast = speedNode->getChildElement( "veryFast" )->getChildElement( )->getFloat( );

    m_fade = Texture::createTexture( false, 1, 1 );
    m_fade->createAlpha( 0xB0, false );

    m_background = Background::createBackground( );
    m_loading = Loading::createLoading( );
    
    m_displayable = DisplayableFactory::createDisplayable( DISPLAYABLE_MENU );
}

// ---------------------------------------------------------------------------- DISPLAY UPDATE
void Application::displayUpdate( float elapsedTime )
{
    m_elapsedTime = elapsedTime;
    m_time += m_elapsedTime;
    
    RenderSystem *rs = RenderSystemManager::getRenderSystem( );
    
    if ( !m_displayable->isFinished( ) )
    {
        m_displayable->displayUpdate( );
    }
    else
    {
        Displayable *newDisplayable = 0;

        switch( m_displayable->getDisplayableType( ) )
        {
        case DISPLAYABLE_MENU:
            {
                Ship *shipPlayer1 = ( ( Menu *) m_displayable )->getShipPlayer1( );
                Ship *shipPlayer2 = ( ( Menu *) m_displayable )->getShipPlayer2( );

                if ( shipPlayer1 != 0 ) // at least, player 1 has to be valid
                {
                    m_level = Level::createLevel( m_levelIndex );

                    m_player1 = Player::createPlayer( shipPlayer1 );
                    m_player2 = Player::createPlayer( shipPlayer2 );

                    newDisplayable = DisplayableFactory::createDisplayable( DISPLAYABLE_GAME );
                }
            }
            break;

        case DISPLAYABLE_GAME:
            {
                assert( m_level );
                delete m_level;
                m_level = 0;

                bool lost = false;
                
                if ( m_player1 && m_player1->hasLost( ) )
                    lost = true;

                if ( m_player2 && m_player2->hasLost( ) )
                    lost = true;

                if ( lost )
                {
                    if ( m_player1 )
                    {
                        delete m_player1;
                        m_player1 = 0;
                    }
                    
                    if ( m_player2 )
                    {
                        delete m_player2;
                        m_player2 = 0;
                    }

                    newDisplayable = DisplayableFactory::createDisplayable( DISPLAYABLE_MENU );
                }
                else
                {
                    m_levelIndex++;
                    m_level = Level::createLevel( m_levelIndex );

                    if ( m_player1 )
                        m_player1->reset( );
                    
                    if ( m_player2 )
                        m_player2->reset( );

                    newDisplayable = DisplayableFactory::createDisplayable( DISPLAYABLE_GAME );
                }
            }
            break;
        }

        delete m_displayable;

        if ( newDisplayable )
            m_displayable = newDisplayable;
        else
        {
            m_displayable = 0;

            rs->exit( );
        }
    }
}

// ---------------------------------------------------------------------------- KEY PRESS
void Application::keyPress( Key key )
{
    m_displayable->keyPress( key );
}

// ---------------------------------------------------------------------------- RELEASE
void Application::release( )
{
    if ( m_xml )
        delete m_xml;
    
    if ( m_littleFont )
        delete m_littleFont;
    
    if ( m_bigFont )
        delete m_bigFont;

    if ( m_hud )
        delete m_hud;

    if ( m_detail )
        delete m_detail;

    if ( m_clickSelect )
        delete m_clickSelect;

    if ( m_clickValidate )
        delete m_clickValidate;

    if ( m_death )
        delete m_death;

    if ( m_go )
        delete m_go;

    if ( m_jump )
        delete m_jump;

    if ( m_fade )
        delete m_fade;

    if ( m_player1 )
        delete m_player1;
    
    if ( m_player2 )
        delete m_player2;
    
    for ( unsigned int i = 0; i < m_ships.size( ); ++i )
        delete m_ships[ i ];
    
    if ( m_level )
        delete m_level;

    if ( m_background )
        delete m_background;

    if ( m_loading )
        delete m_loading;

    if ( m_displayable )
        delete m_displayable;

    delete m_resourceReader;

    delete m_soundSystem;
}

// ---------------------------------------------------------------------------- GET LANGUAGE NODE
XMLNode *Application::getLanguageNode( )
{
    switch( m_languageType )
    {
    case LANGUAGE_FRENCH:
        return getXML( )->getRoot( )->getChildElement( "languages" )->getChildElement( "french" );

    case LANGUAGE_ENGLISH:
        return getXML( )->getRoot( )->getChildElement( "languages" )->getChildElement( "english" );
    }

    return 0;
}

// ---------------------------------------------------------------------------- GET TILE SPEED
float Application::getTileSpeed( TileType tileType )
{
    switch( tileType )
    {
    case TILE_SLOW:         return m_tileSpeedSlow;
    case TILE_NORMAL:       return m_tileSpeedNormal;
    case TILE_FAST:         return m_tileSpeedFast;
    case TILE_VERYFAST:     return m_tileSpeedVeryFast;
    }

    return 0.0f;
}