/**********************************************************************
 *
 *   FreeDoko a Doppelkopf-Game
 *    
 *   Copyright (C) 2001-2006  by Diether Knof and Borg Enders
 *
 *   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 can find this license in the file 'gpl.txt'.
 *
 *   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
 *
 *  Contact:
 *    Diether Knof dknof@gmx.de
 *    Borg Enders  borg@borgsoft.de
 *
 *********************************************************************/

#include "constants.h"

#ifdef USE_UI_GTKMM

#include "aiconfig.h"
#include "ui.h"
#include "translations.h"

#include "../../party/party.h"
#include "../../player/aiconfig.h"
#include "../../misc/setting.h"
#include "../../utils/string.h"
#ifdef USE_NETWORK
#include "../../network/server.h"
#endif

#include "widgets/labelscalespinbutton.h"
#include "widgets/filemenu.h"
#include "widgets/stock_button.h"
#include "widgets/label_card_selector.h"
#include <gtkmm/stock.h>
#include <gtkmm/label.h>
#include <gtkmm/box.h>
#include <gtkmm/table.h>
#include <gtkmm/checkbutton.h>
#include <gtkmm/fileselection.h>
#include <gtkmm/notebook.h>
#include <gtkmm/frame.h>
#include <gtkmm/main.h>

namespace UI_GTKMM_NS {

  /**
   ** Constructor
   **
   ** @param	player	the corresponding (Gtk-)Player
   **
   ** @return	-
   ** 
   ** @author	Diether Knof
   **
   ** @version	0.5.4
   **/
  Players::Player::AiConfig::AiConfig(Player* const player) :
    Base(player),
    sigc::trackable(),
    player(player),
    container(NULL),
    notebook(NULL),
    heuristic_notebook(NULL),
    hardcoded_button(NULL),
    difficulty_selector(NULL),
    adopt_button(NULL),
    allot_button(NULL),
    load_button(NULL),
    save_button(NULL),
    save_file_selector(NULL),
    aitype(),
    future_limit(),
    aitype_as_previous(),
    type_heuristic(),
    type_bool(),
    type_unsigned(),
    type_card()
  {
    this->init();

    return ;
  } // Players::Player::AiConfig::AiConfig(Player* const player)

  /**
   ** Destruktor
   **
   ** @param	-
   **
   ** @return	-
   ** 
   ** @author	Diether Knof
   **
   ** @version	0.5.4
   **/
  Players::Player::AiConfig::~AiConfig()
  {
    for (vector<Gtk::OptionMenu*>::iterator i = this->aitype.begin();
	 i != this->aitype.end();
	 i++) {
      for (Gtk::Menu_Helpers::MenuList::iterator
	   t = (*i)->get_menu()->items().begin();
	   t != (*i)->get_menu()->items().end();
	   ++t) {
	delete static_cast<unsigned*>(t->steal_data("trick number"));
	delete static_cast<AiType*>(t->steal_data("aitype"));
      }
    }

    for (vector<Gtk::CheckButton*>::iterator i = this->type_heuristic.begin();
	 i != this->type_heuristic.end();
	 i++)
      delete static_cast<string*>((*i)->steal_data("type"));

    for (vector<Gtk::CheckButton*>::iterator i = this->type_bool.begin();
	 i != this->type_bool.end();
	 i++)
      delete static_cast<string*>((*i)->steal_data("type"));

    for (vector<Gtk::LabelCardSelector*>::iterator i = this->type_card.begin();
	 i != this->type_card.end();
	 i++)
      delete static_cast<string*>((*i)->steal_data("type"));

    for (vector<Gtk::LabelSpinButton*>::iterator i
	 = this->type_unsigned.begin();
	 i != this->type_unsigned.end();
	 i++)
      delete static_cast<string*>((*i)->steal_data("type"));

    return ;
  } // Players::Player::AiConfig::~AiConfig()

