#ifdef W32_BCC551
  /* dont include unistd.h, but dir.h for windoof */
  #include <dir.h>
#else
  #include <unistd.h>
#endif

#include "caresources.h"
#include "catrophy.h"
#include "caloadingscreen.h"
#include "caimagemanipulation.h"

CAResources* CAResources::theOneAndOnlyResource=0;


/** Gets the one and only Resources-Object.
    Creates a new one on first call.
 */
CAResources*
CAResources::getResources() {
    if(theOneAndOnlyResource==0) {
        theOneAndOnlyResource = new CAResources;
        theOneAndOnlyResource->load();
    }
    return theOneAndOnlyResource;
}


/** Constructor.
 */
CAResources::CAResources() {}


/** Destructor.
*/
CAResources::~CAResources() {
    delete misc_cross;
    delete misc_light;
    delete misc_hitpoint;
    delete misc_gunfire;
    delete misc_carfire;
    delete misc_checkflag;
    delete misc_fog;
    delete misc_dust;
    delete misc_info;
    delete misc_caution;

    delete goody_turbo;
    delete goody_life;
    delete goody_money;
    delete goody_bullets;

    delete font_normal_11_white;
    delete font_normal_14_white;
    delete font_normal_22_white;
    delete font_normal_22_gray;
    delete font_lcd_13_green;

    delete menu_bg;
    delete menu_cursorani;
    delete menu_bar;

    delete panel_label;
    delete panel_button;
    delete panel_life;
    delete panel_infoview;
    delete panel_speed;
    delete panel_turbolabel;
    delete panel_turbo;
    delete panel_death;

    delete gui_edge1;
    delete gui_edge2;
    delete gui_edge3;
    delete gui_edge4;
    delete gui_border1;
    delete gui_border2;
    delete gui_border3;
    delete gui_border4;
    delete gui_button;
    delete gui_arrow_l;
    delete gui_arrow_r;
    delete gui_arrow_t;
    delete gui_arrow_b;

#ifndef CA_LIGHTVERSION
    delete sound_horn;
    delete sound_menu;
    delete sound_selector;
    delete sound_slide;
    delete sound_crash;
    delete sound_engine;
    delete sound_goody_money;
    delete sound_goody_bullets;
    delete sound_goody_turbo;
    delete sound_goody_fogbomb;
    delete sound_goody_life;

    delete sound_shoot;
    delete sound_fogbomb;
    delete sound_fire;

    delete sound_background01;
#endif

    delete effectCrash;
    delete effectSlide;
    delete effectEngine;
    delete effectHorn;
    delete effectLight;
    delete effectMenu;
    delete effectSelector;
    delete effectGoodyMoney;
    delete effectGoodyBullets;
    delete effectGoodyTurbo;
    delete effectGoodyFogbomb;
    delete effectGoodyLife;
    delete effectShoot;
    delete effectFogBomb;
    delete effectFire;
    delete effectBackground01;

    for( int i=0; i<CA_FPR; ++i ) {
        delete dust[i];
    }

    delete resources;
}


