//  $Id$
//
//  SuperTuxKart - a fun racing game with go-kart
//  Copyright (C) 2006 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 2
//  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 <iostream>

#include "loader.hpp"
#include "track_manager.hpp"
#include "race_setup.hpp"
#include "screen_manager.hpp"
#include "start_screen.hpp"
#include "world_screen.hpp"
#include "empty_screen.hpp"
#include "kart_properties_manager.hpp"
#include "race_manager.hpp"
#include "gui/menu_manager.hpp"

RaceManager* race_manager= NULL;


void
RaceMode::next()
{
    exit_race();
}

//-----------------------------------------------------------------------------
void
RaceMode::exit_race()
{
    startScreen = new StartScreen();
    screen_manager->setScreen(startScreen);
}

//=============================================================================
GrandPrixMode::GrandPrixMode(const std::vector<std::string>& players_,
                             const CupData& cup_,
                             RaceDifficulty difficulty_,
                             int numKarts_)
: m_difficulty(difficulty_), m_num_karts(numKarts_), m_players(players_),
    m_cup(cup_), m_track(0)
{

    std::vector<std::string> kart_names;
    kart_names.resize(m_num_karts);

    const int NUM_PLAYERS = m_players.size();
    for(int i = 0; i < NUM_PLAYERS; ++i)
    {
        /*Players position is behind the AI in the first race*/
        kart_names[m_num_karts-1 - i] = m_players[NUM_PLAYERS - 1 - i];
    }

    kart_properties_manager->fillWithRandomKarts(kart_names);

    const int NUM_AI_KARTS = m_num_karts - NUM_PLAYERS;
    //Add the AI karts
    for(int i = 0; i < NUM_AI_KARTS; ++i)
        m_karts.push_back(KartStatus(kart_names[i], 0, i, NUM_PLAYERS));
    //Add the player karts
    for(int i = 0; i < NUM_PLAYERS; ++i)
        m_karts.push_back(KartStatus(kart_names[i+NUM_AI_KARTS], 0, i+NUM_AI_KARTS, i));
}

//-----------------------------------------------------------------------------
void
GrandPrixMode::start_race(int n)
{
    RaceSetup raceSetup;
    raceSetup.m_mode       = RaceSetup::RM_GRAND_PRIX;
    raceSetup.m_difficulty = m_difficulty;
    raceSetup.m_num_laps    = 2;
    raceSetup.m_track      = m_cup.m_tracks[n];
    raceSetup.m_karts.resize(m_karts.size());
    raceSetup.m_players.resize(m_players.size());
    raceSetup.setHerringStyle(m_cup.getHerringStyle());


    for(int i = 0; i < int(m_karts.size()); ++i)
    {
        raceSetup.m_karts[m_karts[i].prev_finish_pos] = m_karts[i].ident;
        if (m_karts[i].player < int(m_players.size()))
        {
            raceSetup.m_players[m_karts[i].player] = i;
        }
    }

    screen_manager->setScreen(new WorldScreen(raceSetup));
}

//-----------------------------------------------------------------------------
void
GrandPrixMode::start()
{
    start_race(m_track);
}

//-----------------------------------------------------------------------------
void
GrandPrixMode::next()
{
    m_track += 1;
    if (m_track < int(m_cup.m_tracks.size()))
    {
        start_race(m_track);

    }
    else
    {
        exit_race();
    }
}

//-----------------------------------------------------------------------------
void
GrandPrixMode::exit_race()
{
    if (m_track < int(m_cup.m_tracks.size()))
    {
        RaceMode::exit_race();
    }
    else
    {
        menu_manager->switchToGrandPrixEnding();
    }
}

//=============================================================================
QuickRaceMode::QuickRaceMode(const std::string& track_,
                             const std::vector<std::string>& players_,
                             RaceDifficulty difficulty_,
                             int numKarts_, int numLaps_)
        : m_track(track_), m_players(players_), m_difficulty(difficulty_),
        m_num_karts(numKarts_), m_num_laps(numLaps_)
{}