  /**
   ** creates all subelements
   **
   ** @param	-
   **
   ** @return	-
   **
   ** @author	Diether Knof
   **
   ** @version	0.5.4
   **/
  void
    Players::Player::AiConfig::init()
    {

      { // create the widgets
	{ // buttons
	  this->hardcoded_button
	    = Gtk::manage(new Gtk::StockButton(Gtk::Stock::CLEAR, "hardcoded"));
	  this->ui->translations->add(*(this->hardcoded_button),
				      ::translation("hardcoded"));
	  this->difficulty_selector
	    = Gtk::manage(new Gtk::LabelTypeSelector< ::Aiconfig::Difficulty>());
	  this->ui->translations->add(this->difficulty_selector->get_label(),
				      ::translation("AiConfig::difficulty")
				      + ": ");
	  for (int difficulty = ::Aiconfig::DIFFICULTY_FIRST;
	       difficulty <= ::Aiconfig::DIFFICULTY_LAST;
	       difficulty++)
	    this->difficulty_selector->add(static_cast< ::Aiconfig::Difficulty>(difficulty));

	  this->adopt_button
	    = Gtk::manage(new Gtk::StockButton("adopt"));
	  this->ui->translations->add(*(this->adopt_button),
				      ::translation("adopt"));
	  this->allot_button
	    = Gtk::manage(new Gtk::StockButton("allot"));
	  this->ui->translations->add(*(this->allot_button),
				      ::translation("allot"));
	  this->load_button
	    = Gtk::manage(new Gtk::StockButton(Gtk::Stock::OPEN, "load"));
	  this->ui->translations->add(*(this->load_button),
				      ::translation("load"));
	  this->save_button
	    = Gtk::manage(new Gtk::StockButton(Gtk::Stock::SAVE_AS, "save"));
	  this->ui->translations->add(*(this->save_button),
				      ::translation("save"));
	  this->save_file_selector = new Gtk::FileSelection("Save aiconfig");
	  this->ui->translations->add(*(this->save_file_selector),
				      ::translation("Save aiconfig of %splayer%",
						    this->player->player().name()));
#ifndef WINDOWS
	  this->save_file_selector->set_filename(::setting(Setting::PRIVATE_DATA_DIRECTORY)
						 + "/"
						 + ::setting(Setting::AI_DIRECTORY)
						 + "/");
#else // #ifndef WINDOWS
	  {
	    string filename = (::setting(Setting::PRIVATE_DATA_DIRECTORY)
			       + "/"
			       + ::setting(Setting::AI_DIRECTORY)
			       + "/"
			      );
	    DK::Utils::String::replace_all(filename, "/", "\\");
	    this->save_file_selector->set_filename(filename);
	  }
#endif // #ifndef WINDOWS
	} // buttons


	for (int t = Aiconfig::HEURISTIC_FIRST;
	     t <= Aiconfig::HEURISTIC_LAST;
	     t++) {
	  this->type_heuristic.push_back(Gtk::manage(new Gtk::CheckButton(::name(Aiconfig::Heuristic(t)))));
	  this->type_heuristic.back()->set_data("type", new Aiconfig::Heuristic(Aiconfig::Heuristic(t)));
	  this->ui->translations->add(*(this->type_heuristic.back()),
				      ::translation(Aiconfig::Heuristic(t)));
	  this->type_heuristic.back()->signal_toggled().connect(sigc::bind<int const>(sigc::mem_fun(*this, &AiConfig::change),
										      t)
							       );
	} // for (t \in Aiconfig::Heuristic)
	for (int t = Aiconfig::BOOL_FIRST;
	     t <= Aiconfig::BOOL_LAST;
	     t++) {
	  this->type_bool.push_back(Gtk::manage(new Gtk::CheckButton(::name(Aiconfig::Heuristic(t)))));
	  this->type_bool.back()->set_data("type", new Aiconfig::TypeBool(Aiconfig::TypeBool(t)));
	  this->ui->translations->add(*(this->type_bool.back()),
				      ::translation(Aiconfig::TypeBool(t)));
	  this->type_bool.back()->signal_toggled().connect(sigc::bind<int const>(sigc::mem_fun(*this, &AiConfig::change),
										 t)
							  );
	} // for (t \in Aiconfig::TypeBool)
	for (int t = Aiconfig::UNSIGNED_FIRST;
	     t <= Aiconfig::UNSIGNED_LAST;
	     t++) {
	  switch (t) {
	  case Aiconfig::REMEMBERTRICKS:
	  case Aiconfig::LASTFEHLCREATION:
	  case Aiconfig::LASTHEURISTICTRICK:
	  case Aiconfig::FIRST_TRICK_FOR_TRUMP_POINTS_OPTIMIZATION:
	    this->type_unsigned.push_back(Gtk::manage(new Gtk::LabelScaleSpinButton(::name(Aiconfig::TypeUnsigned(t)))));
	    break;
	  case Aiconfig::LIMIT_THROW_FEHL:
	  case Aiconfig::LIMITQUEEN:
	  case Aiconfig::LIMITDOLLE:
	  case Aiconfig::ANNOUNCELIMIT:
	  case Aiconfig::ANNOUNCELIMITDEC:
	  case Aiconfig::ANNOUNCECONFIG:
	  case Aiconfig::ANNOUNCELIMITREPLY:
	  case Aiconfig::ANNOUNCECONFIGREPLY:
	  case Aiconfig::TAKEPOVERTY:
	  case Aiconfig::SINGLESOLO:
	  case Aiconfig::DOUBLESOLO:
	  case Aiconfig::TRIPLESOLO:
	  case Aiconfig::COLORSOLO:
	  case Aiconfig::MEATLESS:
	  case Aiconfig::FUTURE_LIMIT:
	    this->type_unsigned.push_back(Gtk::manage(new Gtk::LabelSpinButton(::name(Aiconfig::TypeUnsigned(t)))));
	    break;
	  } // switch(t)
	  this->type_unsigned.back()->set_data("type", new Aiconfig::TypeUnsigned(Aiconfig::TypeUnsigned(t)));
	  this->ui->translations->add(this->type_unsigned.back()->get_label(),
				      ::translation(Aiconfig::TypeUnsigned(t))
				      + ": ");
	  this->type_unsigned.back()->signal_value_changed().connect(sigc::bind<int const>(sigc::mem_fun(*this, &AiConfig::change),
											   t)
								    );
	  switch(t) {
	  case Aiconfig::FUTURE_LIMIT:
	    this->type_unsigned.back()->get_spin_button().set_increments(1, 1000);
	    break;
	  default:
	    break;
	  } // switch(t)
	} // for (t \in Aiconfig::TypeUnsigned)
	for (int t = Aiconfig::CARD_FIRST;
	     t <= Aiconfig::CARD_LAST;
	     t++) {
	  Aiconfig::TypeCard const type = static_cast<Aiconfig::TypeCard>(t);
	  switch (type) {
	  case Aiconfig::LIMITTHROWING:
	  case Aiconfig::LIMITHIGH:
	  case Aiconfig::TRUMPLIMIT_NORMAL:
	  case Aiconfig::LOWEST_TRUMPLIMIT_NORMAL:
	    this->type_card.push_back(Gtk::manage(new Gtk::LabelCardSelector(::name(type))));
	    this->ui->translations->add(this->type_card.back()->get_label(),
					::translation(type));
	    break;
	  case Aiconfig::TRUMPLIMIT_SOLOCOLOR:
	  case Aiconfig::LOWEST_TRUMPLIMIT_SOLOCOLOR:
	  case Aiconfig::TRUMPLIMIT_SOLOJACK:
	  case Aiconfig::LOWEST_TRUMPLIMIT_SOLOJACK:
	  case Aiconfig::TRUMPLIMIT_SOLOQUEEN:
	  case Aiconfig::LOWEST_TRUMPLIMIT_SOLOQUEEN:
	  case Aiconfig::TRUMPLIMIT_SOLOKING:
	  case Aiconfig::LOWEST_TRUMPLIMIT_SOLOKING:
	  case Aiconfig::TRUMPLIMIT_SOLOJACKKING:
	  case Aiconfig::LOWEST_TRUMPLIMIT_SOLOJACKKING:
	  case Aiconfig::TRUMPLIMIT_SOLOJACKQUEEN:
	  case Aiconfig::LOWEST_TRUMPLIMIT_SOLOJACKQUEEN:
	  case Aiconfig::TRUMPLIMIT_SOLOQUEENKING:
	  case Aiconfig::LOWEST_TRUMPLIMIT_SOLOQUEENKING:
	  case Aiconfig::TRUMPLIMIT_SOLOKOEHLER:
	  case Aiconfig::LOWEST_TRUMPLIMIT_SOLOKOEHLER:
	  case Aiconfig::TRUMPLIMIT_MEATLESS:
	  case Aiconfig::LOWEST_TRUMPLIMIT_MEATLESS:
	    // the translation is added by a separate label
	    this->type_card.push_back(Gtk::manage(new Gtk::LabelCardSelector()));
	    break;
	  default:
	    DEBUG_ASSERTION(false,
			    "UI_GTKMM::AiConfig::init()\n"
			    "  Aiconfig::TypeCard '" << type << "' "
			    "not taken into account.");
	    break;
	  } // switch(type)
	  this->type_card.back()->set_data("type",
					   new Aiconfig::TypeCard(type));
	  for (list<Card>::const_iterator
	       c = this->aiconfig().valid_cards(type).begin();
	       c != this->aiconfig().valid_cards(type).end();
	       ++c)
	    this->type_card.back()->add(*c);
	  this->type_card.back()->signal_value_changed().connect(sigc::bind<int const>(sigc::mem_fun(*this, &AiConfig::change), t) );
	} // for (t \in Aiconfig::TypeCard)
      } // create the widgets

      this->create_container();

      { // the signals
	this->hardcoded_button->signal_clicked().connect(sigc::mem_fun(*this, &AiConfig::hardcoded));
	this->difficulty_selector->signal_value_changed().connect(sigc::mem_fun(*this, &AiConfig::difficulty_changed));
	this->adopt_button->signal_clicked().connect(sigc::mem_fun(*this, &AiConfig::adopt));
	this->allot_button->signal_clicked().connect(sigc::mem_fun(*this, &AiConfig::allot));
	this->load_button->signal_clicked().connect(sigc::mem_fun(*this, &AiConfig::load));
	this->save_button->signal_clicked().connect(sigc::mem_fun(*(this->save_file_selector), &Widget::show));

	this->save_file_selector->get_cancel_button()->signal_clicked().connect(sigc::mem_fun(*(this->save_file_selector), &Widget::hide));
	this->save_file_selector->get_ok_button()->signal_clicked().connect(sigc::mem_fun(*(this->save_file_selector), &Widget::hide));
	this->save_file_selector->get_ok_button()->signal_clicked().connect(sigc::mem_fun(*this, &AiConfig::save));
      } // the signals

      this->update();
      this->sensitivity_update();

      return ;
    } // void Players::Player::AiConfig::init()