/** Load all resources.
*/
void
CAResources::load() {
    // Try to load resource file (resources.dat):
    //
    chdir(PKGDATADIR);

    try {
        resources = new CL_ResourceManager( "resources.dat", true );
    }

    // Just use the resource config file (resources.scr) if there's no compiled .dat:
    //
    catch (CL_Error err) {
        resources = new CL_ResourceManager( "resources.scr", false );
    }

    // Load info frame for showing loading status:
    //
    gui_loading = CL_Surface::load( "resources/gui/loading", resources );
    gui_progressbar = CL_Surface::load( "resources/gui/progressbar", resources );

    // Show progress:
    //
    CA_APP->loading.begin();

    // Load fonts:
    //
    font_normal_11_white = CL_Font::load( "resources/fonts/normal_11_white", resources );
    font_normal_14_white = CL_Font::load( "resources/fonts/normal_14_white", resources );
    font_normal_22_white = CL_Font::load( "resources/fonts/normal_22_white", resources );
    font_normal_22_gray = CL_Font::load( "resources/fonts/normal_22_gray", resources );
    font_lcd_13_green = CL_Font::load( "resources/fonts/lcd_13_green", resources );

    CA_APP->loading.setProgress( 15 );

    // Load sounds:
    //

    sound_horn = CL_SoundBuffer::load( "resources/sounds/horn", resources );
    sound_menu = CL_SoundBuffer::load( "resources/sounds/menu", resources );
    sound_selector = CL_SoundBuffer::load( "resources/sounds/selector", resources );
    sound_slide = CL_SoundBuffer::load( "resources/sounds/slide", resources );
    sound_crash = CL_SoundBuffer::load( "resources/sounds/crash", resources );
    sound_engine = CL_SoundBuffer::load( "resources/sounds/engine", resources );
    sound_light = CL_SoundBuffer::load( "resources/sounds/light", resources );
    sound_goody_money = CL_SoundBuffer::load( "resources/sounds/goody_money", resources );
    sound_goody_bullets = CL_SoundBuffer::load( "resources/sounds/goody_bullets", resources );
    sound_goody_turbo = CL_SoundBuffer::load( "resources/sounds/goody_turbo", resources );
    sound_goody_fogbomb = CL_SoundBuffer::load( "resources/sounds/goody_fogbomb", resources );
    sound_goody_life = CL_SoundBuffer::load( "resources/sounds/goody_life", resources );
    sound_shoot = CL_SoundBuffer::load( "resources/sounds/shoot", resources );
    sound_fogbomb = CL_SoundBuffer::load( "resources/sounds/fogbomb", resources );
    sound_fire = CL_SoundBuffer::load( "resources/sounds/fire", resources );
    sound_background01 = CL_SoundBuffer::load( "resources/sounds/background01", resources );

    CA_APP->loading.setProgress( 25 );

    effectCrash  = new CASoundEffect( sound_crash, 2 );
    effectSlide  = new CASoundEffect( sound_slide, 1 );
    effectEngine = new CASoundEffect( sound_engine, 1 );
    effectHorn   = new CASoundEffect( sound_horn, 2 );
    effectLight  = new CASoundEffect( sound_light, 2 );
    effectMenu   = new CASoundEffect( sound_menu, 4 );
    effectSelector= new CASoundEffect( sound_selector, 10 );
    effectGoodyMoney  = new CASoundEffect( sound_goody_money, 5 );
    effectGoodyBullets  = new CASoundEffect( sound_goody_bullets, 5 );
    effectGoodyTurbo  = new CASoundEffect( sound_goody_turbo, 5 );
    effectGoodyFogbomb  = new CASoundEffect( sound_goody_fogbomb, 10 );
    effectGoodyLife  = new CASoundEffect( sound_goody_life, 5 );
    effectShoot  = new CASoundEffect( sound_shoot, 3 );
    effectFogBomb  = new CASoundEffect( sound_fogbomb, 10 );
    effectFire  = new CASoundEffect( sound_fire, 10 );
    effectBackground01  = new CASoundEffect( sound_background01, 1 );

    CA_APP->loading.setProgress( 30 );


    // Load generic sprites:
    //
    misc_cross = CL_Surface::load( "resources/misc/cross", resources );
    misc_light = CL_Surface::load( "resources/misc/light", resources );
    misc_hitpoint = CL_Surface::load( "resources/misc/hitpoint", resources );
    misc_gunfire = CL_Surface::load( "resources/misc/gunfire", resources );
    misc_carfire = CL_Surface::load( "resources/misc/carfire", resources );
    misc_checkflag = CL_Surface::load( "resources/misc/checkflag", resources );
    misc_fog = CL_Surface::load( "resources/misc/fog", resources );
    misc_dust = CL_Surface::load( "resources/misc/dust", resources );
    misc_info = CL_Surface::load( "resources/misc/info", resources );
    misc_caution = CL_Surface::load( "resources/misc/caution", resources );


    // Load player effect sprites (dust, ...)
    //

    CL_Surface* tmp = CL_Surface::load( "resources/cars/dust", resources );
    for( int i=0; i<CA_FPR; ++i ) {
        dust[i] = CAImageManipulation::rotate( tmp, (float)i/CA_FPR*360.0, true );
    }


    CA_APP->loading.setProgress( 35 );

    // Load Goodies:
    //
    goody_turbo = CL_Surface::load( "resources/goody/turbo", resources );
    goody_life  = CL_Surface::load( "resources/goody/life", resources );
    goody_money = CL_Surface::load( "resources/goody/money", resources );
    goody_bullets = CL_Surface::load( "resources/goody/bullets", resources );
    goody_fogbomb = CL_Surface::load( "resources/goody/fogbomb", resources );

    // Menu things:
    //
    menu_bg = CL_Surface::load( "resources/menu/bg", resources );
    menu_cursorani = CL_Surface::load( "resources/menu/cursorani", resources );
    menu_bar = CL_Surface::load( "resources/menu/bar", resources );

    CA_APP->loading.setProgress( 40 );

    // Panel resources:
    //
    panel_label = CL_Surface::load( "resources/panel/label", resources );
    panel_button = CL_Surface::load( "resources/panel/button", resources );
    panel_life = CL_Surface::load( "resources/panel/life", resources );
    panel_infoview = CL_Surface::load( "resources/panel/infoview", resources );
    panel_speed = CL_Surface::load( "resources/panel/speed", resources );
    panel_turbolabel = CL_Surface::load( "resources/panel/turbolabel", resources );
    panel_turbo = CL_Surface::load( "resources/panel/turbo", resources );
    panel_death = CL_Surface::load( "resources/panel/death", resources );

    CA_APP->loading.setProgress( 45 );

    // GUI resources:
    //
    gui_edge1 = CL_Surface::load( "resources/gui/edge1", resources );
    gui_edge2 = CL_Surface::load( "resources/gui/edge2", resources );
    gui_edge3 = CL_Surface::load( "resources/gui/edge3", resources );
    gui_edge4 = CL_Surface::load( "resources/gui/edge4", resources );
    gui_border1 = CL_Surface::load( "resources/gui/border1", resources );
    gui_border2 = CL_Surface::load( "resources/gui/border2", resources );
    gui_border3 = CL_Surface::load( "resources/gui/border3", resources );
    gui_border4 = CL_Surface::load( "resources/gui/border4", resources );
    gui_button = CL_Surface::load( "resources/gui/button", resources );
    gui_arrow_l = CL_Surface::load( "resources/gui/arrow_l", resources );
    gui_arrow_r = CL_Surface::load( "resources/gui/arrow_r", resources );
    gui_arrow_t = CL_Surface::load( "resources/gui/arrow_t", resources );
    gui_arrow_b = CL_Surface::load( "resources/gui/arrow_b", resources );

    CA_APP->loading.setProgress( 50 );
}



