//  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.

#include "modes/follow_the_leader.hpp"

#include "audio/music_manager.hpp"
#include "challenges/unlock_manager.hpp"
#include "config/user_config.hpp"
#include "graphics/camera.hpp"
#include "items/powerup_manager.hpp"
#include "karts/abstract_kart.hpp"
#include "states_screens/race_gui_base.hpp"
#include "tracks/track.hpp"
#include "utils/translation.hpp"

#include <ISceneManager.h>

//-----------------------------------------------------------------------------
FollowTheLeaderRace::FollowTheLeaderRace() : LinearWorld()
{
    // We have to make sure that no kart finished the set number of laps
    // in a FTL race (since otherwise its distance will not be computed
    // correctly, and as a result e.g. a leader might suddenly fall back
    // after crossing the start line
    race_manager->setNumLaps(99999);

    m_leader_intervals = stk_config->m_leader_intervals;
    for(unsigned int i=0; i<m_leader_intervals.size(); i++)
        m_leader_intervals[i] +=
            stk_config->m_leader_time_per_kart*race_manager->getNumberOfKarts();
    m_use_highscores   = false;  // disable high scores
    setClockMode(WorldStatus::CLOCK_COUNTDOWN, m_leader_intervals[0]);
    m_is_over_delay = 5.0f;
}

//-----------------------------------------------------------------------------
/** Called immediately after the constructor. Here functions that use
 *  World::getWorld() as well as overridden functions.
 */
void FollowTheLeaderRace::init()
{
    LinearWorld::init();
    getKart(0)->setOnScreenText(_("Leader"));
}

#if 0
#pragma mark -
#pragma mark clock events
#endif
//-----------------------------------------------------------------------------
FollowTheLeaderRace::~FollowTheLeaderRace()
{
}

//-----------------------------------------------------------------------------
/** Called just before a race is started.
 */
void FollowTheLeaderRace::reset()
{
    LinearWorld::reset();
    m_leader_intervals.clear();
    m_leader_intervals    = stk_config->m_leader_intervals;
    for(unsigned int i=0; i<m_leader_intervals.size(); i++)
        m_leader_intervals[i] +=
            stk_config->m_leader_time_per_kart*race_manager->getNumberOfKarts();
    WorldStatus::setClockMode(WorldStatus::CLOCK_COUNTDOWN,
                              m_leader_intervals[0]);
                              
    m_is_over_delay = 2.0f;
}   // reset

//-----------------------------------------------------------------------------
/** Returns the original time at which the countdown timer started. This is
 *  used by the race_gui to display the music credits in FTL mode correctly.
 */
float FollowTheLeaderRace::getClockStartTime()
{
    return m_leader_intervals[0];
}   // getClockStartTime

//-----------------------------------------------------------------------------
/** Called when a kart must be eliminated.
 */