  /**
   ** -> result
   **
   ** @param	-
   **
   ** @return	a container with the configuration (in notebooks)
   **
   ** @author	Diether Knof
   **
   ** @version	0.6.6
   **/
  void
    Players::Player::AiConfig::create_container()
    {
      this->container
	= Gtk::manage(new Gtk::VBox(false, 1 ex));

      { // the settings
	this->notebook = Gtk::manage(new Gtk::Notebook());
	this->notebook->set_scrollable(true);

	{ // the notebook pages
	  { // data buttons
	    Gtk::Label* label = Gtk::manage(new Gtk::Label(""));
	    this->ui->translations->add(*label,
					::translation("AiConfig::Group::data"));

	    Gtk::Alignment* alignment
	      = Gtk::manage(new Gtk::Alignment(Gtk::ALIGN_CENTER,
					       Gtk::ALIGN_CENTER,
					       0, 0));
	    alignment->set_border_width(1 em);

	    Gtk::Table* table = Gtk::manage(new Gtk::Table(4, 4, true));
	    table->set_col_spacings(2 em);
	    table->set_row_spacings(1 ex);
	    table->set_border_width(1 ex);

	    //table->attach(*this->hardcoded_button, 0, 1, 0, 1);
	    {
	      Gtk::Alignment* alignment
		= Gtk::manage(new Gtk::Alignment(Gtk::ALIGN_CENTER,
						 Gtk::ALIGN_CENTER,
						 0, 1));
	      alignment->add(*this->difficulty_selector);

	      table->attach(*alignment, 0, 4, 0, 1);
	    }
	    table->attach(*this->adopt_button,        0, 2, 2, 3);
	    table->attach(*this->allot_button,        2, 4, 2, 3);
	    table->attach(*this->load_button,         0, 2, 3, 4);
	    table->attach(*this->save_button,         2, 4, 3, 4);

	    alignment->add(*table);
	    this->notebook->append_page(*alignment, *label);
	  } // data buttons
	  { // simple settings
	    Gtk::Label* label = Gtk::manage(new Gtk::Label("simple"));
	    this->ui->translations->add(*label,
					::translation("AiConfig::Group::simple"));

	    Gtk::Alignment* alignment
	      = Gtk::manage(new Gtk::Alignment(Gtk::ALIGN_CENTER,
					       Gtk::ALIGN_CENTER,
					       0, 0));
	    alignment->set_border_width(1 em);

	    Gtk::VBox* vbox = Gtk::manage(new Gtk::VBox(false, 1 em));

	    vbox->add(*(this->type_bool[Aiconfig::FAIRPLAYHANDS - Aiconfig::BOOL_FIRST]));
	    vbox->add(*(this->type_bool[Aiconfig::FAIRPLAYTEAMS - Aiconfig::BOOL_FIRST]));
	    vbox->add(*(this->type_bool[Aiconfig::TRUSTING - Aiconfig::BOOL_FIRST]));
	    vbox->add(*(this->type_unsigned[Aiconfig::REMEMBERTRICKS - Aiconfig::UNSIGNED_FIRST]));

	    alignment->add(*vbox);
	    this->notebook->append_page(*alignment, *label);
	  } // simple settings
	  { // aitype
	    Gtk::Label* label = Gtk::manage(new Gtk::Label("aitype"));
	    this->ui->translations->add(*label,
					::translation("AiConfig::Group::aitype"));

	    Gtk::Alignment* alignment
	      = Gtk::manage(new Gtk::Alignment(Gtk::ALIGN_CENTER,
					       Gtk::ALIGN_CENTER,
					       0, 0));
	    alignment->set_border_width(1 em);

	    // ToDo: table -> ListStore
	    Gtk::Table* table = Gtk::manage(new Gtk::Table(this->ui->party().rule()(Rule::MAX_NUMBER_OF_TRICKS_IN_GAME) + 2, 4));
	    { // titles
	      Gtk::Label* label;
#ifdef POSTPHONED
	      label = Gtk::manage(new Gtk::Label("as previous"));
	      this->ui->translations->add(*label, ::translation("as previous"));
	      table->attach(*label, 0, 1, 0, 1);
#endif

	      label = Gtk::manage(new Gtk::Label("trick"));
	      this->ui->translations->add(*label, ::translation("trick"));
	      table->attach(*label, 1, 2, 0, 1);

	      label = Gtk::manage(new Gtk::Label("aitype"));
	      this->ui->translations->add(*label, ::translation("AiConfig::aitype"));
	      table->attach(*label, 2, 3, 0, 1);

	      label = Gtk::manage(new Gtk::Label("future limit"));
	      this->ui->translations->add(*label, ::translation(Aiconfig::FUTURE_LIMIT));
	      table->attach(*label, 3, 4, 0, 1);

	      label = Gtk::manage(new Gtk::Label(""));
	      table->attach(*label, 0, 4, 1, 2);
	    } // titles
	    for (unsigned t = 0;
		 t < this->ui->party().rule()(Rule::MAX_NUMBER_OF_TRICKS_IN_GAME); 
		 ++t) {
	      { // aitype as previous
		this->aitype_as_previous.push_back(Gtk::manage(new Gtk::CheckButton()));
		if (t > 0) {
		  this->aitype_as_previous.back()->set_active(   (this->aiconfig().aitype(t) != this->aiconfig().aitype(t - 1))
							      || (this->aiconfig().future_limit(t) != this->aiconfig().future_limit(t - 1))
							     );
		  table->attach(*this->aitype_as_previous.back(), 0, 1, t + 2, t + 3);
		  this->aitype_as_previous.back()->signal_toggled().connect(sigc::bind<unsigned const>(sigc::mem_fun(*this, &AiConfig::aitype_as_previous_changed), t));
		} // if (t > 0)
	      } // aitype as previous

	      { // label
		Gtk::Label* label = Gtk::manage(new Gtk::Label( " " + DK::Utils::String::to_string(t + 1) + ": "));
		table->attach(*label, 1, 2, t + 2, t + 3);
	      } // label

	      { // menu
		Gtk::Menu *menu = Gtk::manage(new Gtk::Menu());

		for (int a = AITYPE::AITYPE_FIRST;
		     a <= AITYPE::AITYPE_LAST;
		     ++a) {
		  if (a == AITYPE::NO_CHOOSEBESTCARD)
		    continue;

		  Gtk::MenuItem *item
		    = Gtk::manage(new Gtk::MenuItem("ai type"));
		  this->ui->translations->add(*(dynamic_cast<Gtk::Label*>(item->get_child())),
					      ::translation(static_cast<AiType>(a)));
		  item->set_data("aitype", new AiType(AiType(a)));
		  item->set_data("trick number", new unsigned(t));
		  menu->append(*item);
		} // for (a \in AITYPE)
		this->aitype.push_back(Gtk::manage(new Gtk::OptionMenu()));
		this->aitype.back()->set_menu(*menu);
		this->aitype.back()->set_history(this->aiconfig().aitype(t) - 1);

		table->attach(*this->aitype.back(), 2, 3, t + 2, t + 3);
		this->aitype.back()->signal_changed().connect(sigc::bind<unsigned const>(sigc::mem_fun(*this, &AiConfig::aitype_changed), t));


	      } // menu
	      { // future limit
		this->future_limit.push_back(Gtk::manage(new Gtk::SpinButton()));
		this->future_limit.back()->set_range(this->aiconfig().min(Aiconfig::FUTURE_LIMIT), this->aiconfig().max(Aiconfig::FUTURE_LIMIT));
		this->future_limit.back()->set_increments(1, 1000);
		this->future_limit.back()->set_numeric(true);
		table->attach(*this->future_limit.back(), 3, 4, t + 2, t + 3);

		this->future_limit.back()->signal_value_changed().connect(sigc::bind<unsigned const>(sigc::mem_fun(*this, &AiConfig::future_limit_changed), t));
	      } // future limit
	    } // for (t < MAX_NUMBER_OF_TRICKS_IN_GAME)

	    alignment->add(*table);
	    this->notebook->append_page(*alignment, *label);
	  } // aitype
	  { // announcement
	    Gtk::Label* label = Gtk::manage(new Gtk::Label("announcement"));
	    this->ui->translations->add(*label,
					::translation("AiConfig::Group::announcement"));

	    Gtk::Alignment* alignment
	      = Gtk::manage(new Gtk::Alignment(Gtk::ALIGN_CENTER,
					       Gtk::ALIGN_CENTER,
					       0, 0));
	    alignment->set_border_width(1 em);

	    Gtk::VBox* vbox = Gtk::manage(new Gtk::VBox(false, 1 em));

	    vbox->add(*(this->type_unsigned[Aiconfig::ANNOUNCELIMIT - Aiconfig::UNSIGNED_FIRST]));
	    vbox->add(*(this->type_unsigned[Aiconfig::ANNOUNCELIMITDEC - Aiconfig::UNSIGNED_FIRST]));
	    vbox->add(*(this->type_unsigned[Aiconfig::ANNOUNCECONFIG - Aiconfig::UNSIGNED_FIRST]));
	    vbox->add(*(this->type_unsigned[Aiconfig::ANNOUNCELIMITREPLY - Aiconfig::UNSIGNED_FIRST]));
	    vbox->add(*(this->type_unsigned[Aiconfig::ANNOUNCECONFIGREPLY - Aiconfig::UNSIGNED_FIRST]));

	    alignment->add(*vbox);
	    this->notebook->append_page(*alignment, *label);
	  } // announcement
	  { // trick decision
	    Gtk::Label* label = Gtk::manage(new Gtk::Label("trick decision"));
	    this->ui->translations->add(*label,
					::translation("AiConfig::Group::trick decision"));

	    Gtk::Alignment* alignment
	      = Gtk::manage(new Gtk::Alignment(Gtk::ALIGN_CENTER,
					       Gtk::ALIGN_CENTER,
					       0, 0));
	    alignment->set_border_width(1 em);

	    Gtk::VBox* vbox = Gtk::manage(new Gtk::VBox(false, 1 em));

	    vbox->add(*(this->type_bool[Aiconfig::FEHLCREATIONONFIRSTCARD - Aiconfig::BOOL_FIRST]));
	    vbox->add(*(this->type_unsigned[Aiconfig::LASTHEURISTICTRICK - Aiconfig::UNSIGNED_FIRST]));
	    vbox->add(*(this->type_unsigned[Aiconfig::FIRST_TRICK_FOR_TRUMP_POINTS_OPTIMIZATION - Aiconfig::UNSIGNED_FIRST]));
	    vbox->add(*(this->type_unsigned[Aiconfig::LASTFEHLCREATION - Aiconfig::UNSIGNED_FIRST]));
	    vbox->add(*(this->type_unsigned[Aiconfig::LIMITQUEEN - Aiconfig::UNSIGNED_FIRST]));
	    vbox->add(*(this->type_unsigned[Aiconfig::LIMITDOLLE - Aiconfig::UNSIGNED_FIRST]));

	    alignment->add(*vbox);
	    this->notebook->append_page(*alignment, *label);
	  } // trick decision
	  { // game decision
	    Gtk::Label* label = Gtk::manage(new Gtk::Label("game decision"));
	    this->ui->translations->add(*label,
					::translation("AiConfig::Group::game decision"));

	    Gtk::Alignment* alignment
	      = Gtk::manage(new Gtk::Alignment(Gtk::ALIGN_CENTER,
					       Gtk::ALIGN_CENTER,
					       0, 0));
	    alignment->set_border_width(1 em);

	    Gtk::VBox* vbox = Gtk::manage(new Gtk::VBox(false, 1 em));

	    vbox->add(*(this->type_unsigned[Aiconfig::TAKEPOVERTY - Aiconfig::UNSIGNED_FIRST]));
	    vbox->add(*(this->type_unsigned[Aiconfig::SINGLESOLO - Aiconfig::UNSIGNED_FIRST]));
	    vbox->add(*(this->type_unsigned[Aiconfig::DOUBLESOLO - Aiconfig::UNSIGNED_FIRST]));
	    vbox->add(*(this->type_unsigned[Aiconfig::TRIPLESOLO - Aiconfig::UNSIGNED_FIRST]));
	    vbox->add(*(this->type_unsigned[Aiconfig::COLORSOLO - Aiconfig::UNSIGNED_FIRST]));
	    vbox->add(*(this->type_unsigned[Aiconfig::MEATLESS - Aiconfig::UNSIGNED_FIRST]));

	    alignment->add(*vbox);
	    this->notebook->append_page(*alignment, *label);
	  } // game decision
	  { // the heuristics
	    Gtk::Label* label = Gtk::manage(new Gtk::Label("heuristics"));
	    this->ui->translations->add(*label,
					::translation("AiConfig::Group::heuristics"));

	    this->heuristic_notebook = Gtk::manage(new Gtk::Notebook());

	    { // normal game
	      Gtk::Label* label = Gtk::manage(new Gtk::Label("normal game"));
	      this->ui->translations->add(*label,
					  ::translation("AiConfig::Heuristic::Group::normal game"));

	      Gtk::Alignment* alignment
		= Gtk::manage(new Gtk::Alignment(Gtk::ALIGN_CENTER,
						 Gtk::ALIGN_CENTER,
						 0, 0));
	      alignment->set_border_width(1 em);

	      Gtk::VBox* vbox = Gtk::manage(new Gtk::VBox(false, 1 ex / 2));

	      vbox->add(*this->type_heuristic[Aiconfig::PLAY_TO_MARRY - Aiconfig::HEURISTIC_FIRST]);
	      vbox->add(*this->type_heuristic[Aiconfig::CHOOSE_ACE - Aiconfig::HEURISTIC_FIRST]);
	      vbox->add(*this->type_heuristic[Aiconfig::CHOOSE_FOR_COLOR_TRICK - Aiconfig::HEURISTIC_FIRST]);
	      vbox->add(*this->type_heuristic[Aiconfig::RETRY_COLOR - Aiconfig::HEURISTIC_FIRST]);
	      vbox->add(*this->type_heuristic[Aiconfig::SERVE_COLOR_TRICK - Aiconfig::HEURISTIC_FIRST]);
	      vbox->add(*this->type_heuristic[Aiconfig::SERVE_TRUMP_TRICK - Aiconfig::HEURISTIC_FIRST]);
	      vbox->add(*this->type_heuristic[Aiconfig::CHOOSE_PFUND - Aiconfig::HEURISTIC_FIRST]);
	      vbox->add(*this->type_heuristic[Aiconfig::CHOOSE_PFUND_POVERTY - Aiconfig::HEURISTIC_FIRST]);
	      vbox->add(*this->type_heuristic[Aiconfig::JAB_FOR_ACE - Aiconfig::HEURISTIC_FIRST]);
	      vbox->add(*this->type_heuristic[Aiconfig::CREATE_FEHL - Aiconfig::HEURISTIC_FIRST]);
	      vbox->add(*this->type_heuristic[Aiconfig::BEST_WINNING - Aiconfig::HEURISTIC_FIRST]);
	      vbox->add(*this->type_heuristic[Aiconfig::LOW_HIGH - Aiconfig::HEURISTIC_FIRST]);
	      vbox->add(*this->type_heuristic[Aiconfig::PLAY_FOR_TEAM - Aiconfig::HEURISTIC_FIRST]);
	      vbox->add(*this->type_heuristic[Aiconfig::JAB_FOX - Aiconfig::HEURISTIC_FIRST]);
	      vbox->add(*this->type_heuristic[Aiconfig::TRY_FOR_DOPPELKOPF - Aiconfig::HEURISTIC_FIRST]);
	      vbox->add(*this->type_heuristic[Aiconfig::DRAW_TRUMP - Aiconfig::HEURISTIC_FIRST]);
	      vbox->add(*this->type_heuristic[Aiconfig::GET_TRICK_FOR_ANNOUNCEMENT - Aiconfig::HEURISTIC_FIRST]);

	      this->heuristic_notebook->append_page(*alignment, *label);
	      alignment->add(*vbox);
	    } // normal game
	    { // poverty
	      Gtk::Label* label = Gtk::manage(new Gtk::Label("poverty"));
	      this->ui->translations->add(*label,
					  ::translation("AiConfig::Heuristic::Group::poverty"));

	      Gtk::Alignment* alignment
		= Gtk::manage(new Gtk::Alignment(Gtk::ALIGN_CENTER,
						 Gtk::ALIGN_CENTER,
						 0, 0));
	      alignment->set_border_width(1 em);

	      Gtk::VBox* vbox = Gtk::manage(new Gtk::VBox(false, 1 ex / 2));

	      vbox->add(*(this->type_heuristic[Aiconfig::POVERTY_PLAYER_PLAY_PFUND - Aiconfig::HEURISTIC_FIRST]));

	      alignment->add(*vbox);
	      this->heuristic_notebook->append_page(*alignment, *label);
	    } // poverty
	    { // color solo
	      Gtk::Label* label = Gtk::manage(new Gtk::Label("color solo"));
	      this->ui->translations->add(*label,
					  ::translation("AiConfig::Heuristic::Group::Solo::color"));

	      Gtk::Alignment* alignment
		= Gtk::manage(new Gtk::Alignment(Gtk::ALIGN_CENTER,
						 Gtk::ALIGN_CENTER,
						 0, 0));
	      alignment->set_border_width(1 em);

	      Gtk::VBox* vbox = Gtk::manage(new Gtk::VBox(false, 1 ex / 2));

	      vbox->add(*this->type_heuristic[Aiconfig::COLOR_CHOOSE_ACE - Aiconfig::HEURISTIC_FIRST]);
	      vbox->add(*this->type_heuristic[Aiconfig::COLOR_BEST_WINNING - Aiconfig::HEURISTIC_FIRST]);
	      vbox->add(*this->type_heuristic[Aiconfig::COLOR_JAB_FOR_ACE - Aiconfig::HEURISTIC_FIRST]);
	      vbox->add(*this->type_heuristic[Aiconfig::COLOR_LOW_HIGH - Aiconfig::HEURISTIC_FIRST]);

	      alignment->add(*vbox);
	      this->heuristic_notebook->append_page(*alignment, *label);
	    } // color solo
	    { // picture solo
	      Gtk::Label* label = Gtk::manage(new Gtk::Label("picture solo"));
	      this->ui->translations->add(*label,
					  ::translation("AiConfig::Heuristic::Group::Solo::picture"));

	      Gtk::Alignment* alignment
		= Gtk::manage(new Gtk::Alignment(Gtk::ALIGN_CENTER,
						 Gtk::ALIGN_CENTER,
						 0, 0));
	      alignment->set_border_width(1 em);

	      Gtk::VBox* vbox = Gtk::manage(new Gtk::VBox(false, 1 ex / 2));

	      vbox->add(*this->type_heuristic[Aiconfig::PICTURE_SECONDBESTTRUMP - Aiconfig::HEURISTIC_FIRST]);

	      alignment->add(*vbox);
	      this->heuristic_notebook->append_page(*alignment, *label);
	    } // picture solo
	    { // meatless solo
	      Gtk::Label* label = Gtk::manage(new Gtk::Label("meatless solo"));
	      this->ui->translations->add(*label,
					  ::translation("AiConfig::Heuristic::Group::Solo::meatless"));

	      Gtk::Alignment* alignment
		= Gtk::manage(new Gtk::Alignment(Gtk::ALIGN_CENTER,
						 Gtk::ALIGN_CENTER,
						 0, 0));
	      alignment->set_border_width(1 em);

	      Gtk::VBox* vbox = Gtk::manage(new Gtk::VBox(false, 1 ex / 2));

	      vbox->add(*(this->type_heuristic[Aiconfig::MEATLESS_PLAYHIGHESTCOLOR - Aiconfig::HEURISTIC_FIRST]));

	      alignment->add(*vbox);
	      this->heuristic_notebook->append_page(*alignment, *label);
	    } // meatless solo

	    this->notebook->append_page(*this->heuristic_notebook, *label);
	  } // the heuristics
	  { // card limits
	    Gtk::Label* label = Gtk::manage(new Gtk::Label("card limits"));
	    this->ui->translations->add(*label,
					::translation("AiConfig::Group::card limits"));

	    this->card_limits_notebook = Gtk::manage(new Gtk::Notebook());

	    { // normal game
	      Gtk::Label* label = Gtk::manage(new Gtk::Label("normal game"));
	      this->ui->translations->add(*label,
					  ::translation("AiConfig::CardLimit::Group::normal game"));

	      Gtk::Alignment* alignment
		= Gtk::manage(new Gtk::Alignment(Gtk::ALIGN_CENTER,
						 Gtk::ALIGN_CENTER,
						 0, 0));
	      alignment->set_border_width(1 em);

	      Gtk::VBox* vbox = Gtk::manage(new Gtk::VBox(false, 1 ex / 2));

	      vbox->add(*this->type_card[Aiconfig::LIMITTHROWING - Aiconfig::CARD_FIRST]);
	      vbox->add(*this->type_card[Aiconfig::TRUMPLIMIT_NORMAL - Aiconfig::CARD_FIRST]);
	      vbox->add(*this->type_card[Aiconfig::LOWEST_TRUMPLIMIT_NORMAL - Aiconfig::CARD_FIRST]);
	      vbox->add(*this->type_card[Aiconfig::LIMITHIGH - Aiconfig::CARD_FIRST]);

	      alignment->add(*vbox);
	      this->card_limits_notebook->append_page(*alignment, *label);
	    } // normal game
	    { // other solo
	      Gtk::Label* label = Gtk::manage(new Gtk::Label("solo"));
	      this->ui->translations->add(*label,
					  ::translation("AiConfig::CardLimit::Group::solo"));

	      Gtk::Alignment* alignment
		= Gtk::manage(new Gtk::Alignment(Gtk::ALIGN_CENTER,
						 Gtk::ALIGN_CENTER,
						 0, 0));
	      alignment->set_border_width(1 em);
	      Gtk::Table* table = Gtk::manage(new Gtk::Table(1, 3, false));
	      table->set_row_spacings(1 ex / 2);
	      table->set_col_spacings(1 em / 2);
	      { // the table
		Gtk::Label* label;
		Gtk::Alignment* alignment;
		int row = 0;

		// title
		label = Gtk::manage(new Gtk::Label("trump limit"));
		this->ui->translations->add(*label,
					    ::translation("AiConfig::CardLimit::Group::trump limit"));
		table->attach(*label, 1, 2, row, row + 1);
		label = Gtk::manage(new Gtk::Label("lowest trump limit"));
		this->ui->translations->add(*label,
					    ::translation("AiConfig::CardLimit::Group::lowest trump limit"));
		table->attach(*label, 2, 3, row, row + 1);
		row += 1;
		table->set_row_spacing(0, 3 ex / 2);
		// color solo
		table->resize(row + 1, 3);
		label = Gtk::manage(new Gtk::Label("color solo"));
		this->ui->translations->add(*label,
					    ::translation("GameType::Group::Solo::color")
					    + ": ");
		alignment = Gtk::manage(new Gtk::Alignment(Gtk::ALIGN_RIGHT,
							   Gtk::ALIGN_CENTER,
							   0, 0));
		alignment->add(*label);
		table->attach(*alignment, 0, 1, row, row + 1);
		table->attach(*this->type_card[::Aiconfig::TRUMPLIMIT_SOLOCOLOR - ::Aiconfig::CARD_FIRST],
			      1, 2, row, row + 1);
		table->attach(*this->type_card[::Aiconfig::LOWEST_TRUMPLIMIT_SOLOCOLOR - ::Aiconfig::CARD_FIRST],
			      2, 3, row, row + 1);
		row += 1;
		// jack solo
		table->resize(row + 1, 3);
		label = Gtk::manage(new Gtk::Label("jack solo"));
		this->ui->translations->add(*label,
					    ::translation(GAMETYPE::SOLO_JACK)
					    + ": ");
		alignment = Gtk::manage(new Gtk::Alignment(Gtk::ALIGN_RIGHT,
							   Gtk::ALIGN_CENTER,
							   0, 0));
		alignment->add(*label);
		table->attach(*alignment, 0, 1, row, row + 1);
		table->attach(*this->type_card[::Aiconfig::TRUMPLIMIT_SOLOJACK - ::Aiconfig::CARD_FIRST],
			      1, 2, row, row + 1);
		table->attach(*this->type_card[::Aiconfig::LOWEST_TRUMPLIMIT_SOLOJACK - ::Aiconfig::CARD_FIRST],
			      2, 3, row, row + 1);
		row += 1;
		// queen solo
		table->resize(row + 1, 3);
		label = Gtk::manage(new Gtk::Label("queen solo"));
		this->ui->translations->add(*label,
					    ::translation(GAMETYPE::SOLO_QUEEN)
					    + ": ");
		alignment = Gtk::manage(new Gtk::Alignment(Gtk::ALIGN_RIGHT,
							   Gtk::ALIGN_CENTER,
							   0, 0));
		alignment->add(*label);
		table->attach(*alignment, 0, 1, row, row + 1);
		table->attach(*this->type_card[::Aiconfig::TRUMPLIMIT_SOLOQUEEN - ::Aiconfig::CARD_FIRST],
			      1, 2, row, row + 1);
		table->attach(*this->type_card[::Aiconfig::LOWEST_TRUMPLIMIT_SOLOQUEEN - ::Aiconfig::CARD_FIRST],
			      2, 3, row, row + 1);
		row += 1;
		// king solo
		table->resize(row + 1, 3);
		label = Gtk::manage(new Gtk::Label("king solo"));
		this->ui->translations->add(*label,
					    ::translation(GAMETYPE::SOLO_KING)
					    + ": ");
		alignment = Gtk::manage(new Gtk::Alignment(Gtk::ALIGN_RIGHT,
							   Gtk::ALIGN_CENTER,
							   0, 0));
		alignment->add(*label);
		table->attach(*alignment, 0, 1, row, row + 1);
		table->attach(*this->type_card[::Aiconfig::TRUMPLIMIT_SOLOKING - ::Aiconfig::CARD_FIRST],
			      1, 2, row, row + 1);
		table->attach(*this->type_card[::Aiconfig::LOWEST_TRUMPLIMIT_SOLOKING - ::Aiconfig::CARD_FIRST],
			      2, 3, row, row + 1);
		row += 1;
		// queen-jack solo
		table->resize(row + 1, 3);
		label = Gtk::manage(new Gtk::Label("queen-jack solo"));
		this->ui->translations->add(*label,
					    ::translation(GAMETYPE::SOLO_QUEEN_JACK)
					    + ": ");
		alignment = Gtk::manage(new Gtk::Alignment(Gtk::ALIGN_RIGHT,
							   Gtk::ALIGN_CENTER,
							   0, 0));
		alignment->add(*label);
		table->attach(*alignment, 0, 1, row, row + 1);
		table->attach(*this->type_card[::Aiconfig::TRUMPLIMIT_SOLOJACKQUEEN - ::Aiconfig::CARD_FIRST],
			      1, 2, row, row + 1);
		table->attach(*this->type_card[::Aiconfig::LOWEST_TRUMPLIMIT_SOLOJACKQUEEN - ::Aiconfig::CARD_FIRST],
			      2, 3, row, row + 1);
		row += 1;
		// king-jack solo
		table->resize(row + 1, 3);
		label = Gtk::manage(new Gtk::Label("king-jack solo"));
		this->ui->translations->add(*label,
					    ::translation(GAMETYPE::SOLO_KING_JACK)
					    + ": ");
		alignment = Gtk::manage(new Gtk::Alignment(Gtk::ALIGN_RIGHT,
							   Gtk::ALIGN_CENTER,
							   0, 0));
		alignment->add(*label);
		table->attach(*alignment, 0, 1, row, row + 1);
		table->attach(*this->type_card[::Aiconfig::TRUMPLIMIT_SOLOJACKKING - ::Aiconfig::CARD_FIRST],
			      1, 2, row, row + 1);
		table->attach(*this->type_card[::Aiconfig::LOWEST_TRUMPLIMIT_SOLOJACKKING - ::Aiconfig::CARD_FIRST],
			      2, 3, row, row + 1);
		row += 1;
		// king-queen solo
		table->resize(row + 1, 3);
		label = Gtk::manage(new Gtk::Label("queen-king solo"));
		this->ui->translations->add(*label,
					    ::translation(GAMETYPE::SOLO_KING_QUEEN)
					    + ": ");
		alignment = Gtk::manage(new Gtk::Alignment(Gtk::ALIGN_RIGHT,
							   Gtk::ALIGN_CENTER,
							   0, 0));
		alignment->add(*label);
		table->attach(*alignment, 0, 1, row, row + 1);
		table->attach(*this->type_card[::Aiconfig::TRUMPLIMIT_SOLOQUEENKING - ::Aiconfig::CARD_FIRST],
			      1, 2, row, row + 1);
		table->attach(*this->type_card[::Aiconfig::LOWEST_TRUMPLIMIT_SOLOQUEENKING - ::Aiconfig::CARD_FIRST],
			      2, 3, row, row + 1);
		row += 1;
		// koehler
		table->resize(row + 1, 3);
		label = Gtk::manage(new Gtk::Label("koehler solo"));
		this->ui->translations->add(*label,
					    ::translation(GAMETYPE::SOLO_KOEHLER)
					    + ": ");
		alignment = Gtk::manage(new Gtk::Alignment(Gtk::ALIGN_RIGHT,
							   Gtk::ALIGN_CENTER,
							   0, 0));
		alignment->add(*label);
		table->attach(*alignment, 0, 1, row, row + 1);
		table->attach(*this->type_card[::Aiconfig::TRUMPLIMIT_SOLOKOEHLER - ::Aiconfig::CARD_FIRST],
			      1, 2, row, row + 1);
		table->attach(*this->type_card[::Aiconfig::LOWEST_TRUMPLIMIT_SOLOKOEHLER - ::Aiconfig::CARD_FIRST],
			      2, 3, row, row + 1);
		row += 1;
		// meatless
		table->resize(row + 1, 3);
		label = Gtk::manage(new Gtk::Label("meatless solo"));
		this->ui->translations->add(*label,
					    ::translation(GAMETYPE::SOLO_MEATLESS)
					    + ": ");
		alignment = Gtk::manage(new Gtk::Alignment(Gtk::ALIGN_RIGHT,
							   Gtk::ALIGN_CENTER,
							   0, 0));
		alignment->add(*label);
		table->attach(*alignment, 0, 1, row, row + 1);
		table->attach(*this->type_card[::Aiconfig::TRUMPLIMIT_MEATLESS - ::Aiconfig::CARD_FIRST],
			      1, 2, row, row + 1);
		table->attach(*this->type_card[::Aiconfig::LOWEST_TRUMPLIMIT_MEATLESS - ::Aiconfig::CARD_FIRST],
			      2, 3, row, row + 1);
		row += 1;
	      } // the table
	      alignment->add(*table);
	      this->card_limits_notebook->append_page(*alignment, *label);

#ifdef OUTDATED
	      Gtk::Box* hbox = Gtk::manage(new Gtk::HBox(false, 1 em / 2));

	      { // left column
		Gtk::Alignment* alignment
		  = Gtk::manage(new Gtk::Alignment(Gtk::ALIGN_CENTER,
						   Gtk::ALIGN_CENTER,
						   0, 0));
		alignment->set_border_width(1 em);

		Gtk::Frame* frame = Gtk::manage(new Gtk::Frame("trumplimit"));
		this->ui->translations->add(*dynamic_cast<Gtk::Label*>(frame->get_label_widget()),
					    ::translation("AiConfig::CardLimit::Group::trump limit"));

		Gtk::VBox* vbox = Gtk::manage(new Gtk::VBox(false, 1 ex / 2));
		vbox->set_border_width(1 ex);

		vbox->add(*this->type_card[Aiconfig::TRUMPLIMIT_SOLOCOLOR - Aiconfig::CARD_FIRST]);
		vbox->add(*this->type_card[Aiconfig::TRUMPLIMIT_SOLOJACK - Aiconfig::CARD_FIRST]);
		vbox->add(*this->type_card[Aiconfig::TRUMPLIMIT_SOLOQUEEN - Aiconfig::CARD_FIRST]);
		vbox->add(*this->type_card[Aiconfig::TRUMPLIMIT_SOLOKING - Aiconfig::CARD_FIRST]);
		vbox->add(*this->type_card[Aiconfig::TRUMPLIMIT_SOLOJACKKING - Aiconfig::CARD_FIRST]);
		vbox->add(*this->type_card[Aiconfig::TRUMPLIMIT_SOLOJACKQUEEN - Aiconfig::CARD_FIRST]);
		vbox->add(*this->type_card[Aiconfig::TRUMPLIMIT_SOLOQUEENKING - Aiconfig::CARD_FIRST]);
		vbox->add(*this->type_card[Aiconfig::TRUMPLIMIT_SOLOKOEHLER - Aiconfig::CARD_FIRST]);
		vbox->add(*this->type_card[Aiconfig::TRUMPLIMIT_MEATLESS - Aiconfig::CARD_FIRST]);

		frame->add(*vbox);
		alignment->add(*frame);
		hbox->add(*alignment);
	      } // left column
	      { // right column
		Gtk::Alignment* alignment
		  = Gtk::manage(new Gtk::Alignment(Gtk::ALIGN_CENTER,
						   Gtk::ALIGN_CENTER,
						   0, 0));
		alignment->set_border_width(1 em);

		Gtk::Frame* frame = Gtk::manage(new Gtk::Frame("lowest trumplimit"));
		this->ui->translations->add(*dynamic_cast<Gtk::Label*>(frame->get_label_widget()),
					    ::translation("AiConfig::CardLimit::Group::lowest trump limit"));

		Gtk::VBox* vbox = Gtk::manage(new Gtk::VBox(false, 1 ex / 2));
		vbox->set_border_width(1 ex);

		vbox->add(*this->type_card[Aiconfig::LOWEST_TRUMPLIMIT_SOLOCOLOR - Aiconfig::CARD_FIRST]);
		vbox->add(*this->type_card[Aiconfig::LOWEST_TRUMPLIMIT_SOLOJACK - Aiconfig::CARD_FIRST]);
		vbox->add(*this->type_card[Aiconfig::LOWEST_TRUMPLIMIT_SOLOQUEEN - Aiconfig::CARD_FIRST]);
		vbox->add(*this->type_card[Aiconfig::LOWEST_TRUMPLIMIT_SOLOKING - Aiconfig::CARD_FIRST]);
		vbox->add(*this->type_card[Aiconfig::LOWEST_TRUMPLIMIT_SOLOJACKKING - Aiconfig::CARD_FIRST]);
		vbox->add(*this->type_card[Aiconfig::LOWEST_TRUMPLIMIT_SOLOJACKQUEEN - Aiconfig::CARD_FIRST]);
		vbox->add(*this->type_card[Aiconfig::LOWEST_TRUMPLIMIT_SOLOQUEENKING - Aiconfig::CARD_FIRST]);
		vbox->add(*this->type_card[Aiconfig::LOWEST_TRUMPLIMIT_SOLOKOEHLER - Aiconfig::CARD_FIRST]);
		vbox->add(*this->type_card[Aiconfig::LOWEST_TRUMPLIMIT_MEATLESS - Aiconfig::CARD_FIRST]);

		frame->add(*vbox);
		alignment->add(*frame);
		hbox->add(*alignment);
	      } // right column
	      this->card_limits_notebook->append_page(*hbox, *label);
#endif
	    } // other solo

	    this->notebook->append_page(*this->card_limits_notebook, *label);
	  } // card limits
	} // the notebook pages

	this->container->pack_start(*this->notebook, true, true);
      } // the settings

      return ;
    } // void Players::Player::AiConfig::create_container()