/** Updates the frameCounter for the given surface so it shows
    fps frames per second.
    \return true if the zero frame was passed during animation. Otherwise false.
*/
bool
CAResources::advanceAnimation( float* frameCounter,
                               CL_Surface* surface,
                               float fps,
                               AnimationMode mode ) {
    return advanceAnimation( frameCounter, surface->get_num_frames(), fps, mode );
}



/** Updates the frameCounter for the given maximal number of frames so it shows
    fps frames per second.
*/
bool
CAResources::advanceAnimation( float* frameCounter,
                               int numFrames,
                               float fps,
                               AnimationMode mode ) {
    bool ret = false;
    static bool fw = true;  // Forward? for revolving mode
    float amount = (fps / CA_APP->framesPerSec);

    switch( mode ) {
    case Forward:
        *frameCounter += amount;
        if( *frameCounter>=(float)numFrames ) {
            *frameCounter -= (float)numFrames;
            ret = true;
        }
        break;

    case Backward:
        *frameCounter -= amount;
        if( *frameCounter<0.0 ) {
            *frameCounter += (float)(numFrames);
            ret = true;
        }
        break;

    case Revolving:
        *frameCounter += (fw ? amount : -amount);

        if( *frameCounter>=(float)numFrames ) {
            *frameCounter -= amount;
            fw = false;
            ret = true;
        }
        if( *frameCounter<0.0 ) {
            *frameCounter += amount;
            fw = true;
            ret = true;
        }
        break;
    }

    return ret;
}


