/**********************************************************************
 *
 *   FreeDoko a Doppelkopf-Game
 *    
 *   Copyright (C) 2001-2004  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"

#include "widgets/labelscalespinbutton.h"
#include "widgets/filemenu.h"
#include "widgets/stock_button.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::Object(),
    player(player),
    container(NULL),
    notebook(NULL),
    heuristic_notebook(NULL),
    hardcoded_button(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()
  {
    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::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	-
   **
   ** @version	0.5.4
   **
   ** @author	Diether Knof
   **
   **/
  void
    Players::Player::AiConfig::init()
    {
      this->hardcoded_button
	= Gtk::manage(new Gtk::StockButton(Gtk::Stock::CLEAR, "hardcoded"));
      this->ui->translations->add(*(this->hardcoded_button),
				  ::translator("hardcoded"));
      this->adopt_button
	= Gtk::manage(new Gtk::StockButton("adopt"));
      this->ui->translations->add(*(this->adopt_button),
				  ::translator("adopt"));
      this->allot_button
	= Gtk::manage(new Gtk::StockButton("allot"));
      this->ui->translations->add(*(this->allot_button),
				  ::translator("allot"));
      this->load_button
	= Gtk::manage(new Gtk::StockButton(Gtk::Stock::OPEN, "load"));
      this->ui->translations->add(*(this->load_button),
				  ::translator("load"));
      this->save_button
	= Gtk::manage(new Gtk::StockButton(Gtk::Stock::SAVE_AS, "save"));
      this->ui->translations->add(*(this->save_button),
				  ::translator("save"));
      this->save_file_selector = new Gtk::FileSelection("Save aiconfig");
      this->ui->translations->add(*(this->save_file_selector),
				  ::translator("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

      { // create the buttons
#ifdef OUTEDATED
	// 0.6.7	2004-11-21
	Gtk::RadioButton::Group aitype_group;
	for (int t = AITYPE::AITYPE_FIRST; t <= AITYPE::AITYPE_LAST; t++) {
	  this->aitype.push_back(Gtk::manage(new Gtk::RadioButton(aitype_group,
								  ::name(AiType(t)))));
	  this->aitype.back()->set_data("type", new AiType(AiType(t)));
	  this->ui->translations->add(*(this->aitype.back()),
				      ::translator(::name(AiType(t))));
	  this->aitype.back()->signal_toggled().connect(SigC::bind<int const>(SigC::slot(*this, &AiConfig::aitype_change),
									      t)
						       );
	}
#endif
	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()),
				      ::translator(::name(Aiconfig::Heuristic(t))));
	  this->type_heuristic.back()->signal_toggled().connect(SigC::bind<int const>(SigC::slot(*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()),
				      ::translator(::name(Aiconfig::TypeBool(t))));
	  this->type_bool.back()->signal_toggled().connect(SigC::bind<int const>(SigC::slot(*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:
	    this->type_unsigned.push_back(Gtk::manage(new Gtk::LabelScaleSpinButton(::name(Aiconfig::TypeUnsigned(t)))));
	    break;
	  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(),
				      ::translator("%ttranslation%: ",
						   ::translator(::name(Aiconfig::TypeUnsigned(t)))));
	  this->type_unsigned.back()->signal_value_changed().connect(SigC::bind<int const>(SigC::slot(*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)
      } // create the buttons

      this->create_container();

      // the signals
      this->hardcoded_button->signal_clicked().connect(SigC::slot(*this, &AiConfig::hardcoded));
      this->adopt_button->signal_clicked().connect(SigC::slot(*this, &AiConfig::adopt));
      this->allot_button->signal_clicked().connect(SigC::slot(*this, &AiConfig::allot));
      this->load_button->signal_clicked().connect(SigC::slot(*this, &AiConfig::load));
      this->save_button->signal_clicked().connect(SigC::slot(*(this->save_file_selector), &Widget::show));

      this->save_file_selector->get_cancel_button()->signal_clicked().connect(SigC::slot(*(this->save_file_selector), &Widget::hide));
      this->save_file_selector->get_ok_button()->signal_clicked().connect(SigC::slot(*(this->save_file_selector), &Widget::hide));
      this->save_file_selector->get_ok_button()->signal_clicked().connect(SigC::slot(*this, &AiConfig::save));

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

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

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

      { // the buttons for loading/saving
	Gtk::Alignment*
	  alignment = Gtk::manage(new Gtk::Alignment(Gtk::ALIGN_CENTER,
						     Gtk::ALIGN_CENTER,
						     0, 0));
	this->container->pack_end(*alignment, false, true);

	Gtk::Frame* frame = Gtk::manage(new Gtk::Frame());
	frame->set_border_width(1 em / 2);
	alignment->add(*frame);

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

	table->attach(*(this->hardcoded_button), 0, 1, 1, 3);
	table->attach(*(this->adopt_button), 1, 2, 0, 2);
	table->attach(*(this->allot_button), 2, 3, 0, 2);
	table->attach(*(this->load_button), 1, 2, 2, 4);
	table->attach(*(this->save_button), 2, 3, 2, 4);
      } // the buttons for loading/saving
      { // the settings
	this->notebook = Gtk::manage(new Gtk::Notebook());
	this->container->pack_start(*(this->notebook), true, true);
	{ // the notebook pages
	  Gtk::Alignment* alignment = NULL;
	  Gtk::VBox* vbox = NULL;
	  { // simple settings
	    alignment = Gtk::manage(new Gtk::Alignment(Gtk::ALIGN_CENTER,
						       Gtk::ALIGN_CENTER,
						       0, 0));
	    alignment->set_border_width(1 em);
	    Gtk::Label* label = Gtk::manage(new Gtk::Label("simple"));
	    this->ui->translations->add(*label,
					::translator("simple"));
	    this->notebook->append_page(*alignment, *label);

	    vbox = Gtk::manage(new Gtk::VBox(false, 1 em));
	    alignment->add(*vbox);

	    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]));
#ifdef OUTDATED
	    // 0.6.7   2004-11-29
	    // split the future limit for each trick
	    vbox->add(*(this->type_unsigned[Aiconfig::FUTURE_LIMIT - Aiconfig::UNSIGNED_FIRST]));
#endif
	  } // simple settings
	  { // aitype
	    alignment = Gtk::manage(new Gtk::Alignment(Gtk::ALIGN_CENTER,
						       Gtk::ALIGN_CENTER,
						       0, 0));
	    alignment->set_border_width(1 em);
	    Gtk::Label* label = Gtk::manage(new Gtk::Label("aitype"));
	    this->ui->translations->add(*label,
					::translator("aitype"));
	    this->notebook->append_page(*alignment, *label);

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

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

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

	      label = Gtk::manage(new Gtk::Label("future limit"));
	      this->ui->translations->add(*label, ::translator("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));
		  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::slot(*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())),
					      ::translator(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::slot(*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::slot(*this, &AiConfig::future_limit_changed), t));
	      } // future limit
	    } // for (t < MAX_NUMBER_OF_TRICKS_IN_GAME)

	  } // aitype
#ifdef OUTEDATED
	  // 0.6.7	2004-11-21
	  { // aitype
	    alignment = Gtk::manage(new Gtk::Alignment(Gtk::ALIGN_CENTER,
						       Gtk::ALIGN_CENTER,
						       0, 0));
	    alignment->set_border_width(1 em);
	    Gtk::Label* label = Gtk::manage(new Gtk::Label("aitype"));
	    this->ui->translations->add(*label,
					::translator("aitype"));
	    this->notebook->append_page(*alignment, *label);

	    vbox = Gtk::manage(new Gtk::VBox(false, 1 em));
	    alignment->add(*vbox);

	    for (int t = AITYPE::AITYPE_FIRST + 1;
		 t <= AITYPE::AITYPE_LAST;
		 t++)
	      vbox->add(*(this->aitype[t - AITYPE::AITYPE_FIRST]));
	  } // aitype
#endif
	  { // announcement
	    alignment = Gtk::manage(new Gtk::Alignment(Gtk::ALIGN_CENTER,
						       Gtk::ALIGN_CENTER,
						       0, 0));
	    alignment->set_border_width(1 em);
	    Gtk::Label* label = Gtk::manage(new Gtk::Label("announcement"));
	    this->ui->translations->add(*label,
					::translator("announcement"));
	    this->notebook->append_page(*alignment, *label);

	    vbox = Gtk::manage(new Gtk::VBox(false, 1 em));
	    alignment->add(*vbox);

	    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]));
	  } // announcement
	  { // trick decision
	    alignment = Gtk::manage(new Gtk::Alignment(Gtk::ALIGN_CENTER,
						       Gtk::ALIGN_CENTER,
						       0, 0));
	    alignment->set_border_width(1 em);
	    Gtk::Label* label = Gtk::manage(new Gtk::Label("trick decision"));
	    this->ui->translations->add(*label,
					::translator("trick decision"));
	    this->notebook->append_page(*alignment, *label);

	    vbox = Gtk::manage(new Gtk::VBox(false, 1 em));
	    alignment->add(*vbox);

	    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::LASTFEHLCREATION - Aiconfig::UNSIGNED_FIRST]));
	    vbox->add(*(this->type_unsigned[Aiconfig::LIMITQUEEN - Aiconfig::UNSIGNED_FIRST]));
	    vbox->add(*(this->type_unsigned[Aiconfig::LIMITDOLLE - Aiconfig::UNSIGNED_FIRST]));
	  } // trick decision
	  { // game decision
	    alignment = Gtk::manage(new Gtk::Alignment(Gtk::ALIGN_CENTER,
						       Gtk::ALIGN_CENTER,
						       0, 0));
	    alignment->set_border_width(1 em);
	    Gtk::Label* label = Gtk::manage(new Gtk::Label("game decision"));
	    this->ui->translations->add(*label,
					::translator("game decision"));
	    this->notebook->append_page(*alignment, *label);

	    vbox = Gtk::manage(new Gtk::VBox(false, 1 em));
	    alignment->add(*vbox);

	    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]));
	  } // game decision
	  { // the heuristics
	    this->heuristic_notebook = Gtk::manage(new Gtk::Notebook());
	    Gtk::Label* label = Gtk::manage(new Gtk::Label("heuristics"));
	    this->ui->translations->add(*label,
					::translator("heuristics"));
	    this->notebook->append_page(*(this->heuristic_notebook), *label);

	    { // normal game
	      alignment = Gtk::manage(new Gtk::Alignment(Gtk::ALIGN_CENTER,
							 Gtk::ALIGN_CENTER,
							 0, 0));
	      alignment->set_border_width(1 em);
	      Gtk::Label* label = Gtk::manage(new Gtk::Label("normal game"));
	      this->ui->translations->add(*label,
					  ::translator("normal game"));
	      this->heuristic_notebook->append_page(*alignment, *label);

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

	      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::SERVE_COLOR_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::DRAW_TRUMP - Aiconfig::HEURISTIC_FIRST]));
	    } // normal game
	    { // color solo
	      alignment = Gtk::manage(new Gtk::Alignment(Gtk::ALIGN_CENTER,
							 Gtk::ALIGN_CENTER,
							 0, 0));
	      alignment->set_border_width(1 em);
	      Gtk::Label* label = Gtk::manage(new Gtk::Label("color solo"));
	      this->ui->translations->add(*label,
					  ::translator("color solo"));
	      this->heuristic_notebook->append_page(*alignment, *label);

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

	      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]));
	    } // color solo
	    { // picture solo
	      alignment = Gtk::manage(new Gtk::Alignment(Gtk::ALIGN_CENTER,
							 Gtk::ALIGN_CENTER,
							 0, 0));
	      alignment->set_border_width(1 em);
	      Gtk::Label* label = Gtk::manage(new Gtk::Label("picture solo"));
	      this->ui->translations->add(*label,
					  ::translator("picture solo"));
	      this->heuristic_notebook->append_page(*alignment, *label);

	      vbox = Gtk::manage(new Gtk::VBox(false, 1 ex / 2));
	      alignment->add(*vbox);
	      vbox->add(*(this->type_heuristic[Aiconfig::PICTURE_SECONDBESTTRUMP - Aiconfig::HEURISTIC_FIRST]));
	    } // picture solo
	    { // meatless solo
	      alignment = Gtk::manage(new Gtk::Alignment(Gtk::ALIGN_CENTER,
							 Gtk::ALIGN_CENTER,
							 0, 0));
	      alignment->set_border_width(1 em);
	      Gtk::Label* label = Gtk::manage(new Gtk::Label("meatless solo"));
	      this->ui->translations->add(*label,
					  ::translator("meatless solo"));
	      this->heuristic_notebook->append_page(*alignment, *label);

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

	      vbox->add(*(this->type_heuristic[Aiconfig::MEATLESS_PLAYHIGHESTCOLOR - Aiconfig::HEURISTIC_FIRST]));
	    } // meatless solo
	  } // the heuristics
	} // the notebook pages
      } // the settings

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

  /**
   **
   ** -> result
   **
   ** @param	-
   **
   ** @return	the ai configuration
   **
   ** @version	0.5.4
   **
   ** @author	Diether Knof
   **
   **/
  ::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	-
   **
   ** @version	0.6.7
   **
   ** @author	Diether Knof
   **
   **/
  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());
      }

      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	-
   **
   ** @version	0.6.7
   **
   ** @author	Diether Knof
   **
   **/
  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);

      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	-
   **
   ** @version	0.6.7
   **
   ** @author	Diether Knof
   **
   **/
  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	-
   **
   ** @version	0.5.4
   **
   ** @author	Diether Knof
   **
   **/
  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 
	DEBUG_ASSERTION(false,
			"AiConfig::change(type):\n"
			"  type '" << type << "' unknown.");

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

  /**
   **
   ** sets the ai to the hardcoded
   **
   ** @param	-
   **
   ** @return	-
   **
   ** @version	0.5.4
   **
   ** @author	Diether Knof
   **
   **/
  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	-
   **
   ** @version	0.5.4
   **
   ** @author	Diether Knof
   **
   **/
  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 < ::party.playerno(); p++)
	if (p != this->player->playerno()) {
	  Gtk::MenuItem* item
	    = Gtk::manage(new Gtk::MenuItem(Glib::locale_to_utf8(this->player->players->player(p).player().name())));
	  item->signal_activate().connect(SigC::bind<unsigned const>(SigC::slot(*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	-
   **
   ** @version	0.5.4
   **
   ** @author	Diether Knof
   **
   **/
  void
    Players::Player::AiConfig::adopt_aiconfig(unsigned const playerno)
    {
#ifdef RELEASE
      DEBUG_ASSERTION((::game_status == GAMESTATUS::PARTY_INIT),
		      "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	-
   **
   ** @version	0.5.4
   **
   ** @author	Diether Knof
   **
   **/
  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	-
   **
   ** @version	0.5.4
   **
   ** @author	Diether Knof
   **
   **/
  void
    Players::Player::AiConfig::load()
    {

      Gtk::FileMenu* load_menu
	= Gtk::manage(new Gtk::FileMenu(SigC::slot(*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	-
   **
   ** @version	0.5.4
   **
   ** @author	Diether Knof
   **
   **/
  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	-
   **
   ** @version	0.5.4
   **
   ** @author	Diether Knof
   **
   **/
  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	-
   **
   ** @version	0.6.0
   **
   ** @author	Diether Knof
   **
   **/
  void
    Players::Player::AiConfig::sensitivity_update()
    {
#ifdef RELEASE
      if (::game_status == GAMESTATUS::PARTY_INIT)
#else
	;
      // be carful when changing the ai during the game
      if (true)
#endif
      {
	this->hardcoded_button->set_sensitive(true);
	this->adopt_button->set_sensitive(true);
	this->allot_button->set_sensitive(true);
	this->load_button->set_sensitive(true);
	this->save_button->set_sensitive(true);

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

	for (unsigned t = 0; t < this->aitype.size(); ++t) {
	  this->aitype[t]->set_sensitive(true);
	  this->future_limit[t]->set_sensitive(true);
	  this->aitype_as_previous[t]->set_sensitive(true);
	}
	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);
	  }
      } else { // if !(::game_status == GAMESTATUS::PARTY_INIT)
	this->hardcoded_button->set_sensitive(false);
	this->adopt_button->set_sensitive(false);
	this->allot_button->set_sensitive(false);
	this->load_button->set_sensitive(false);

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

	for (unsigned t = 0; t < this->aitype.size(); ++t) {
	  this->aitype[t]->set_sensitive(false);
	  this->future_limit[t]->set_sensitive(false);
	  this->aitype_as_previous[t]->set_sensitive(false);
	}
      } // if !(::game_status == GAMESTATUS::PARTY_INIT) 

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

  /**
   **
   ** update all widgets
   **
   ** @param	-
   **
   ** @return	-
   **
   ** @version	0.5.4
   **
   ** @author	Diether Knof
   **
   **/
  void
    Players::Player::AiConfig::update()
    {
      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->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)

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

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

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

} // namespace UI_GTKMM_NS

#endif // #ifdef USE_UI_GTKMM