  /**
   ** -> result
   **
   ** @param	-
   **
   ** @return	the ai configuration
   **
   ** @author	Diether Knof
   **
   ** @version	0.5.4
   **/
  ::Aiconfig&
    Players::Player::AiConfig::aiconfig()
    {
      return dynamic_cast<Aiconfig&>(this->player->player());
    } // ::Aiconfig& Players::Player::AiConfig::aiconfig()

  /**
   ** the aitype has changed
   **
   ** @param	trickno		the trick number of the changed type
   **
   ** @return	-
   **
   ** @author	Diether Knof
   **
   ** @version	0.6.7
   **/
  void
    Players::Player::AiConfig::aitype_changed(unsigned const trickno)
    {
      AiType const aitype
	= *static_cast<AiType*>(this->aitype[trickno]->get_menu()->get_active()->get_data("aitype"));
      this->aiconfig().set_aitype(trickno, aitype);

      if ( (trickno < this->aitype_as_previous.size() - 1)
	  && !this->aitype_as_previous[trickno + 1]->get_active()) {
	this->aitype[trickno + 1]->set_history(this->aitype[trickno]->get_history());
	this->future_limit[trickno + 1]->set_value(this->future_limit[trickno]->get_value());
      }

      this->difficulty_selector->set_type(this->aiconfig().difficulty());

      return ;
    } // void Players::Player::AiConfig::aitype_changed(unsigned const trickno)