void FollowTheLeaderRace::countdownReachedZero()
{
    if(m_leader_intervals.size()>1)
        m_leader_intervals.erase(m_leader_intervals.begin());
    WorldStatus::setTime(m_leader_intervals[0]);

    // If the leader kart is not the first kart, remove the first
    // kart, otherwise remove the last kart.
    int position_to_remove = m_karts[0]->getPosition()==1
                           ? getCurrentNumKarts() : 1;
    AbstractKart *kart = getKartAtPosition(position_to_remove);
    if(!kart || kart->isEliminated())
    {
        Log::error("[FTL]", "Problem with removing leader: position %d not found",
                position_to_remove);
        for(unsigned int i=0; i<m_karts.size(); i++)
        {
            Log::error("[FTL]", "kart %u: eliminated %d position %d",
                    i, m_karts[i]->isEliminated(), m_karts[i]->getPosition());
        }   // for i
    }  //
    else
    {
        if(UserConfigParams::m_ftl_debug)
        {
            Log::debug("[FTL", "Eliminiating kart '%s' at position %d.",
                kart->getIdent().c_str(), position_to_remove);
        }
        eliminateKart(kart->getWorldKartId());

        // In case that the kart on position 1 was removed, we have
        // to set the correct position (which equals the remaining
        // number of karts) for the removed kart, as well as recompute
        // the position for all other karts
        if(position_to_remove==1)
        {
            // We have to add 1 to the number of karts to get the correct
            // position, since the eliminated kart was already removed
            // from the value returned by getCurrentNumKarts (and we have
            // to remove the kart before we can call updateRacePosition).
            // Note that we can not call WorldWithRank::setKartPosition
            // here, since it would not properly support debugging kart
            // ranks (since this kart would get its position set again
            // in updateRacePosition). We only set the rank of the eliminated
            // kart, and updateRacePosition will then call setKartPosition
            // for the now eliminated kart.
            kart->setPosition(getCurrentNumKarts()+1);
            updateRacePosition();
        }
        // Time doesn't make any sense in FTL (and it is not displayed)
        kart->finishedRace(-1.0f);

        // Move any camera for this kart to the leader, facing backwards,
        // so that the eliminated player has something to watch.
        if (race_manager->getNumPlayers() > 1)
        {
            for(unsigned int i=0; i<Camera::getNumCameras(); i++)
            {
                Camera *camera = Camera::getCamera(i);
                if(camera->getKart()==kart)
                {
                    camera->setMode(Camera::CM_LEADER_MODE);
                    camera->setKart(getKart(0));
                }
            }   // for i<number of cameras
        }
    }   // if kart to eliminate exists

    // almost over, use fast music
    if(getCurrentNumKarts()==3)
    {
        music_manager->switchToFastMusic();
    }

    if (isRaceOver())
    {
        // Handle special FTL situation: the leader is kart number 3 when
        // the last kart gets eliminated. In this case kart on position 1
        // is eliminated, and the kart formerly on position 2 is on
        // position 1, the leader now position 2. In this case the kart
        // on position 1 would get more points for this victory. So if
        // this is the case, change the position
        if(m_karts[0]->getPosition()!=1)
        {
            // Adjust the position of all still driving karts that
            // are ahead of the leader by +1, and move the leader
            // to position 1.
            for (unsigned int i=1; i<m_karts.size(); i++)
            {
                if(!m_karts[i]->hasFinishedRace() &&
                    !m_karts[i]->isEliminated()   &&
                    m_karts[i]->getPosition()<m_karts[0]->getPosition())
                {
                        m_karts[i]->setPosition(m_karts[i]->getPosition()+1);
                }
            }
            m_karts[0]->setPosition(1);
        }

        // Mark all still racing karts to be finished.
        for (unsigned int n=0; n<m_karts.size(); n++)
        {
            if (!m_karts[n]->isEliminated() &&
                !m_karts[n]->hasFinishedRace())
            {
                m_karts[n]->finishedRace(getTime());
            }
        }
    }
    // End of race is detected from World::updateWorld()

}   // countdownReachedZero

//-----------------------------------------------------------------------------
/** The follow the leader race is over if there is only one kart left (plus
 *  the leader), or if all (human) players have been eliminated.
 */
bool FollowTheLeaderRace::isRaceOver()
{
    bool is_over = (getCurrentNumKarts()==2 || getCurrentNumPlayers()==0);
    if (is_over)
    {
        if (m_is_over_delay < 0.0f)
        {
            return true;
        }
        else
        {
            m_is_over_delay -= GUIEngine::getLatestDt();
            return false;
        }
    }
    else
    {
        return false;
    }
}   // isRaceOver

//-----------------------------------------------------------------------------
/** Returns the internal identifier for this kind of race.
 */
const std::string& FollowTheLeaderRace::getIdent() const
{
    return IDENT_FTL;
}   // getIdent

//-----------------------------------------------------------------------------
/** Sets the title for all karts that is displayed in the icon list. In
 *  this mode the title for the first kart is set to 'leader'.
 */
void FollowTheLeaderRace::getKartsDisplayInfo(
                           std::vector<RaceGUIBase::KartIconDisplayInfo> *info)
{
    LinearWorld::getKartsDisplayInfo(info);
    (*info)[0].special_title = _("Leader");
}   // getKartsDisplayInfo
