/**********************************************************************
 *
 *   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 "rules.h"
#include "ui.h"

#include "../../party/party.h"
#include "../../party/rule.h"
#include "../../misc/setting.h"
#ifdef WINDOWS
#include "../../utils/string.h"
#endif

#include "widgets/labelscalespinbutton.h"
#include "widgets/filemenu.h"
#include "widgets/stock_button.h"
#include <gtkmm/main.h>
#include <gtkmm/stock.h>
#include <gtkmm/label.h>
#include <gtkmm/alignment.h>
#include <gtkmm/checkbutton.h>
#include <gtkmm/box.h>
#include <gtkmm/table.h>
#include <gtkmm/separator.h>
#include <gtkmm/fileselection.h>
#include <gtkmm/sizegroup.h>

namespace UI_GTKMM_NS {

  /**
   **
   ** Constructor
   **
   ** @param	-
   **
   ** @return	-
   ** 
   ** @author	Diether Knof
   **
   ** @version	0.5.4
   **
   **/
  Rules::Rules(Base* const parent) :
    Base(parent),
  Notebook(),
  container(Gtk::manage(new Gtk::VBox())),
  type_bool(),
  type_unsigned(),
  load_button(NULL),
  save_button(NULL),
  save_file_selector(NULL),
  backup_(NULL)
  {
    DEBUG_CALLING(INFO_GTKMM_RULES && INFO_GTKMM_INIT,
		  "Rules::Rules(parent)");

#ifdef POSTPHONED
    this->signal_realize().connect(SigC::slot(*this, &Rules::init));
#else
    this->init();
    this->signal_realize().connect(SigC::slot(*this, &Rules::language_update));
    this->signal_realize().connect(SigC::slot(*this, &Rules::update_all));
#endif

    this->create_backup();

    DEBUG_RETURNING(VOID,
		    INFO_GTKMM_RULES && INFO_GTKMM_INIT,
		    "Rules::Rules(parent)");
  } // Rules::Rules(Base* const parent)

  /**
   **
   ** Destruktor
   **
   ** @param	-
   **
   ** @return	-
   ** 
   ** @author	Diether Knof
   **
   ** @version	0.5.4
   **
   **/
  Rules::~Rules()
  {
    DEBUG_CALLING(INFO_GTKMM_RULES && INFO_GTKMM_INIT,
		  "Rules::~Rules()");

    delete this->save_file_selector;

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

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

    delete this->backup_;

    DEBUG_RETURNING(VOID,
		    INFO_GTKMM_RULES && INFO_GTKMM_INIT,
		    "Rules::~Rules()");
  } // Rules::~Rules()

  /**
   **
   ** creates all subelements
   **
   ** @param	-
   **
   ** @return	-
   **
   ** @version	0.5.4
   **
   ** @author	Diether Knof
   **
   **/
  void
    Rules::init()
    {
      DEBUG_CALLING(INFO_GTKMM_RULES && INFO_GTKMM_INIT,
		    "Rules::init()");

      this->set_scrollable(true);
      this->popup_enable();

      this->load_button
	= Gtk::manage(new Gtk::StockButton("load"));
      this->ui->add_for_translation(*(this->load_button),
				    ::translator("load"));
      this->save_button
	= Gtk::manage(new Gtk::StockButton(Gtk::Stock::SAVE_AS, "save"));
      this->ui->add_for_translation(*(this->save_button),
				    ::translator("save"));
      this->save_file_selector = new Gtk::FileSelection("Save rules");
      this->ui->add_for_translation(*(this->save_file_selector),
				    ::translator("Save rules"));

#ifndef WINDOWS
      this->save_file_selector->set_filename(::setting(Setting::PRIVATE_DATA_DIRECTORY)
					     + "/"
					     + ::setting(Setting::RULES_DIRECTORY)
					     + "/");
#else // #ifndef WINDOWS
      {
	string filename = (::setting(Setting::PRIVATE_DATA_DIRECTORY)
			   + "/"
			   + ::setting(Setting::RULES_DIRECTORY)
			   + "/"
			  );
	DK::Utils::String::replace_all(filename, "/", "\\");
	this->save_file_selector->set_filename(filename);
      }
#endif // #ifndef WINDOWS

      { // put the notebook and the buttons in the container
	this->container->add(*this);

	Gtk::HBox* hbox = Gtk::manage(new Gtk::HBox(true));
	this->container->pack_end(*hbox, false, true);

	hbox->add(*(this->load_button));
	hbox->add(*(this->save_button));
      } // put the notebook and the buttons in the container


      { // create the buttons
	for (int t = Rule::BOOL_FIRST; t <= Rule::BOOL_LAST; t++) {
	  this->type_bool.push_back(Gtk::manage(new Gtk::CheckButton(::name(Rule::TypeBool(t)))));
	  this->type_bool.back()->set_data("type", new Rule::TypeBool(Rule::TypeBool(t)));
	  this->ui->add_for_translation(*(this->type_bool.back()),
					::translator(::name(Rule::TypeBool(t))));
	  this->type_bool.back()->signal_toggled().connect(SigC::bind<int const>(SigC::slot(*this, &Rules::change),
										 t)
							  );
	} // for (t \in Rule::BOOL)
	for (int t = Rule::UNSIGNED_FIRST; t <= Rule::UNSIGNED_LAST; t++) {
	  switch (t) {
	  case Rule::SHOW_TRICKS_NUMBER:
	  case Rule::MARRIAGE_DETERMINATION:
	  case Rule::ANNOUNCEMENT_NO_120:
	  case Rule::ANNOUNCEMENT_NO_90:
	  case Rule::ANNOUNCEMENT_NO_60:
	  case Rule::ANNOUNCEMENT_NO_30:
	  case Rule::ANNOUNCEMENT_NO_0:
	  case Rule::ANNOUNCEMENT_LAST:
	    this->type_unsigned.push_back(Gtk::manage(new Gtk::LabelScaleSpinButton()));
	    break;
	  default:
	    this->type_unsigned.push_back(Gtk::manage(new Gtk::LabelSpinButton()));
	    break;
	  } // switch(t)
	  this->type_unsigned.back()->set_data("type", new Rule::TypeUnsigned(Rule::TypeUnsigned(t)));
	  this->ui->add_for_translation(this->type_unsigned.back()->get_label(),
					::translator("%ttranslation%: ",
						     ::translator(::name(Rule::TypeUnsigned(t)))));
	  this->type_unsigned.back()->signal_value_changed().connect(SigC::bind<int const>(SigC::slot(*this, &Rules::change),
											   t)
								    );
	} // for (t \in Rule::UNSIGNED)
	{ // same size of some widgets
	  static Glib::RefPtr<Gtk::SizeGroup> announcement_scale_size_group
	    = Gtk::SizeGroup::create(Gtk::SIZE_GROUP_BOTH);
	  announcement_scale_size_group->add_widget(dynamic_cast<Gtk::LabelScaleSpinButton*>(this->type_unsigned[Rule::ANNOUNCEMENT_NO_120 - Rule::UNSIGNED_FIRST])->get_scale());
	  announcement_scale_size_group->add_widget(dynamic_cast<Gtk::LabelScaleSpinButton*>(this->type_unsigned[Rule::ANNOUNCEMENT_NO_90  - Rule::UNSIGNED_FIRST])->get_scale());
	  announcement_scale_size_group->add_widget(dynamic_cast<Gtk::LabelScaleSpinButton*>(this->type_unsigned[Rule::ANNOUNCEMENT_NO_60  - Rule::UNSIGNED_FIRST])->get_scale());
	  announcement_scale_size_group->add_widget(dynamic_cast<Gtk::LabelScaleSpinButton*>(this->type_unsigned[Rule::ANNOUNCEMENT_NO_30  - Rule::UNSIGNED_FIRST])->get_scale());
	  announcement_scale_size_group->add_widget(dynamic_cast<Gtk::LabelScaleSpinButton*>(this->type_unsigned[Rule::ANNOUNCEMENT_NO_0   - Rule::UNSIGNED_FIRST])->get_scale());
	  announcement_scale_size_group->add_widget(dynamic_cast<Gtk::LabelScaleSpinButton*>(this->type_unsigned[Rule::ANNOUNCEMENT_LAST   - Rule::UNSIGNED_FIRST])->get_scale());

	} // same size of some widgets
      } // create the buttons

      { // set the pages of the notebook
	Gtk::Alignment* alignment = NULL;
	Gtk::VBox* vbox = NULL;
	Gtk::HBox* hbox = NULL;
	Gtk::VBox* vbox2 = NULL;
	{ // Information
	  alignment = Gtk::manage(new Gtk::Alignment(Gtk::ALIGN_CENTER,
						     Gtk::ALIGN_CENTER,
						     0, 0));
	  alignment->set_border_width(20);
	  Gtk::Label* label = Gtk::manage(new Gtk::Label("information"));
	  this->ui->add_for_translation(*label,
					::translator("information"));
	  this->append_page(*alignment, *label);

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

	  {
	    hbox = Gtk::manage(new Gtk::HBox(false, 20));
	    vbox->add(*hbox);
	    {
	      alignment = Gtk::manage(new Gtk::Alignment(Gtk::ALIGN_CENTER,
							 Gtk::ALIGN_CENTER,
							 0, 0));
	      hbox->add(*alignment);
	      vbox2 = Gtk::manage(new Gtk::VBox(false, 10));
	      alignment->add(*vbox2);

	      vbox2->add(*(this->type_unsigned[Rule::SHOW_TRICKS_NUMBER - Rule::UNSIGNED_FIRST]));
	      vbox2->add(*(this->type_bool[Rule::SHOW_TRICKS_IN_TRICKPILES - Rule::BOOL_FIRST]));
	      vbox2->add(*(this->type_bool[Rule::SHOW_TRICKPILES_POINTS - Rule::BOOL_FIRST]));
	    }
	    {
	      alignment = Gtk::manage(new Gtk::Alignment(Gtk::ALIGN_CENTER,
							 Gtk::ALIGN_CENTER,
							 0, 0));
	      hbox->add(*alignment);
	      vbox2 = Gtk::manage(new Gtk::VBox(false, 10));
	      alignment->add(*vbox2);

	      vbox2->add(*(this->type_bool[Rule::SHOW_IF_VALID - Rule::BOOL_FIRST]));
	      vbox2->add(*(this->type_bool[Rule::SHOW_ALL_HANDS - Rule::BOOL_FIRST]));
	      vbox2->add(*(this->type_bool[Rule::SHOW_KNOWN_TEAMS_IN_GAME - Rule::BOOL_FIRST]));
	      vbox2->add(*(this->type_bool[Rule::SHOW_SOLOPLAYER_IN_GAME - Rule::BOOL_FIRST]));
	    }
	  }
	  {
	    alignment = Gtk::manage(new Gtk::Alignment(Gtk::ALIGN_CENTER,
						       Gtk::ALIGN_CENTER,
						       0, 0));
	    vbox->add(*alignment);
	    vbox2 = Gtk::manage(new Gtk::VBox(false, 10));
	    alignment->add(*vbox2);

	    vbox2->add(*(this->type_bool[Rule::CARD_HINT - Rule::BOOL_FIRST]));
	    vbox2->add(*(this->type_bool[Rule::TAKE_BACK_TRICKS - Rule::BOOL_FIRST]));
	  }
	} // Information
	{ // Poverty
	  alignment = Gtk::manage(new Gtk::Alignment(Gtk::ALIGN_CENTER,
						     Gtk::ALIGN_CENTER,
						     0, 0));
	  alignment->set_border_width(20);
	  Gtk::Label* label = Gtk::manage(new Gtk::Label("poverty"));
	  this->ui->add_for_translation(*label,
					::translator("poverty"));
	  this->append_page(*alignment, *label);

	  hbox = Gtk::manage(new Gtk::HBox(false, 20));
	  alignment->add(*hbox);
	  {
	    alignment = Gtk::manage(new Gtk::Alignment(Gtk::ALIGN_CENTER,
						       Gtk::ALIGN_CENTER,
						       0, 0));
	    hbox->add(*alignment);
	    vbox2 = Gtk::manage(new Gtk::VBox(false, 10));
	    alignment->add(*vbox2);

	    vbox2->add(*(this->type_bool[Rule::POVERTY - Rule::BOOL_FIRST]));
	    vbox2->add(*(this->type_bool[Rule::POVERTY_SHIFT - Rule::BOOL_FIRST]));
	    vbox2->add(*(this->type_bool[Rule::POVERTY_SHIFT_ONLY_TRUMP - Rule::BOOL_FIRST]));
	    vbox2->add(*(this->type_bool[Rule::THROW_WITH_ONE_TRUMP - Rule::BOOL_FIRST]));
	  }
	  {
	    alignment = Gtk::manage(new Gtk::Alignment(Gtk::ALIGN_CENTER,
						       Gtk::ALIGN_CENTER,
						       0, 0));
	    hbox->add(*alignment);
	    vbox2 = Gtk::manage(new Gtk::VBox(false, 10));
	    alignment->add(*vbox2);

	    vbox2->add(*(this->type_bool[Rule::THROW_WITH_FIVE_NINES - Rule::BOOL_FIRST]));
	    vbox2->add(*(this->type_bool[Rule::THROW_WITH_SIX_KINGS - Rule::BOOL_FIRST]));
	    vbox2->add(*(this->type_bool[Rule::THROW_WHEN_FOX_HIGHEST_TRUMP - Rule::BOOL_FIRST]));
	  }

	} // Poverty
	{ // Marriage
	  alignment = Gtk::manage(new Gtk::Alignment(Gtk::ALIGN_CENTER,
						     Gtk::ALIGN_CENTER,
						     0, 0));
	  alignment->set_border_width(20);
	  Gtk::Label* label = Gtk::manage(new Gtk::Label("marriage"));
	  this->ui->add_for_translation(*label,
					::translator("marriage"));
	  this->append_page(*alignment, *label);

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

	  {
	    alignment = Gtk::manage(new Gtk::Alignment(Gtk::ALIGN_CENTER,
						       Gtk::ALIGN_CENTER,
						       0, 0));
	    vbox->add(*alignment);

	    alignment->add(*(this->type_unsigned[Rule::MARRIAGE_DETERMINATION - Rule::UNSIGNED_FIRST]));
	  }
	  {
	    alignment = Gtk::manage(new Gtk::Alignment(Gtk::ALIGN_CENTER,
						       Gtk::ALIGN_CENTER,
						       0, 0));
	    vbox->add(*alignment);
	    vbox2 = Gtk::manage(new Gtk::VBox(false, 10));
	    alignment->add(*vbox2);

	    vbox2->add(*(this->type_bool[Rule::MARRIAGE_FIRST_FOREIGN - Rule::BOOL_FIRST]));
	    vbox2->add(*(this->type_bool[Rule::MARRIAGE_FIRST_COLOR - Rule::BOOL_FIRST]));
	    vbox2->add(*(this->type_bool[Rule::MARRIAGE_FIRST_SINGLE_COLOR - Rule::BOOL_FIRST]));
	    vbox2->add(*(this->type_bool[Rule::MARRIAGE_FIRST_TRUMP - Rule::BOOL_FIRST]));
	  }
	  {
	    alignment = Gtk::manage(new Gtk::Alignment(Gtk::ALIGN_CENTER,
						       Gtk::ALIGN_CENTER,
						       0, 0));
	    vbox->add(*alignment);

	    alignment->add(*(this->type_bool[Rule::GENSCHER - Rule::BOOL_FIRST]));
	  }
	} // Marriage
	{ // Solo
	  alignment = Gtk::manage(new Gtk::Alignment(Gtk::ALIGN_CENTER,
						     Gtk::ALIGN_CENTER,
						     0, 0));
	  alignment->set_border_width(20);
	  Gtk::Label* label = Gtk::manage(new Gtk::Label("solo"));
	  this->ui->add_for_translation(*label,
					::translator("solo"));
	  this->append_page(*alignment, *label);

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

	  {
	    alignment = Gtk::manage(new Gtk::Alignment(Gtk::ALIGN_CENTER,
						       Gtk::ALIGN_CENTER,
						       0, 0));
	    vbox->add(*alignment);

	    alignment->add(*(this->type_bool[Rule::SOLO - Rule::BOOL_FIRST]));
	  }
	  {
	    alignment = Gtk::manage(new Gtk::Alignment(Gtk::ALIGN_CENTER,
						       Gtk::ALIGN_CENTER,
						       0, 0));
	    vbox->add(*alignment);
	    {
	      hbox = Gtk::manage(new Gtk::HBox(false, 20));
	      alignment->add(*hbox);
	      {
		vbox2 = Gtk::manage(new Gtk::VBox(true, 10));
		hbox->add(*vbox2);

		vbox2->add(*(this->type_bool[Rule::SOLO_COLOR - Rule::BOOL_FIRST]));
		vbox2->add(*(this->type_bool[Rule::SOLO_KOEHLER - Rule::BOOL_FIRST]));
		vbox2->add(*(this->type_bool[Rule::SOLO_MEATLESS - Rule::BOOL_FIRST]));
	      }
	      {
		vbox2 = Gtk::manage(new Gtk::VBox(true, 10));
		hbox->add(*vbox2);

		vbox2->add(*(this->type_bool[Rule::SOLO_JACK - Rule::BOOL_FIRST]));
		vbox2->add(*(this->type_bool[Rule::SOLO_QUEEN - Rule::BOOL_FIRST]));
		vbox2->add(*(this->type_bool[Rule::SOLO_KING - Rule::BOOL_FIRST]));
	      }
	      {
		vbox2 = Gtk::manage(new Gtk::VBox(true, 10));
		hbox->add(*vbox2);

		vbox2->add(*(this->type_bool[Rule::SOLO_QUEEN_JACK - Rule::BOOL_FIRST]));
		vbox2->add(*(this->type_bool[Rule::SOLO_KING_JACK - Rule::BOOL_FIRST]));
		vbox2->add(*(this->type_bool[Rule::SOLO_KING_QUEEN - Rule::BOOL_FIRST]));
	      }
	    }
	  }
	} // Solo
	{ // Dollen
	  alignment = Gtk::manage(new Gtk::Alignment(Gtk::ALIGN_CENTER,
						     Gtk::ALIGN_CENTER,
						     0, 0));
	  alignment->set_border_width(20);
	  Gtk::Label* label = Gtk::manage(new Gtk::Label("dollen"));
	  this->ui->add_for_translation(*label,
					::translator("dollen"));
	  this->append_page(*alignment, *label);

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

	  vbox->add(*(this->type_bool[Rule::DOLLEN - Rule::BOOL_FIRST]));
	  vbox->add(*(this->type_bool[Rule::DOLLEN_SECOND_OVER_FIRST - Rule::BOOL_FIRST]));
	  vbox->add(*(this->type_bool[Rule::DOLLEN_CONTRARY_IN_LAST_TRICK - Rule::BOOL_FIRST]));
	} // Dollen
	{ // Swines
	  alignment = Gtk::manage(new Gtk::Alignment(Gtk::ALIGN_CENTER,
						     Gtk::ALIGN_CENTER,
						     0, 0));
	  alignment->set_border_width(20);
	  Gtk::Label* label = Gtk::manage(new Gtk::Label("swines"));
	  this->ui->add_for_translation(*label,
					::translator("swines"));
	  this->append_page(*alignment, *label);

	  Gtk::Table* table = Gtk::manage(new Gtk::Table(4, 2, true));
	  alignment->add(*table);

	  table->set_col_spacings(20);
	  table->set_row_spacings(10);

	  table->attach(*(this->type_bool[Rule::SWINES - Rule::BOOL_FIRST]),
			0, 1, 0, 1);
	  table->attach(*(this->type_bool[Rule::SWINES_IN_SOLO - Rule::BOOL_FIRST]),
			0, 1, 1, 2);
	  table->attach(*(this->type_bool[Rule::SWINES_ANNOUNCEMENT_BEGIN - Rule::BOOL_FIRST]),
			0, 1, 2, 3);
	  table->attach(*(this->type_bool[Rule::SWINE_ONLY_SECOND - Rule::BOOL_FIRST]),
			0, 1, 3, 4);
	  table->attach(*(this->type_bool[Rule::HYPERSWINES - Rule::BOOL_FIRST]),
			1, 2, 0, 1);
	  table->attach(*(this->type_bool[Rule::HYPERSWINES_IN_SOLO - Rule::BOOL_FIRST]),
			1, 2, 1, 2);
	  table->attach(*(this->type_bool[Rule::HYPERSWINES_ANNOUNCEMENT_BEGIN - Rule::BOOL_FIRST]),
			1, 2, 2, 3);

	} // Swines
	{ // Extrapoints
	  alignment = Gtk::manage(new Gtk::Alignment(Gtk::ALIGN_CENTER,
						     Gtk::ALIGN_CENTER,
						     0, 0));
	  alignment->set_border_width(20);
	  Gtk::Label* label = Gtk::manage(new Gtk::Label("extrapoints"));
	  this->ui->add_for_translation(*label,
					::translator("extrapoints"));
	  this->append_page(*alignment, *label);

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

	  {
	    hbox = Gtk::manage(new Gtk::HBox(false, 20));
	    vbox->add(*hbox);
	    {
	      alignment = Gtk::manage(new Gtk::Alignment(Gtk::ALIGN_CENTER,
							 Gtk::ALIGN_CENTER,
							 0, 0));
	      hbox->add(*alignment);
	      vbox2 = Gtk::manage(new Gtk::VBox(false, 10));
	      alignment->add(*vbox2);

	      vbox2->add(*(this->type_bool[Rule::EXTRAPOINT_CATCH_FOX - Rule::BOOL_FIRST]));
	      vbox2->add(*(this->type_bool[Rule::EXTRAPOINT_FOX_LAST_TRICK - Rule::BOOL_FIRST]));
	      vbox2->add(*(this->type_bool[Rule::EXTRAPOINT_DOUBLE_FOX_LAST_TRICK - Rule::BOOL_FIRST]));
	    }
	    {
	      alignment = Gtk::manage(new Gtk::Alignment(Gtk::ALIGN_CENTER,
							 Gtk::ALIGN_CENTER,
							 0, 0));
	      hbox->add(*alignment);
	      vbox2 = Gtk::manage(new Gtk::VBox(false, 10));
	      alignment->add(*vbox2);

	      vbox2->add(*(this->type_bool[Rule::EXTRAPOINT_CHARLIE - Rule::BOOL_FIRST]));
	      vbox2->add(*(this->type_bool[Rule::EXTRAPOINT_CATCH_CHARLIE - Rule::BOOL_FIRST]));
	      vbox2->add(*(this->type_bool[Rule::EXTRAPOINT_DOUBLE_CHARLIE - Rule::BOOL_FIRST]));
	      vbox2->add(*(this->type_bool[Rule::EXTRAPOINT_CATCH_DOUBLE_CHARLIE - Rule::BOOL_FIRST]));
	    }
	  }
	  {
	    alignment = Gtk::manage(new Gtk::Alignment(Gtk::ALIGN_CENTER,
						       Gtk::ALIGN_CENTER,
						       0, 0));
	    vbox->add(*alignment);
	    vbox2 = Gtk::manage(new Gtk::VBox(false, 10));
	    alignment->add(*vbox2);

	    vbox2->add(*(this->type_bool[Rule::EXTRAPOINT_DOLLE_JABS_DOLLE - Rule::BOOL_FIRST]));
	    vbox2->add(*(this->type_bool[Rule::EXTRAPOINT_HEART_TRICK - Rule::BOOL_FIRST]));
	  }
	} // Extrapoints
	{ // Announcements
	  alignment = Gtk::manage(new Gtk::Alignment(Gtk::ALIGN_CENTER,
						     Gtk::ALIGN_CENTER,
						     0, 0));
	  alignment->set_border_width(20);
	  Gtk::Label* label = Gtk::manage(new Gtk::Label("announcements"));
	  this->ui->add_for_translation(*label,
					::translator("announcements"));
	  this->append_page(*alignment, *label);

	  hbox = Gtk::manage(new Gtk::HBox(false, 20));
	  alignment->add(*hbox);

	  {
	    alignment = Gtk::manage(new Gtk::Alignment(Gtk::ALIGN_CENTER,
						       Gtk::ALIGN_CENTER,
						       0, 0));
	    hbox->add(*alignment);

	    vbox2 = Gtk::manage(new Gtk::VBox(false, 10));
	    alignment->add(*vbox2);

	    vbox2->add(*(this->type_bool[Rule::ANNOUNCEMENT_FIRST_TRICK_THIRTY_POINTS - Rule::BOOL_FIRST]));
	    vbox2->add(*(this->type_bool[Rule::ANNOUNCEMENT_REPLY - Rule::BOOL_FIRST]));
	    vbox2->add(*(this->type_bool[Rule::ANNOUNCEMENT_RE_DOUBLES - Rule::BOOL_FIRST]));
	  }
	  {
	    alignment = Gtk::manage(new Gtk::Alignment(Gtk::ALIGN_CENTER,
						       Gtk::ALIGN_CENTER,
						       0, 0));
	    hbox->add(*alignment);

	    vbox2 = Gtk::manage(new Gtk::VBox(false, 10));
	    alignment->add(*vbox2);

	    vbox2->add(*(this->type_unsigned[Rule::ANNOUNCEMENT_NO_120 - Rule::UNSIGNED_FIRST]));
	    vbox2->add(*(this->type_unsigned[Rule::ANNOUNCEMENT_NO_90 - Rule::UNSIGNED_FIRST]));
	    vbox2->add(*(this->type_unsigned[Rule::ANNOUNCEMENT_NO_60 - Rule::UNSIGNED_FIRST]));
	    vbox2->add(*(this->type_unsigned[Rule::ANNOUNCEMENT_NO_30 - Rule::UNSIGNED_FIRST]));
	    vbox2->add(*(this->type_unsigned[Rule::ANNOUNCEMENT_NO_0 - Rule::UNSIGNED_FIRST]));
	    vbox2->add(*(this->type_unsigned[Rule::ANNOUNCEMENT_LAST - Rule::UNSIGNED_FIRST]));
	  }
	} // Announcements
	{ // Tournament
	  alignment = Gtk::manage(new Gtk::Alignment(Gtk::ALIGN_CENTER,
						     Gtk::ALIGN_CENTER,
						     0, 0));
	  alignment->set_border_width(20);
	  Gtk::Label* label = Gtk::manage(new Gtk::Label("tournament"));
	  this->ui->add_for_translation(*label,
					::translator("tournament"));
	  this->append_page(*alignment, *label);

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

	  {
	    hbox = Gtk::manage(new Gtk::HBox(false, 20));
	    vbox->add(*hbox);
	    {
	      alignment = Gtk::manage(new Gtk::Alignment(Gtk::ALIGN_CENTER,
							 Gtk::ALIGN_CENTER,
							 0, 0));
	      hbox->add(*alignment);
	      vbox2 = Gtk::manage(new Gtk::VBox(false, 10));
	      alignment->add(*vbox2);

	      vbox2->add(*(this->type_bool[Rule::WITH_NINES - Rule::BOOL_FIRST]));
	    }
	    {
	      alignment = Gtk::manage(new Gtk::Alignment(Gtk::ALIGN_CENTER,
							 Gtk::ALIGN_CENTER,
							 0, 0));
	      hbox->add(*alignment);
	      vbox2 = Gtk::manage(new Gtk::VBox(false, 10));
	      alignment->add(*vbox2);

	      vbox2->add(*(this->type_unsigned[Rule::NUMBER_OF_PLAYERS - Rule::UNSIGNED_FIRST]));
	      vbox2->add(*(this->type_unsigned[Rule::NUMBER_OF_PLAYERS_IN_GAME - Rule::UNSIGNED_FIRST]));
	    }
	  }
	  {
	    hbox = Gtk::manage(new Gtk::HBox(false, 20));
	    vbox->add(*hbox);
	    {
	      alignment = Gtk::manage(new Gtk::Alignment(Gtk::ALIGN_CENTER,
							 Gtk::ALIGN_CENTER,
							 0, 0));
	      hbox->add(*alignment);
	      vbox2 = Gtk::manage(new Gtk::VBox(false, 10));
	      alignment->add(*vbox2);

	      vbox2->add(*(this->type_bool[Rule::NUMBER_OF_ROUNDS_LIMITED - Rule::BOOL_FIRST]));
	      vbox2->add(*(this->type_unsigned[Rule::NUMBER_OF_ROUNDS - Rule::UNSIGNED_FIRST]));
	      vbox2->add(*(this->type_bool[Rule::POINTS_LIMITED - Rule::BOOL_FIRST]));
	      vbox2->add(*(this->type_unsigned[Rule::POINTS - Rule::UNSIGNED_FIRST]));
	    }
	    {
	      alignment = Gtk::manage(new Gtk::Alignment(Gtk::ALIGN_CENTER,
							 Gtk::ALIGN_CENTER,
							 0, 0));
	      hbox->add(*alignment);
	      vbox2 = Gtk::manage(new Gtk::VBox(false, 10));
	      alignment->add(*vbox2);

	      vbox2->add(*(this->type_unsigned[Rule::NUMBER_OF_DUTY_SOLI - Rule::UNSIGNED_FIRST]));
	      vbox2->add(*(this->type_unsigned[Rule::NUMBER_OF_DUTY_COLOR_SOLI - Rule::UNSIGNED_FIRST]));
	      vbox2->add(*(this->type_unsigned[Rule::NUMBER_OF_DUTY_PICTURE_SOLI - Rule::UNSIGNED_FIRST]));
	      vbox2->add(*(this->type_bool[Rule::LUSTSOLO_PLAYER_LEADS - Rule::BOOL_FIRST]));
	    }
	  }
	} // Tournament
      } // set the pages of the notebook

#ifndef RELEASE
#ifdef DKNOF
      { // test, whether all rules-buttons are packed in a container
	for (int t = Rule::BOOL_FIRST; t <= Rule::BOOL_LAST; t++) {
	  if (!this->type_bool[t - Rule::BOOL_FIRST]->get_parent())
	    cerr << "GTKMM_DOKO::Rules::Rules():\n"
	      << "  rule '" << name(Rule::TypeBool(t)) << "' not packed\n";
	}
	for (int t = Rule::UNSIGNED_FIRST; t <= Rule::UNSIGNED_LAST; t++) {
	  if (!this->type_unsigned[t - Rule::UNSIGNED_FIRST]->get_parent())
	    cerr << "GTKMM_DOKO::Rules::Rules():\n"
	      << "  rule '" << name(Rule::TypeUnsigned(t)) << "' not packed\n";
	}
      } // test, whether all rule-buttons are packed in a container
#endif
#endif

      // signals
      this->load_button->signal_clicked().connect(SigC::slot(*this, &Rules::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, &Rules::save));

      this->update_all();

      this->container->show_all();

      this->language_update();

      DEBUG_RETURNING(VOID,
		      INFO_GTKMM_RULES && INFO_GTKMM_INIT,
		      "Rules::init()");
    } // void Rules::init()

  /**
   **
   ** creates a backup
   **
   ** @param	-
   **
   ** @return	-
   **
   ** @version	0.5.4
   **
   ** @author	Diether Knof
   **
   **/
  void
    Rules::create_backup()
    {
      DEBUG_CALLING(INFO_GTKMM_RULES && INFO_GTKMM_VALUE,
		    "Rules::create_backup()");

      delete this->backup_;
      this->backup_ = new Rule(::party.rule());

      DEBUG_RETURNING(VOID,
		      INFO_GTKMM_RULES && INFO_GTKMM_VALUE,
		      "Rules::create_backup()");
    } // void Rules::create_backup()

  /**
   **
   ** -> result
   **
   ** @param	-
   **
   ** @return	the backup
   **
   ** @version	0.5.4
   **
   ** @author	Diether Knof
   **
   **/
  Rule const&
    Rules::backup() const
    {
      DEBUG_CALLING(INFO_GTKMM_RULES && INFO_GTKMM_VALUE,
		    "Rules::backup()");

      DEBUG_ASSERTION((this->backup_ != NULL),
		      "Rule::backup():\n"
		      "  'this->backup_' == NULL");

      DEBUG_RETURNING(*(this->backup_),
		      INFO_GTKMM_RULES && INFO_GTKMM_VALUE,
		      "Rules::backup()");
    } // Rule const& Rules::backup() const

  /**
   **
   ** resets the settings
   **
   ** @param	-
   **
   ** @return	-
   **
   ** @version	0.5.4
   **
   ** @author	Diether Knof
   **
   **/
  void
    Rules::reset()
    {
      DEBUG_CALLING(INFO_GTKMM_RULES && INFO_GTKMM_UPDATE,
		    "Rules::reset()");

      ::party.rule() = this->backup();
      this->update_all();

      DEBUG_RETURNING(VOID,
		      INFO_GTKMM_RULES && INFO_GTKMM_UPDATE,
		      "Rules::reset()");
    } // void Rules::reset()

  /**
   **
   ** creates a menu with the files in the rules directories
   **
   ** @param	-
   **
   ** @return	-
   **
   ** @version	0.5.4
   **
   ** @author	Diether Knof
   **
   **/
  void
    Rules::load()
    {
      DEBUG_CALLING(INFO_GTKMM_RULES && INFO_GTKMM_UPDATE,
		    "Rules::load()");

      Gtk::FileMenu* load_menu
	= Gtk::manage(new Gtk::FileMenu(SigC::slot(*this, &Rules::load_file)));
      load_menu->add_directory(::setting(Setting::PRIVATE_DATA_DIRECTORY)
			       + "/"
			       + ::setting(Setting::RULES_DIRECTORY));
      load_menu->add_directory(::setting(Setting::PUBLIC_DATA_DIRECTORY)
			       + "/"
			       + ::setting(Setting::RULES_DIRECTORY));

      load_menu->show();

      DEBUG_RETURNING(VOID,
		      INFO_GTKMM_RULES && INFO_GTKMM_UPDATE,
		      "Rules::load()");
    } // void Rules::load()

  /**
   **
   ** loads the rules
   **
   ** @param	filename	the rules file
   **
   ** @return	-
   **
   ** @version	0.5.4
   **
   ** @author	Diether Knof
   **
   **/
  void
    Rules::load_file(string const filename)
    {
      DEBUG_CALLING(INFO_GTKMM_RULES && INFO_GTKMM_UPDATE,
		    "Rules::load_file(filename)");

      if (::game_status == GAMESTATUS::PARTY_INIT) {
	::party.rule().load(filename);
	this->update_all();
      } // if (::game_status == GAMESTATUS::PARTY_INIT)


      DEBUG_RETURNING(VOID,
		      INFO_GTKMM_RULES && INFO_GTKMM_UPDATE,
		      "Rules::load_file(filename)");
    } // void Rules::load_file(string const filename)

  /**
   **
   ** saves the rules.
   ** The filename is taken from 'save_file_selector'.
   **
   ** @param	filename	the rules file
   **
   ** @return	-
   **
   ** @version	0.5.4
   **
   ** @author	Diether Knof
   **
   **/
  void
    Rules::save()
    {
      DEBUG_CALLING(INFO_GTKMM_RULES && INFO_GTKMM_UPDATE,
		    "Rules::save()");

      ::party.rule().save(this->save_file_selector->get_filename()); 

      DEBUG_RETURNING(VOID,
		      INFO_GTKMM_RULES && INFO_GTKMM_UPDATE,
		      "Rules::save()");
    } // void Rules::save()

  /**
   **
   ** update the sensitivity of all widgets
   **
   ** @param	-
   **
   ** @return	-
   **
   ** @version	0.5.4
   **
   ** @author	Diether Knof
   **
   **/
  void
    Rules::sensitivity_update()
    {
      DEBUG_CALLING(INFO_GTKMM_RULES && INFO_GTKMM_UPDATE,
		    "Rules::sensitivity_update()");

      if (::game_status == GAMESTATUS::PARTY_INIT) {
	for (vector<Gtk::CheckButton*>::iterator
	     widget = this->type_bool.begin();
	     widget != this->type_bool.end();
	     widget++)
	  (*widget)->set_sensitive(::party.rule().dependencies(*(static_cast<Rule::TypeBool*>((*widget)->get_data("type")))));
	for (vector<Gtk::LabelSpinButton*>::iterator widget
	     = this->type_unsigned.begin();
	     widget != this->type_unsigned.end();
	     widget++) {
	  Rule::TypeUnsigned const type 
	    = *static_cast<Rule::TypeUnsigned*>((*widget)->get_data("type"));

	  (*widget)->set_sensitive(::party.rule().dependencies(type));
	  (*widget)->set_range(::party.rule().min(type),
			       ::party.rule().max(type));
	} // for (widget \in this->type_unsigned)

	this->load_button->set_sensitive(true);
      } else { // if !(::game_status == GAMESTATUS::PARTY_INIT)
	for (vector<Gtk::CheckButton*>::iterator
	     widget = this->type_bool.begin();
	     widget != this->type_bool.end();
	     widget++)
	  (*widget)->set_sensitive(false);
	for (vector<Gtk::LabelSpinButton*>::iterator widget
	     = this->type_unsigned.begin();
	     widget != this->type_unsigned.end();
	     widget++)
	  (*widget)->set_sensitive(false);

	this->load_button->set_sensitive(false);
      } // if !(::game_status == GAMESTATUS::PARTY_INIT)

#ifdef RELEASE
      this->type_bool[Rule::SHOW_IF_VALID - Rule::BOOL_FIRST]->set_sensitive(false);
      this->type_bool[Rule::CARD_HINT - Rule::BOOL_FIRST]->set_sensitive(false);
      this->type_bool[Rule::TAKE_BACK_TRICKS - Rule::BOOL_FIRST]->set_sensitive(false);
      this->type_bool[Rule::NUMBER_OF_ROUNDS_LIMITED - Rule::BOOL_FIRST]->set_sensitive(false);
      this->type_bool[Rule::POINTS_LIMITED - Rule::BOOL_FIRST]->set_sensitive(false);
      this->type_unsigned[Rule::NUMBER_OF_ROUNDS - Rule::UNSIGNED_FIRST]->set_sensitive(false);
      this->type_unsigned[Rule::NUMBER_OF_DUTY_SOLI - Rule::UNSIGNED_FIRST]->set_sensitive(false);
      this->type_unsigned[Rule::NUMBER_OF_DUTY_COLOR_SOLI - Rule::UNSIGNED_FIRST]->set_sensitive(false);
      this->type_unsigned[Rule::NUMBER_OF_DUTY_PICTURE_SOLI - Rule::UNSIGNED_FIRST]->set_sensitive(false);
      this->type_unsigned[Rule::NUMBER_OF_PLAYERS - Rule::UNSIGNED_FIRST]->set_sensitive(false);
      this->type_unsigned[Rule::NUMBER_OF_PLAYERS_IN_GAME - Rule::UNSIGNED_FIRST]->set_sensitive(false);
#endif // #ifdef RELEASE

      DEBUG_RETURNING(VOID,
		      INFO_GTKMM_RULES && INFO_GTKMM_UPDATE,
		      "Rules::sensitivity_update()");
    } // void Rules::sensitivity_update()

  /**
   **
   ** update the setting 'type'
   **
   ** @param	type			the type of the setting
   ** @param	update_sensitivity	whether the sensitivity shall be updated
   ** 					(default: true)
   **
   ** @return	-
   **
   ** @version	0.5.4
   **
   ** @author	Diether Knof
   **
   **/
  void
    Rules::update(int const type, bool const update_sensitivity)
    {
      DEBUG_CALLING(INFO_GTKMM_RULES && INFO_GTKMM_UPDATE,
		    "Rules::update(type, update_sensitivity)");

      if (!this->is_visible())
	DEBUG_RETURNING(VOID,
			INFO_GTKMM_RULES && INFO_GTKMM_UPDATE,
			"Rules::update(type, update_sensitivity)");

      if (update_sensitivity)
	this->sensitivity_update();

      if ((type >= Rule::BOOL_FIRST)
	  && (type <= Rule::BOOL_LAST))
	this->type_bool[type - Rule::BOOL_FIRST]->set_active(::party.rule().value(Rule::TypeBool(type)));
      else if ((type >= Rule::UNSIGNED_FIRST)
	       && (type <= Rule::UNSIGNED_LAST)) {
	this->type_unsigned[type - Rule::UNSIGNED_FIRST]->set_range(::party.rule().min(Rule::TypeUnsigned(type)),
								    ::party.rule().max(Rule::TypeUnsigned(type)));
	this->type_unsigned[type - Rule::UNSIGNED_FIRST]->set_value(::party.rule().value(Rule::TypeUnsigned(type)));
      } else 
	DEBUG_ASSERTION(false,
			"Rules::update(type, update_sensitivity):\n"
			"  type '" << type << "' unknown.");

      DEBUG_RETURNING(VOID,
		      INFO_GTKMM_RULES && INFO_GTKMM_UPDATE,
		      "Rules::update(type, update_sensitivity)");
    } // void Rules::update(int const type, bool const update_sensitivity = true)

  /**
   **
   ** a rule has been changed by the user
   **
   ** @param	type	the type of the rule
   **
   ** @return	-
   **
   ** @version	0.5.4
   **
   ** @author	Diether Knof
   **
   **/
  void
    Rules::change(int const type)
    {
      DEBUG_CALLING(INFO_GTKMM_RULES && INFO_GTKMM_EVENT,
		    "Rules::change(type)");

      if ((type >= Rule::BOOL_FIRST)
	  && (type <= Rule::BOOL_LAST))
	::party.rule().set(Rule::TypeBool(type),
			   this->type_bool[type - Rule::BOOL_FIRST]->get_active());
      else if ((type >= Rule::UNSIGNED_FIRST)
	       && (type <= Rule::UNSIGNED_LAST)) {
	if (this->type_unsigned[type - Rule::UNSIGNED_FIRST]->is_realized())
	  ::party.rule().set(Rule::TypeUnsigned(type),
			     this->type_unsigned[type - Rule::UNSIGNED_FIRST]->get_value_as_int());
      }
      else 
	DEBUG_ASSERTION(false,
			"Rules::change(type):\n"
			"  type '" << type << "' unknown.");

      DEBUG_RETURNING(VOID,
		      INFO_GTKMM_RULES && INFO_GTKMM_EVENT,
		      "Rules::change(type)");
    } // void Rules::change(int const type)

  /**
   **
   ** updates all widgets
   **
   ** @param	-
   **
   ** @return	-
   **
   ** @version	0.5.4
   **
   ** @author	Diether Knof
   **
   **/
  void
    Rules::update_all()
    {
      DEBUG_CALLING(INFO_GTKMM_RULES && INFO_GTKMM_UPDATE,
		    "Rules::update_all()");

      if (!this->is_visible())
	DEBUG_RETURNING(VOID,
			INFO_GTKMM_RULES && INFO_GTKMM_UPDATE,
			"Rules::update_all()");

      this->sensitivity_update();
      for (int t = Rule::BOOL_FIRST; t <= Rule::BOOL_LAST; t++)
	this->update(t, false);
      for (int t = Rule::UNSIGNED_FIRST; t <= Rule::UNSIGNED_LAST; t++)
	this->update(t, false);

      DEBUG_RETURNING(VOID,
		      INFO_GTKMM_RULES && INFO_GTKMM_UPDATE,
		      "Rules::update_all()");
    } // void Rules::update_all()

} // namespace UI_GTKMM_NS

#endif // #ifdef USE_UI_GTKMM