  /**
   ** the future limit has changed
   **
   ** @param	trickno		the trick number of the changed future limit
   **
   ** @return	-
   **
   ** @author	Diether Knof
   **
   ** @version	0.6.7
   **/
  void
    Players::Player::AiConfig::future_limit_changed(unsigned const trickno)
    {
      unsigned const future_limit
	= static_cast<unsigned>(this->future_limit[trickno]->get_value());
      this->aiconfig().set_future_limit(trickno, future_limit);

      if ( (trickno < this->aitype_as_previous.size() - 1)
	  && !this->aitype_as_previous[trickno + 1]->get_active())
	this->future_limit[trickno + 1]->set_value(future_limit);

      this->difficulty_selector->set_type(this->aiconfig().difficulty());

      return ;
    } // void Players::Player::AiConfig::future_limit_changed(unsigned const trickno)

  /**
   ** the aitype has changed
   **
   ** @param	trickno		the trick number of the changed type
   **
   ** @return	-
   **
   ** @author	Diether Knof
   **
   ** @version	0.6.7
   **/
  void
    Players::Player::AiConfig::aitype_as_previous_changed(unsigned const trickno)
    {
      DEBUG_ASSERTION(trickno > 0,
		      "AiConfig::aitype_as_previous_changed(trickno):\n"
		      "  'trickno' == 0");

      bool const active = this->aitype_as_previous[trickno]->get_active();
      this->aitype[trickno]->set_sensitive(active);
      this->future_limit[trickno]->set_sensitive(active);

      if (!active) {
	this->aitype[trickno]->set_history(this->aitype[trickno - 1]->get_history());
	this->future_limit[trickno]->set_value(this->future_limit[trickno - 1]->get_value());
      } // if (!active)

      return ;
    } // void Players::Player::AiConfig::aitype_as_previous_changed(unsigned const trickno)