//-----------------------------------------------------------------------------
void
QuickRaceMode::start()
{
    RaceSetup raceSetup;

    raceSetup.m_mode       = RaceSetup::RM_QUICK_RACE;
    raceSetup.m_difficulty = m_difficulty;
    raceSetup.m_track      = m_track;
    raceSetup.m_num_laps    = m_num_laps;
    raceSetup.m_karts.resize(m_num_karts);

    const int FIRST_PLAYER = m_num_karts - m_players.size();
    for(int i = 0; i < int(m_players.size()); ++i)
    {
        raceSetup.m_karts[FIRST_PLAYER + i] = m_players[i]; // Players starts last in the race
        raceSetup.m_players.push_back(FIRST_PLAYER + i);
    }

    kart_properties_manager->fillWithRandomKarts(raceSetup.m_karts);

    screen_manager->setScreen(new WorldScreen(raceSetup));
}

//=============================================================================
TimeTrialMode::TimeTrialMode(const std::string& track_, const std::string& kart_,
                             const int& numLaps_)
        : m_track(track_), m_kart(kart_), m_num_laps(numLaps_)
{}

//-----------------------------------------------------------------------------
void
TimeTrialMode::start()
{
    RaceSetup raceSetup;

    raceSetup.m_mode       = RaceSetup::RM_TIME_TRIAL;
    raceSetup.m_track      = m_track;
    raceSetup.m_num_laps   = m_num_laps;
    raceSetup.m_difficulty = RD_HARD;

    raceSetup.m_karts.push_back(m_kart);
    raceSetup.m_players.push_back(0);

    screen_manager->setScreen(new WorldScreen(raceSetup));
}

//=============================================================================
RaceManager::RaceManager()
{
    m_mode       = 0;
    m_num_karts  = 6;
    m_difficulty = RD_MEDIUM;
    m_race_mode  = RaceSetup::RM_QUICK_RACE;
    m_track      = "race";

    m_players.push_back("tuxkart");
}

//-----------------------------------------------------------------------------
RaceManager::~RaceManager()
{
    delete m_mode;
}

//-----------------------------------------------------------------------------
void RaceManager::reset()
{
    m_num_finished_karts   = 0;
    m_num_finished_players = 0;
}  // reset

//-----------------------------------------------------------------------------
void
RaceManager::setPlayerKart(int player, const std::string& kart)
{
    if (player >= 0 && player < 4)
    {
        if (player >= getNumPlayers())
            setNumPlayers(player+1);

        m_players[player] = kart;
    }
    else
    {
        fprintf(stderr, "Warning: player '%d' does not exists.\n", player);
    }
}

//-----------------------------------------------------------------------------
void
RaceManager::setNumPlayers(int num)
{
    m_players.resize(num);
    for(Players::iterator i = m_players.begin(); i != m_players.end(); ++i)
    {
        if (i->empty())
        {
            *i = "tuxkart";
        }
    }
}

//-----------------------------------------------------------------------------
void
RaceManager::start()
{
    m_num_finished_karts   = 0;
    m_num_finished_players = 0;
    delete m_mode;

    assert(m_players.size() > 0);
    switch(m_race_mode)
    {
    case RaceSetup::RM_GRAND_PRIX:
        m_mode = new GrandPrixMode(m_players, m_cup, m_difficulty, m_num_karts);
        break;
    case RaceSetup::RM_TIME_TRIAL:
        m_mode = new TimeTrialMode(m_track, m_players[0], m_num_laps);
        break;
    case RaceSetup::RM_QUICK_RACE:
        m_mode = new QuickRaceMode(m_track, m_players, m_difficulty, m_num_karts, m_num_laps);
        break;
    default:
        assert(!"Unknown game mode");
    }

    m_mode->start();
}

//-----------------------------------------------------------------------------
void
RaceManager::next()
{
    assert(m_mode);
    m_num_finished_karts   = 0;
    m_num_finished_players = 0;
    m_mode->next();
}

//-----------------------------------------------------------------------------
void
RaceManager::exit_race()
{
    m_mode->exit_race();
}

/* EOF */
