//
//  SuperTuxKart - a fun racing game with go-kart
//  Copyright (C) 2004-2015 SuperTuxKart-Team
//
//  This program is free software; you can redistribute it and/or
//  modify it under the terms of the GNU General Public License
//  as published by the Free Software Foundation; either version 3
//  of the License, or (at your option) any later version.
//
//  This program is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//  GNU General Public License for more details.
//
//  You should have received a copy of the GNU General Public License
//  along with this program; if not, write to the Free Software
//  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

#ifndef HEADER_WORLD_HPP
#define HEADER_WORLD_HPP

/**
  * \defgroup modes
  * Contains the logic for the various game modes (race, follow the leader,
  * battle, etc.)
  */

#include <vector>
#include <stdexcept>

#include "world_status.h"
#include "../maps/map.h"
#include "../states_screens/state_manager.h"
#include "../utils/random_generator.h"
#include "../game/game_manager.h"

//#include "LinearMath/btTransform.h" //bullet, not needed yet




class Map;


namespace irr
{
    namespace scene { class ISceneNode; }
}

class AbortWorldUpdateException : public std::runtime_error
{
public:
    AbortWorldUpdateException() : std::runtime_error("race abort") { };
};

/**
 *  \brief base class for all game modes
 *  This class is responsible for running the actual race. A world is created
 *  by the race manager on the start of each race (so a new world is created
 *  for each race of a Grand Prix). It creates the
 *  physics, loads the track, creates all karts, and initialises the race
 *  specific managers (ItemManager, ProjectilManager, highscores, ...).
 *  It uses the information from the race manager to get information like
 *  what and how many karts, track to load etc. This class does not really
 *  know about Grand Prixs, a GP is created
 *  It maintains the race clock, and updates all karts, herings etc. during
 *  the race.
 *  Special game modes (e.g. follow the leader) are currently integrated in
 *  this world, see e.g. updateRaceStatus where the world clock behaviour
 *  is handled differently to create the count down.
 * \ingroup modes
 */

class World : public WorldStatus
{
private:
    /** A pointer to the global world object for a race. */
    static World *m_world;

protected:

#ifdef DEBUG
    unsigned int m_magic_number;
#endif








    Map* m_map;


    /** Pointer to the race GUI. The race GUI is handled by world. */
    //RaceGUIBase *m_race_gui;

    /** The actual race gui needs to be saved when the race result gui is
        displayed since it is still needed in case of a restart, and it
        can't simply be created again (since it assumes that it can render
        to texture without having any scene nodes, but in case of a restart
        there are scene nodes). */
    //RaceGUIBase *m_saved_race_gui;

    irr::video::SColor m_clear_color;

    /** Pausing/unpausing are not done immediately, but at next udpdate. The
     *  use of this is when switching between screens : if we leave a screen
     *  that paused the game, only to go to another screen that pauses back
     *  the game, this mechanism prevents the game from moving on between
     *  the switch. */
    bool m_schedule_pause;

    /** Pausing/unpausing are not done immediately, but at next udpdate. The
     *  use of this is when switching between screens : if we leave a screen
     *  that paused the game, only to go to another screen that pauses back
     *  the game, this mechanism prevents the game from moving on between the
     *  switch. */
    bool m_schedule_unpause;

    bool m_schedule_exit_race;


    Phase m_scheduled_pause_phase;

    /** Set when the world needs to be deleted but you can't do it immediately
     * because you are e.g. within World::update()
     */
    bool m_self_destruct;



    /** Used to show weather graphical effects. */


    virtual void  onGo();
    /** Returns true if the race is over. Must be defined by all modes. */
    virtual bool  isGameEnded() = 0;
    virtual void  update(float dt);
    //virtual void  createGameGUI();
            void  updateMap(float dt);
    // ------------------------------------------------------------------------
    /** Used for AI karts that are still racing when all player kart finished.
     *  Generally it should estimate the arrival time for those karts, but as
     *  a default (useful for battle mode and ftl races) we just use the
     *  current time for this (since this is a good value for karts still
     *  around at the end of a race, and other criteria (number of lives,
     *  race position) will be used to determine the final order.
     */


public:
                    World();
    virtual        ~World();
    // Static functions to access world:
    // =================================
    // ------------------------------------------------------------------------
    /** Returns a pointer to the (singleton) world object. */
    static World*   getWorld() { return m_world; }
    // ------------------------------------------------------------------------
    /** Delete the )singleton) world object, if it exists, and sets the
      * singleton pointer to NULL. It's harmless to call this if the world
      *  has been deleted already. */
    static void     deleteWorld() { delete m_world; m_world = NULL; }
    // ------------------------------------------------------------------------
    /** Sets the pointer to the world object. This is only used by
     *  the race_manager.*/
    static void     setWorld(World *world) {m_world = world; }
    // ------------------------------------------------------------------------

    // Pure virtual functions
    // ======================

    /** Each game mode should have a unique identifier. Override
      * this method in child classes to provide it. */
    virtual const std::string& getIdent() const = 0;





    // Virtual functions
    // =================
    virtual void    init();
    //virtual void    terminateGame() OVERRIDE;
    virtual void    terminateGame();
    virtual void    reset();
    virtual void    pause(Phase phase) OVERRIDE;
    virtual void    unpause() OVERRIDE;

    virtual void    endRaceEarly() { return; }



    // ------------------------------------------------------------------------
    /** If you want to do something to karts or their graphics at the start
     *  of the race, override this. */
    // ------------------------------------------------------------------------
    /** Called whenever a kart starts a new lap. Meaningless (and won't be
     *  called) in non-laped races.
     */
    // ------------------------------------------------------------------------
    /** Called when a kart was hit by a projectile. */
    // ------------------------------------------------------------------------
    virtual void onMouseClick(int x, int y) {};

    // Other functions
    // ===============
    void            schedulePause(Phase phase);
    void            scheduleUnpause();
    void            scheduleExitRace() { m_schedule_exit_race = true; }
    void            scheduleTutorial();
    void            updateWorld(float dt);
    // ------------------------------------------------------------------------
    /** Returns a pointer to the race gui. */
    //RaceGUIBase    *getRaceGUI() const { return m_race_gui;}
    // ------------------------------------------------------------------------
    /** Returns the number of karts in the race. */
    //unsigned int    getNumKarts() const { return (unsigned int) m_karts.size(); }



    // ------------------------------------------------------------------------
    /** Returns a pointer to the track. */
    Map          *getMap() const { return m_map; }


    // ------------------------------------------------------------------------
    /** The code that draws the timer should call this first to know
     *  whether the game mode wants a timer drawn. */
    //virtual bool shouldDrawTimer() const
    //                { return isRacePhase() && getClockMode() != CLOCK_NONE; }

    // ------------------------------------------------------------------------
    /** Returns the color to clear the back buffer. */
    const irr::video::SColor& getClearColor() const { return m_clear_color; }
    // ------------------------------------------------------------------------
    /** Sets the color to use when clearing the back buffer. */
    void setClearbackBufferColor(irr::video::SColor color)
    {
        m_clear_color       = color;
    }




    // ------------------------------------------------------------------------
    void delayedSelfDestruct();
    // ------------------------------------------------------------------------
    virtual void escapePressed();



};   // World

#endif

/* EOF */