  /**
   ** a aiconfig has been changed by the user
   **
   ** @param	type	the type of the aiconfig
   **
   ** @return	-
   **
   ** @author	Diether Knof
   **
   ** @version	0.5.4
   **/
  void
    Players::Player::AiConfig::change(int const type)
    {
      if ((type >= Aiconfig::HEURISTIC_FIRST)
	  && (type <= Aiconfig::HEURISTIC_LAST)) {
	this->aiconfig().set(Aiconfig::Heuristic(type),
			     this->type_heuristic[type - Aiconfig::HEURISTIC_FIRST]->get_active());
      }
      else if ((type >= Aiconfig::BOOL_FIRST)
	       && (type <= Aiconfig::BOOL_LAST))
	this->aiconfig().set(Aiconfig::TypeBool(type),
			     this->type_bool[type - Aiconfig::BOOL_FIRST]->get_active());
      else if ((type >= Aiconfig::UNSIGNED_FIRST)
	       && (type <= Aiconfig::UNSIGNED_LAST)) {
	if (this->type_unsigned[type - Aiconfig::UNSIGNED_FIRST]->is_realized())
	  this->aiconfig().set(Aiconfig::TypeUnsigned(type),
			       this->type_unsigned[type - Aiconfig::UNSIGNED_FIRST]->get_value_as_int());
      }
      else if ((type >= Aiconfig::CARD_FIRST)
	       && (type <= Aiconfig::CARD_LAST)) {
	if (this->type_card[type - Aiconfig::CARD_FIRST]->is_realized())
	  this->aiconfig().set(Aiconfig::TypeCard(type),
			       this->type_card[type - Aiconfig::CARD_FIRST]->card());
      }
      else 
	DEBUG_ASSERTION(false,
			"AiConfig::change(type):\n"
			"  type '" << type << "' unknown.");

      this->difficulty_selector->set_type(this->aiconfig().difficulty());

      return ;
    } // void Players::Player::AiConfig::change(int const type)

