/* $Id: multiplayer_create.cpp 19140 2007-07-26 13:04:17Z soliton $ */
/*
   Copyright (C)
   Part of the Battle for Wesnoth Project http://www.wesnoth.org

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License.
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY.

   See the COPYING file for more details.
*/

#include "global.hpp"

#include <memory>

#include "display.hpp"
#include "gettext.hpp"
#include "image.hpp"
#include "show_dialog.hpp"
#include "map_create.hpp"
#include "minimap.hpp"
#include "multiplayer_create.hpp"
#include "filesystem.hpp"
#include "log.hpp"
#include "preferences.hpp"
#include "video.hpp"
#include "serialization/string_utils.hpp"
#include "wml_separators.hpp"

namespace {
const SDL_Rect null_rect = {0, 0, 0, 0};
}

namespace mp {

create::create(display& disp, const config &cfg, chat& c, config& gamelist) :
	ui(disp, _("Create Game"), cfg, c, gamelist),

	tooltip_manager_(disp.video()),
	map_selection_(-1),
	mp_countdown_init_time_(270),
	mp_countdown_reservoir_time_(330),

	maps_menu_(disp.video(), std::vector<std::string>()),
	turns_slider_(disp.video()),
	turns_label_(disp.video(), "", font::SIZE_SMALL, font::LOBBY_COLOUR),
	countdown_game_(disp.video(), _("Time limit"), gui::button::TYPE_CHECK),
	countdown_init_time_slider_(disp.video()),
	countdown_init_time_label_(disp.video(), "", font::SIZE_SMALL, font::LOBBY_COLOUR),
	countdown_reservoir_time_slider_(disp.video()),
	countdown_reservoir_time_label_(disp.video(), "", font::SIZE_SMALL, font::LOBBY_COLOUR),
	countdown_turn_bonus_label_(disp.video(), "", font::SIZE_SMALL, font::LOBBY_COLOUR),
	countdown_turn_bonus_slider_(disp.video()),
	countdown_action_bonus_label_(disp.video(), "", font::SIZE_SMALL, font::LOBBY_COLOUR),
	countdown_action_bonus_slider_(disp.video()),
	village_gold_slider_(disp.video()),
	village_gold_label_(disp.video(), "", font::SIZE_SMALL, font::LOBBY_COLOUR),
	xp_modifier_slider_(disp.video()),
	xp_modifier_label_(disp.video(), "", font::SIZE_SMALL, font::LOBBY_COLOUR),
	name_entry_label_(disp.video(), _("Name of game:"), font::SIZE_PLUS, font::LOBBY_COLOUR),
	num_players_label_(disp.video(), "", font::SIZE_SMALL, font::LOBBY_COLOUR),
	map_size_label_(disp.video(), "", font::SIZE_SMALL, font::LOBBY_COLOUR),
	era_label_(disp.video(), _("Era:"), font::SIZE_SMALL, font::LOBBY_COLOUR),
	map_label_(disp.video(), _("Map to play:"), font::SIZE_SMALL, font::LOBBY_COLOUR),
	use_map_settings_(disp.video(), _("Use map settings"), gui::button::TYPE_CHECK),
	fog_game_(disp.video(), _("Fog Of War"), gui::button::TYPE_CHECK),
	shroud_game_(disp.video(), _("Shroud"), gui::button::TYPE_CHECK),
	observers_game_(disp.video(), _("Observers"), gui::button::TYPE_CHECK),
	cancel_game_(disp.video(), _("Cancel")),
	launch_game_(disp.video(), _("OK")),
	regenerate_map_(disp.video(), _("Regenerate")),
	generator_settings_(disp.video(), _("Settings...")),
	era_combo_(disp, std::vector<std::string>()),
	vision_combo_(disp, std::vector<std::string>()),
	name_entry_(disp.video(), 32),
	minimap_restorer_(NULL),
	minimap_rect_(null_rect),
	generator_(NULL)
{
	//build the list of scenarios to play

	//add the 'load game' option
	std::string markup_txt = "`~";
	std::string help_sep = " ";
	help_sep[0] = HELP_STRING_SEPARATOR;
	std::string menu_help_str = help_sep + _("Load Game");
	map_options_.push_back(markup_txt + _("Load Game") + std::string("...") + menu_help_str);

	//user maps
	get_files_in_dir(get_user_data_dir() + "/editor/maps",&user_maps_,NULL,FILE_NAME_ONLY);

	for(unsigned int i = 0; i < user_maps_.size(); i++)
	{
		menu_help_str = help_sep + user_maps_[i];
		map_options_.push_back(user_maps_[i] + menu_help_str);
	}

	//standard maps
	const config::child_list& levels = cfg.get_children("multiplayer");
	for(config::child_list::const_iterator j = levels.begin(); j != levels.end(); ++j)
	{
		if ( ((*j)->values.find("allow_new_game") == (*j)->values.end())
			|| utils::string_bool((**j)["allow_new_game"],true))
		{
			menu_help_str = help_sep + ((**j)["name"]);
			map_options_.push_back(((**j)["name"]) + menu_help_str);
		}
	}

	//create the scenarios menu
	maps_menu_.set_items(map_options_);
	if (size_t(preferences::map()) < map_options_.size())
		maps_menu_.move_selection(preferences::map());
	maps_menu_.set_numeric_keypress_selection(false);

	turns_slider_.set_min(20);
	turns_slider_.set_max(100);
	turns_slider_.set_value(preferences::turns());
	turns_slider_.set_help_string(_("The maximum number of turns the game can last"));

	countdown_game_.set_check(preferences::countdown());
	countdown_game_.set_help_string(_("Enables user time limit"));

	countdown_init_time_slider_.set_min(0);
	countdown_init_time_slider_.set_max(1500);
	countdown_init_time_slider_.set_increment(30);
	countdown_init_time_slider_.set_value(preferences::countdown_init_time());
	countdown_init_time_slider_.set_help_string(_("Longest time allowed for first turn (seconds)"));

	countdown_reservoir_time_slider_.set_min(30);
	countdown_reservoir_time_slider_.set_max(1500);
	countdown_reservoir_time_slider_.set_increment(30);
	countdown_reservoir_time_slider_.set_value(preferences::countdown_reservoir_time());
	countdown_reservoir_time_slider_.set_help_string(_("Longest time possible for any turn (seconds)"));

	countdown_turn_bonus_slider_.set_min(10);
	countdown_turn_bonus_slider_.set_max(300);
	countdown_turn_bonus_slider_.set_increment(5);
	countdown_turn_bonus_slider_.set_value(preferences::countdown_turn_bonus());
	countdown_turn_bonus_slider_.set_help_string(_("Time for general tasks each turn (seconds)"));

	countdown_action_bonus_slider_.set_min(0);
	countdown_action_bonus_slider_.set_max(30);
	countdown_action_bonus_slider_.set_increment(1);
	countdown_action_bonus_slider_.set_value(preferences::countdown_action_bonus());
	countdown_action_bonus_slider_.set_help_string(_("Time for each attack, recruit, and capture"));

	village_gold_slider_.set_min(1);
	village_gold_slider_.set_max(5);
	village_gold_slider_.set_value(preferences::village_gold());
	village_gold_slider_.set_help_string(_("The amount of income each village yields per turn"));
	xp_modifier_slider_.set_min(30);
	xp_modifier_slider_.set_max(200);
	xp_modifier_slider_.set_value(preferences::xp_modifier());
	xp_modifier_slider_.set_increment(10);
	xp_modifier_slider_.set_help_string(_("The amount of experience a unit needs to advance"));

	use_map_settings_.set_check(preferences::use_map_settings());
	use_map_settings_.set_help_string(_("Use scenario specific settings"));

	fog_game_.set_check(preferences::fog());
	fog_game_.set_help_string(_("Enemy units cannot be seen unless they are in range of your units"));

	shroud_game_.set_check(preferences::shroud());
	shroud_game_.set_help_string(_("The map is unknown until your units explore it"));

	observers_game_.set_check(preferences::allow_observers());
	observers_game_.set_help_string(_("Allow users who are not playing to watch the game"));

	// The possible vision settings
	std::vector<std::string> vision_types;
	vision_types.push_back(_("Share View"));
	vision_types.push_back(_("Share Maps"));
	vision_types.push_back(_("Share None"));
	vision_combo_.set_items(vision_types);
	vision_combo_.set_selected(0);

	// The possible eras to play
	const config::child_list& era_list = cfg.get_children("era");
	std::vector<std::string> eras;
	for(config::child_list::const_iterator er = era_list.begin(); er != era_list.end(); ++er) {
		eras.push_back((**er)["name"]);
	}
	if(eras.empty()) {
		gui::show_dialog(disp, NULL, "", _("No multiplayer sides."), gui::OK_ONLY);
		std::cerr << "ERROR: no eras found\n";
		throw config::error(_("No eras found"));
	}
	era_combo_.set_items(eras);

	if (size_t(preferences::era()) < eras.size()) {
		era_combo_.set_selected(preferences::era());
	} else {
		era_combo_.set_selected(0);
	}


	utils::string_map i18n_symbols;
	i18n_symbols["login"] = preferences::login();
	name_entry_.set_text(vgettext("$login's game", i18n_symbols));

	gamelist_updated();
}

create::~create()
{
	get_parameters();

	//Save values for next game
	preferences::set_allow_observers(parameters_.allow_observers);
	preferences::set_use_map_settings(parameters_.use_map_settings);
	preferences::set_fog(parameters_.fog_game);
	preferences::set_shroud(parameters_.shroud_game);
	preferences::set_turns(parameters_.num_turns);
	preferences::set_countdown(parameters_.mp_countdown);
	preferences::set_countdown_init_time(parameters_.mp_countdown_init_time);
	preferences::set_countdown_turn_bonus(parameters_.mp_countdown_turn_bonus);
	preferences::set_countdown_reservoir_time(parameters_.mp_countdown_reservoir_time);
	preferences::set_countdown_action_bonus(parameters_.mp_countdown_action_bonus);
	preferences::set_village_gold(parameters_.village_gold);
	preferences::set_xp_modifier(parameters_.xp_modifier);
	preferences::set_era(era_combo_.selected()); // FIXME: may be broken if new eras are added
	preferences::set_map(map_selection_);
	preferences::set_turns(turns_slider_.value());
}

create::parameters& create::get_parameters()
{
	const config::child_list& era_list = game_config().get_children("era");
	const int turns = turns_slider_.value() < turns_slider_.max_value() ?
		turns_slider_.value() : -1;

	const int mp_countdown_turn_bonus_val = countdown_turn_bonus_slider_.value() <= countdown_turn_bonus_slider_.max_value() ?
		countdown_turn_bonus_slider_.value() : -1;
	const int mp_countdown_action_bonus_val = countdown_action_bonus_slider_.value() <= countdown_action_bonus_slider_.max_value() ?
		countdown_action_bonus_slider_.value() : -1;
	const int mp_countdown_reservoir_time_val = countdown_reservoir_time_slider_.value() <= countdown_reservoir_time_slider_.max_value() ?
		countdown_reservoir_time_slider_.value() : -1;
	int mp_countdown_init_time_val = countdown_init_time_slider_.value() <= countdown_init_time_slider_.max_value() ?
		countdown_init_time_slider_.value() : -1;
	if(mp_countdown_reservoir_time_val > 0 && mp_countdown_init_time_val > mp_countdown_reservoir_time_val)
		mp_countdown_init_time_val = mp_countdown_reservoir_time_val;

	// Updates the values in the "parameters_" member to match the values
	// selected by the user with the widgets:
	parameters_.name = name_entry_.text();
	if (size_t(era_combo_.selected()) >= era_list.size()) {
		throw config::error(_("Invalid era selected"));
	}
	parameters_.era = (*era_list[era_combo_.selected()])["id"];
	parameters_.num_turns = turns;
	//CHECK
	parameters_.mp_countdown_init_time = mp_countdown_init_time_val;
	parameters_.mp_countdown_turn_bonus = mp_countdown_turn_bonus_val;
	parameters_.mp_countdown_reservoir_time = mp_countdown_reservoir_time_val;
	parameters_.mp_countdown_action_bonus = mp_countdown_action_bonus_val;
	parameters_.mp_countdown = countdown_game_.checked();
	parameters_.village_gold = village_gold_slider_.value();
	parameters_.xp_modifier = xp_modifier_slider_.value();
	parameters_.use_map_settings = use_map_settings_.checked();
	parameters_.fog_game = fog_game_.checked();
	parameters_.shroud_game = shroud_game_.checked();
	parameters_.allow_observers = observers_game_.checked();
	parameters_.share_view = vision_combo_.selected() == 0;
	parameters_.share_maps = vision_combo_.selected() == 1;

	return parameters_;
}

void create::process_event()
{
	int mousex, mousey;
	SDL_GetMouseState(&mousex,&mousey);
	tooltips::process(mousex, mousey);

	if(cancel_game_.pressed()) {
		set_result(QUIT);
		return;
	}

	if(launch_game_.pressed() || maps_menu_.double_clicked()) {
		if(name_entry_.text() != "") {
			set_result(CREATE);
			return;
		} else {
			gui::show_dialog(disp_, NULL, "", _("You must enter a name."), gui::OK_ONLY);
		}
	}

	// Turns per game
	const int cur_turns = turns_slider_.value();

	std::stringstream buf;
	if(cur_turns < 100) {
		buf << _("Turns: ") << cur_turns;
	} else {
		buf << _("Unlimited Turns");
	}
	turns_label_.set_text(buf.str());

	countdown_init_time_label_.enable(countdown_game_.checked());
	countdown_init_time_slider_.enable(countdown_game_.checked());
	countdown_turn_bonus_label_.enable(countdown_game_.checked());
	countdown_turn_bonus_slider_.enable(countdown_game_.checked());

	countdown_reservoir_time_label_.enable(countdown_game_.checked());
	countdown_reservoir_time_slider_.enable(countdown_game_.checked());
	countdown_action_bonus_label_.enable(countdown_game_.checked());
	countdown_action_bonus_slider_.enable(countdown_game_.checked());

	if(mp_countdown_init_time_ != countdown_init_time_slider_.value()
		&& countdown_init_time_slider_.value() > countdown_reservoir_time_slider_.value())
	{
		countdown_reservoir_time_slider_.set_value(countdown_init_time_slider_.value());
	}
	if(mp_countdown_reservoir_time_ != countdown_reservoir_time_slider_.value()
		&& countdown_reservoir_time_slider_.value() < countdown_init_time_slider_.value())
	{
		countdown_init_time_slider_.set_value(countdown_reservoir_time_slider_.value());
	}
	mp_countdown_init_time_ = countdown_init_time_slider_.value();
	mp_countdown_reservoir_time_ = countdown_reservoir_time_slider_.value();


	buf.str("");
	buf <<  _("Init. Limit: ") << mp_countdown_init_time_; // << _(" sec.");
	countdown_init_time_label_.set_text(buf.str());

	const int mp_countdown_turn_bonus_val = countdown_turn_bonus_slider_.value();
	buf.str("");
	buf <<  _("Turn Bonus: ") << mp_countdown_turn_bonus_val; // << _(" sec.");
	countdown_turn_bonus_label_.set_text(buf.str());

	buf.str("");
	buf <<  _("Reservoir: ") << mp_countdown_reservoir_time_; // << _(" sec.");
	countdown_reservoir_time_label_.set_text(buf.str());

	const int mp_countdown_action_bonus_val = countdown_action_bonus_slider_.value();
	buf.str("");
	buf <<  _("Action Bonus: ") << mp_countdown_action_bonus_val; // << _(" sec.");
	countdown_action_bonus_label_.set_text(buf.str());


	//Villages can produce between 1 and 10 gold a turn
	const int village_gold = village_gold_slider_.value();
	buf.str("");
	buf << _("Village Gold: ") << village_gold;
	village_gold_label_.set_text(buf.str());

	//experience modifier
	const int xpmod = xp_modifier_slider_.value();
	buf.str("");
	buf << _("Experience Modifier: ") << xpmod << "%";
	xp_modifier_label_.set_text(buf.str());

	bool map_changed = map_selection_ != maps_menu_.selection();
	map_selection_ = maps_menu_.selection();

	if(map_changed) {
		generator_.assign(NULL);

		tooltips::clear_tooltips(minimap_rect_);

		const size_t select = size_t(maps_menu_.selection());

		if(select > 0 && select <= user_maps_.size()) {
			parameters_.saved_game = false;
			const config* const generic_multiplayer = game_config().child("generic_multiplayer");
			if(generic_multiplayer != NULL) {
				parameters_.scenario_data = *generic_multiplayer;
				parameters_.scenario_data["map_data"] = read_map(user_maps_[select-1]);
			}

		} else if(select > user_maps_.size() && select <= maps_menu_.nitems()-1) {
			parameters_.saved_game = false;
			const size_t index = select - user_maps_.size() - 1;
			const config::child_list& levels = game_config().get_children("multiplayer");

			if(index < levels.size()) {

				parameters_.scenario_data = *levels[index];

				t_string& map_data = parameters_.scenario_data["map_data"];
				if(map_data == "" && parameters_.scenario_data["map"] != "") {
					map_data = read_map(parameters_.scenario_data["map"]);
				}

				//if the map should be randomly generated
				if(parameters_.scenario_data["map_generation"] != "") {
					generator_.assign(create_map_generator(parameters_.scenario_data["map_generation"],parameters_.scenario_data.child("generator")));
				}

				if(!parameters_.scenario_data["description"].empty()) {
					tooltips::add_tooltip(minimap_rect_,parameters_.scenario_data["description"]);
				}
			}
		} else {
			parameters_.scenario_data.clear();
			parameters_.saved_game = true;

			if (minimap_restorer_ != NULL)
				minimap_restorer_->restore();
		}
	}

	if(generator_ != NULL && generator_->allow_user_config() && generator_settings_.pressed()) {
		generator_->user_config(disp_);
		map_changed = true;
	}

	if(generator_ != NULL && (map_changed || regenerate_map_.pressed())) {
		const cursor::setter cursor_setter(cursor::WAIT);

		//generate the random map
		cursor::setter cur(cursor::WAIT);
		parameters_.scenario_data = generator_->create_scenario(std::vector<std::string>());
		map_changed = true;

		//set the scenario to have placing of sides based on the terrain they prefer
		parameters_.scenario_data["modify_placing"] = "true";
	}

	if(map_changed) {
		generator_settings_.hide(generator_ == NULL);
		regenerate_map_.hide(generator_ == NULL);

		const std::string& map_data = parameters_.scenario_data["map_data"];

		std::auto_ptr<gamemap> map(NULL);
		try {
			map = std::auto_ptr<gamemap>(new gamemap(game_config(), map_data));
		} catch(gamemap::incorrect_format_exception& e) {
			LOG_STREAM(err,general) << "map could not be loaded: " << e.msg_ << "\n";
			tooltips::clear_tooltips(minimap_rect_);
			tooltips::add_tooltip(minimap_rect_,e.msg_);
		}

		launch_game_.enable(map.get() != NULL);

		//if there are less sides in the configuration than there are starting
		//positions, then generate the additional sides
		const int map_positions = map.get() != NULL ? map->num_valid_starting_positions() : 0;

		for(int pos =  parameters_.scenario_data.get_children("side").size(); pos < map_positions; ++pos) {
			config& side = parameters_.scenario_data.add_child("side");
			side["enemy"] = "1";
			side["side"] = lexical_cast<std::string>(pos+1);
			side["team_name"] = lexical_cast<std::string>(pos+1);
			side["canrecruit"] = "1";
			side["controller"] = "human";
		}


		if(map.get() != NULL) {
			const surface mini(image::getMinimap(minimap_rect_.w,minimap_rect_.h,*map,0));
			if(mini != NULL) {
				SDL_Rect rect = minimap_rect_;
				SDL_BlitSurface(mini, NULL, video().getSurface(), &rect);
				update_rect(rect);
			}
		}

		int nsides = parameters_.scenario_data.get_children("side").size();
		const config::child_list& player_sides = parameters_.scenario_data.get_children("side");
		for(config::child_list::const_iterator k = player_sides.begin(); k != player_sides.end(); ++k) {
			if((**k)["allow_player"] == "no") {
				nsides--;
			}
		}

		std::stringstream players;
		std::stringstream map_size;
		if(map.get() != NULL) {
			players << _("Players: ") << nsides;
			map_size << _("Size") << " " << map.get()->x() << "x" << map.get()->y();
		} else {
			players << _("Error");
			map_size << "";
		}
		num_players_label_.set_text(players.str());
		map_size_label_.set_text(map_size.str());

		if(use_map_settings_.checked()) {
			try {
				xp_modifier_slider_.set_value(lexical_cast<int>(parameters_.scenario_data["experience_modifier"]));
			} catch(bad_lexical_cast&) {
				xp_modifier_slider_.set_value(preferences::xp_modifier());
			}
		}
	}
}

void create::hide_children(bool hide)
{
	ui::hide_children(hide);

	maps_menu_.hide(hide);
	turns_slider_.hide(hide);
	turns_label_.hide(hide);

	countdown_init_time_slider_.hide(hide);
	countdown_init_time_label_.hide(hide);
	countdown_turn_bonus_slider_.hide(hide);
	countdown_turn_bonus_label_.hide(hide);
	countdown_reservoir_time_slider_.hide(hide);
	countdown_reservoir_time_label_.hide(hide);
	countdown_action_bonus_slider_.hide(hide);
	countdown_action_bonus_label_.hide(hide);
	countdown_game_.hide(hide);

	village_gold_slider_.hide(hide);
	village_gold_label_.hide(hide);
	xp_modifier_slider_.hide(hide);
	xp_modifier_label_.hide(hide);

	name_entry_label_.hide(hide);
	num_players_label_.hide(hide);
	map_size_label_.hide(hide);
	era_label_.hide(hide);
	map_label_.hide(hide);

	use_map_settings_.hide(hide);
	fog_game_.hide(hide);
	shroud_game_.hide(hide);
	observers_game_.hide(hide);
	cancel_game_.hide(hide);
	launch_game_.hide(hide);
	regenerate_map_.hide(hide || generator_ == NULL);
	generator_settings_.hide(hide || generator_ == NULL);

	era_combo_.hide(hide);
	vision_combo_.hide(hide);
	name_entry_.hide(hide);

	if (hide) {
		minimap_restorer_.assign(NULL);
	} else {
		minimap_restorer_.assign(new surface_restorer(&video(), minimap_rect_));

		const std::string& map_data = parameters_.scenario_data["map_data"];

		try {
			gamemap map(game_config(), map_data);
			const surface mini(image::getMinimap(minimap_rect_.w,minimap_rect_.h,map,0));
			if(mini != NULL) {
				SDL_Rect rect = minimap_rect_;
				SDL_BlitSurface(mini, NULL, video().getSurface(), &rect);
				update_rect(rect);
			}
		} catch(gamemap::incorrect_format_exception& e) {
			LOG_STREAM(err,general) << "map could not be loaded: " << e.msg_ << "\n";
		}

	}
}

void create::layout_children(const SDL_Rect& rect)
{
	ui::layout_children(rect);
	SDL_Rect ca = client_area();

	const int border_size = 6;
	const int column_border_size = 10;
	int xpos = ca.x;
	int ypos = ca.y;

	// Dialog title
	ypos += title().height() + border_size;

	// Name Entry
	name_entry_label_.set_location(xpos, ypos);
	name_entry_.set_location(xpos + name_entry_label_.width() + border_size, ypos);
	name_entry_.set_width(ca.w - name_entry_label_.width() - border_size);
	ypos += maximum<int>(name_entry_.height(), name_entry_label_.height()) + border_size;

	// Save ypos here (column top)
	int ypos_columntop = ypos;

	// First column: minimap & random map options
	const int minimap_width = 200;
	SDL_Rect mmrect = { xpos, ypos, minimap_width, minimap_width };
	minimap_rect_ = mmrect;
	ypos += minimap_width + border_size;

	num_players_label_.set_location(xpos, ypos);
	ypos += num_players_label_.height() + border_size;

	map_size_label_.set_location(xpos, ypos);
	ypos += map_size_label_.height() + 2 * border_size;

	regenerate_map_.set_location(xpos + era_label_.width() + border_size, ypos);
	ypos += regenerate_map_.height() + border_size;
	generator_settings_.set_location(xpos + era_label_.width() + border_size, ypos);
	ypos += generator_settings_.height() + border_size;

	era_label_.set_location(xpos, ypos + (era_combo_.height() - era_label_.height()) / 2);
	era_combo_.set_location(xpos + era_label_.width() + border_size, ypos);
	ypos += era_combo_.height() + border_size;

#ifdef MP_VISION_OPTIONAL
	vision_combo_.set_location(xpos, ypos);
	ypos += vision_combo_.height() + border_size;
#endif

	// Second column: map menu
	ypos = ypos_columntop;
	xpos += minimap_width + column_border_size;
	map_label_.set_location(xpos, ypos);
	ypos += map_label_.height() + border_size;
	maps_menu_.set_max_width(200);
	maps_menu_.set_max_height(ca.h + ca.x - ypos - border_size);
	maps_menu_.set_location(xpos, ypos);
	// Menu dimensions are only updated when items are set. So do this now.
	int mapsel_save = maps_menu_.selection();
	maps_menu_.set_items(map_options_);
	maps_menu_.move_selection(mapsel_save);

	// Third column: big buch of options
	ypos = ypos_columntop;
	xpos += 200 + column_border_size;

	turns_label_.set_location(xpos, ypos);
	ypos += turns_label_.height() + border_size;
	turns_slider_.set_width(ca.w - xpos);
	turns_slider_.set_location(xpos, ypos);
	ypos += turns_slider_.height() + border_size;


	village_gold_label_.set_location(xpos, ypos);
	ypos += village_gold_label_.height() + border_size;
	village_gold_slider_.set_width(ca.w - xpos);
	village_gold_slider_.set_location(xpos, ypos);
	ypos += village_gold_slider_.height() + border_size;

	xp_modifier_label_.set_location(xpos, ypos);
	ypos += xp_modifier_label_.height() + border_size;
	xp_modifier_slider_.set_width(ca.w - xpos);
	xp_modifier_slider_.set_location(xpos, ypos);
	ypos += xp_modifier_slider_.height() + border_size;

	use_map_settings_.set_location(xpos, ypos);
	ypos += use_map_settings_.height() + border_size;

	countdown_init_time_label_.set_location(xpos, ypos);
	countdown_turn_bonus_label_.set_location(xpos + (ca.w - xpos)/2 + 5 , ypos);
	ypos += countdown_init_time_label_.height() + border_size;
	countdown_init_time_slider_.set_width(((ca.w - xpos)/2)-5);
	countdown_turn_bonus_slider_.set_width(((ca.w - xpos)/2)-5);
	countdown_init_time_slider_.set_location(xpos, ypos);
	countdown_turn_bonus_slider_.set_location(xpos + (ca.w - xpos)/2 + 5, ypos);
	ypos += countdown_init_time_slider_.height() + border_size;

	countdown_reservoir_time_label_.set_location(xpos, ypos);
	countdown_action_bonus_label_.set_location(xpos + (ca.w - xpos)/2 + 5 , ypos);
	ypos += countdown_reservoir_time_label_.height() + border_size;
	countdown_reservoir_time_slider_.set_width(((ca.w - xpos)/2)-5);
	countdown_action_bonus_slider_.set_width(((ca.w - xpos)/2)-5);
	countdown_reservoir_time_slider_.set_location(xpos, ypos);
	countdown_action_bonus_slider_.set_location(xpos + (ca.w - xpos)/2 + 5, ypos);
	ypos += countdown_reservoir_time_slider_.height() + border_size;

	countdown_game_.set_location(xpos, ypos);
//	ypos += countdown_game_.height() + border_size;

	fog_game_.set_location(xpos + (ca.w - xpos)/2 + 5, ypos);
	ypos += fog_game_.height() + border_size;

	shroud_game_.set_location(xpos, ypos);
//	ypos += shroud_game_.height() + border_size;

	observers_game_.set_location(xpos + (ca.w - xpos)/2 + 5, ypos);
	ypos += observers_game_.height() + border_size;

	// OK / Cancel buttons
	gui::button* left_button = &launch_game_;
	gui::button* right_button = &cancel_game_;

#ifdef OK_BUTTON_ON_RIGHT
	std::swap(left_button,right_button);
#endif

	// Buttons
	right_button->set_location(ca.x + ca.w - right_button->width(),
	                           ca.y + ca.h - right_button->height());
	left_button->set_location(right_button->location().x - left_button->width() -
	                          gui::ButtonHPadding, ca.y + ca.h - left_button->height());
}

}