  /**
   ** sets the aiconfig to the selected difficulty
   **
   ** @param	-
   **
   ** @return	-
   **
   ** @author	Diether Knof
   **
   ** @version	0.7.2
   **/
  void
    Players::Player::AiConfig::difficulty_changed()
    {
      ::Aiconfig::Difficulty const difficulty
	= this->difficulty_selector->type();
      if (difficulty == ::Aiconfig::CUSTOM)
	return ;

      if (difficulty == this->aiconfig().difficulty())
	return ;

      for (unsigned t = 1; t < this->aitype.size(); ++t)
	this->aitype_as_previous[t]->set_active(true);

      this->aiconfig().set_to_difficulty(difficulty);
      this->update();

      for (unsigned t = 1; t < this->aitype.size(); ++t)
	if ((this->aiconfig().aitype(t)
	     == this->aiconfig().aitype(t - 1)
	     && (this->aiconfig().future_limit(t)
		 == this->aiconfig().future_limit(t - 1))))
	  this->aitype_as_previous[t]->set_active(false);

      return ;
    } // void Players::Player::AiConfig::difficulty_changed()

  /**
   ** sets the ai to the hardcoded
   **
   ** @param	-
   **
   ** @return	-
   **
   ** @author	Diether Knof
   **
   ** @version	0.5.4
   **/
  void
    Players::Player::AiConfig::hardcoded()
    {
      for (unsigned t = 1; t < this->aitype.size(); ++t)
	this->aitype_as_previous[t]->set_active(true);

      this->aiconfig().reset_to_hardcoded();
      this->update();

      for (unsigned t = 1; t < this->aitype.size(); ++t)
	if ((this->aiconfig().aitype(t)
	     == this->aiconfig().aitype(t - 1)
	     && (this->aiconfig().future_limit(t)
		 == this->aiconfig().future_limit(t - 1))))
	  this->aitype_as_previous[t]->set_active(false);


      return ;
    } // void Players::Player::AiConfig::hardcoded()

  /**
   ** creates a menu with the players to adopt from
   **
   ** @param	-
   **
   ** @return	-
   **
   ** @author	Diether Knof
   **
   ** @version	0.5.4
   **/
  void
    Players::Player::AiConfig::adopt()
    {

      Gtk::Menu* adopt_menu
	= Gtk::manage(new Gtk::Menu());
      adopt_menu->add(*(Gtk::manage(new Gtk::TearoffMenuItem())));

      for (unsigned p = 0; p < this->ui->party().playerno(); p++)
	if (p != this->player->playerno()) {
	  Gtk::MenuItem* item
	    = Gtk::manage(new Gtk::MenuItem(this->player->players->player(p).player().name()));
	  item->signal_activate().connect(sigc::bind<unsigned const>(sigc::mem_fun(*this, &AiConfig::adopt_aiconfig), p));
	  adopt_menu->append(*item);
	} // if (p != this->player().playerno())

      adopt_menu->show_all();
      adopt_menu->popup(0, 0);

      return ;
    } // void Players::Player::AiConfig::adopt()

  /**
   ** adopt the aiconfig from player 'playerno'
   **
   ** @param	playerno	player to adopt from
   **
   ** @return	-
   **
   ** @author	Diether Knof
   **
   ** @version	0.5.4
   **/
  void
    Players::Player::AiConfig::adopt_aiconfig(unsigned const playerno)
    {
#ifdef RELEASE
      DEBUG_ASSERTION((::game_status == GAMESTATUS::PARTY_NEW),
		      "Players::Player::AiConfig::adopt_aiconfig():\n"
		      "  game status is not party_init: "
		      << ::game_status);
#endif
      for (unsigned t = 1; t < this->aitype.size(); ++t)
	this->aitype_as_previous[t]->set_active(true);

      this->aiconfig()
	= this->player->players->player(playerno).aiconfig().aiconfig();
      this->update();

      for (unsigned t = 1; t < this->aitype.size(); ++t)
	if ((this->aiconfig().aitype(t)
	     == this->aiconfig().aitype(t - 1)
	     && (this->aiconfig().future_limit(t)
		 == this->aiconfig().future_limit(t - 1))))
	  this->aitype_as_previous[t]->set_active(false);

      return ;
    } // void Players::Player::AiConfig::adopt_aiconfig(unsigned const playerno)

  /**
   ** make all other aiconfigs like this
   **
   ** @param	-
   **
   ** @return	-
   **
   ** @author	Diether Knof
   **
   ** @version	0.5.4
   **/
  void
    Players::Player::AiConfig::allot()
    {
      for (unsigned p = 0; p < ::party.playerno(); p++)
	if (p != this->player->playerno())
	  this->player->players->player(p).aiconfig().adopt_aiconfig(this->player->playerno());

      return ;
    } // void Players::Player::AiConfig::allot()

  /**
   ** creates a menu with the files in the aiconfig directories
   **
   ** @param	-
   **
   ** @return	-
   **
   ** @author	Diether Knof
   **
   ** @version	0.5.4
   **/
  void
    Players::Player::AiConfig::load()
    {

      Gtk::FileMenu* load_menu
	= Gtk::manage(new Gtk::FileMenu(sigc::mem_fun(*this, &AiConfig::load_file)));
      load_menu->add_directory(::setting(Setting::PRIVATE_DATA_DIRECTORY)
			       + "/"
			       + ::setting(Setting::AI_DIRECTORY));
      load_menu->add_directory(::setting(Setting::PUBLIC_DATA_DIRECTORY)
			       + "/"
			       + ::setting(Setting::AI_DIRECTORY));

      load_menu->show();

      return ;
    } // void Players::Player::AiConfig::load()

  /**
   ** loads the aiconfig
   **
   ** @param	filename	the aiconfig file
   **
   ** @return	-
   **
   ** @author	Diether Knof
   **
   ** @version	0.5.4
   **/
  void
    Players::Player::AiConfig::load_file(string const filename)
    {
      for (unsigned t = 1; t < this->aitype.size(); ++t)
	this->aitype_as_previous[t]->set_active(true);

      this->aiconfig().load(filename);
      this->update();

      for (unsigned t = 1; t < this->aitype.size(); ++t)
	if ((this->aiconfig().aitype(t)
	     == this->aiconfig().aitype(t - 1)
	     && (this->aiconfig().future_limit(t)
		 == this->aiconfig().future_limit(t - 1))))
	  this->aitype_as_previous[t]->set_active(false);

      return ;
    } // void Players::Player::AiConfig::load_file(string const filename)

  /**
   ** saves the aiconfig.
   ** The filename is taken from 'save_file_selector'.
   **
   ** @param	filename	the aiconfig file
   **
   ** @return	-
   **
   ** @author	Diether Knof
   **
   ** @version	0.5.4
   **/
  void
    Players::Player::AiConfig::save()
    {
      this->aiconfig().save(this->save_file_selector->get_filename()); 

      return ;
    } // void Players::Player::AiConfig::save()

  /**
   ** update the sensitivity of all widgets
   **
   ** @param	-
   **
   ** @return	-
   **
   ** @author	Diether Knof
   **
   ** @version	0.7.2
   **/
  void
    Players::Player::AiConfig::sensitivity_update()
    {
      bool sensitive = (::game_status == GAMESTATUS::PARTY_NEW);
#ifndef RELEASE
      sensitive = true;
#endif
#ifdef USE_NETWORK
      sensitive &= (this->player->player().type() != ::Player::NETWORK);
#endif

      this->hardcoded_button->set_sensitive(sensitive);
      this->adopt_button->set_sensitive(sensitive);
      this->allot_button->set_sensitive(sensitive);
      this->load_button->set_sensitive(sensitive);
      this->save_button->set_sensitive(true);
      this->difficulty_selector->set_sensitive(sensitive);

      for (vector<Gtk::CheckButton*>::iterator t = this->type_heuristic.begin();
	   t != this->type_heuristic.end();
	   t++)
	(*t)->set_sensitive(sensitive);
      for (vector<Gtk::CheckButton*>::iterator t = this->type_bool.begin();
	   t != this->type_bool.end();
	   t++)
	(*t)->set_sensitive(sensitive);
      for (vector<Gtk::LabelSpinButton*>::iterator
	   t = this->type_unsigned.begin();
	   t != this->type_unsigned.end();
	   t++)
	(*t)->set_sensitive(sensitive);
      for (vector<Gtk::LabelCardSelector*>::iterator
	   t = this->type_card.begin();
	   t != this->type_card.end();
	   t++)
	(*t)->set_sensitive(sensitive);

      for (unsigned t = 0; t < this->aitype.size(); ++t) {
	this->aitype[t]->set_sensitive(sensitive);
	this->future_limit[t]->set_sensitive(sensitive);
	this->aitype_as_previous[t]->set_sensitive(sensitive);
      }
      for (unsigned t = 1; t < this->aitype.size(); ++t)
	if (!this->aitype_as_previous[t]->get_active()) {
	  this->aitype[t]->set_sensitive(false);
	  this->future_limit[t]->set_sensitive(false);
	}

      return ;
    } // void Players::Player::AiConfig::sensitivity_update()

  /**
   ** update all widgets
   **
   ** @param	-
   **
   ** @return	-
   **
   ** @author	Diether Knof
   **
   ** @version	0.7.2
   **/
  void
    Players::Player::AiConfig::update()
    {
      this->difficulty_selector->set_type(this->aiconfig().difficulty());

      for (unsigned t = 0; t < this->aitype.size(); ++t) {
	if ((t < this->aitype.size() - 1)
	    && (   (this->aiconfig().aitype(t + 1)
		    != this->aiconfig().aitype(t))
		|| (this->aiconfig().future_limit(t + 1)
		    != this->aiconfig().future_limit(t))))
	  this->aitype_as_previous[t + 1]->set_active(true);
	this->aitype[t]->set_history(this->aiconfig().aitype(t) - 1);
	this->future_limit[t]->set_value(this->aiconfig().future_limit(t));
      }

      for (vector<Gtk::CheckButton*>::iterator widget = this->type_heuristic.begin();
	   widget != this->type_heuristic.end();
	   widget++)
	(*widget)->set_active(this->aiconfig().value(*static_cast<Aiconfig::Heuristic*>((*widget)->get_data("type"))));
      for (vector<Gtk::CheckButton*>::iterator widget = this->type_bool.begin();
	   widget != this->type_bool.end();
	   widget++)
	(*widget)->set_active(this->aiconfig().value(*static_cast<Aiconfig::TypeBool*>((*widget)->get_data("type"))));
      for (vector<Gtk::LabelSpinButton*>::iterator widget
	   = this->type_unsigned.begin();
	   widget != this->type_unsigned.end();
	   widget++) {
	Aiconfig::TypeUnsigned type
	  = *static_cast<Aiconfig::TypeUnsigned*>((*widget)->get_data("type"));
	(*widget)->set_range(this->aiconfig().min(type),
			     this->aiconfig().max(type));
	(*widget)->set_value(this->aiconfig().value(type));
      } // for (widget \in this->type_unsigned)
      for (vector<Gtk::LabelCardSelector*>::iterator
	   widget = this->type_card.begin();
	   widget != this->type_card.end();
	   widget++) {
	Aiconfig::TypeCard type
	  = *static_cast<Aiconfig::TypeCard*>((*widget)->get_data("type"));
	(*widget)->set_card(this->aiconfig().value(type));
      } // for (widget \in this->type_card)

      return ;
    } // void Players::Player::AiConfig::update()

  /**
   ** update the name
   **
   ** @param	-
   **
   ** @return	-
   **
   ** @author	Diether Knof
   **
   ** @version	0.5.4
   **
   ** @todo	block 'Entry::change_signal()'
   **/
  void
    Players::Player::AiConfig::name_update()
    {
      this->ui->translations->change(*(this->save_file_selector),
				     ::translation("Save aiconfig of %splayer%",
						   this->player->player().name()));

      return ;
    } // void Players::Player::AiConfig::name_update()

  /**
   ** update the language
   **
   ** @param	-
   **
   ** @return	-
   **
   ** @author	Diether Knof
   **
   ** @version	0.7.2
   **/
  void
    Players::Player::AiConfig::language_update()
    {
      for (vector<Gtk::LabelCardSelector*>::iterator
	   s = this->type_card.begin();
	   s != this->type_card.end();
	   ++s)
	(*s)->language_update();

      return ;
    } // void Players::Player::AiConfig::language_update()

} // namespace UI_GTKMM_NS

#endif // #ifdef USE_UI_GTKMM
