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

#include "ui.h"
#include "translations.h"
#include "main_window.h"
#include "party_settings.h"
#include "rules.h"
#include "players.h"
#include "players_db.h"
#include "game_info.h"
#include "preferences.h"
#include "table.h"
#include "party_points.h"
#include "bug_report.h"
#include "bug_report_replay.h"
#include "help.h"
#include "license.h"
#include "cardset_license.h"
#include "changelog.h"
#include "about.h"

#include "../../basistypes.h"
#include "../../party/party.h"
#include "../../game/game.h"
#include "../../misc/setting.h"

#include <gtkmm/alignment.h>
#include <gtkmm/menu.h>
#include <gtkmm/menuitem.h>
#include <gtkmm/stock.h>
#include <gtkmm/tearoffmenuitem.h>
#include <gtkmm/checkmenuitem.h>
#include <gtkmm/notebook.h>
namespace UI_GTKMM_NS {

  /**
   **
   ** Constructor
   **
   ** @param	main_window	the corresponding main window
   **
   ** @return	-
   ** 
   ** @author	Diether Knof
   **
   ** @version	0.5.4
   **
   **/
  Menu::Menu(MainWindow* const main_window) :
    Base(main_window),
  MenuBar(),
  main_window(main_window),
  party_menu(NULL),
  party(NULL),
  new_party(NULL),
  load_party(NULL),
  save_party(NULL),
  end_party(NULL),
  quit(NULL),
  information_menu(NULL),
  information(NULL),
  card_suggestion(NULL),
  last_trick(NULL),
  game_info(NULL),
  bug_report_replay(NULL),
  rules(NULL),
  party_points(NULL),
  players(NULL),
  players_db(NULL),
  announcements(NULL),
  announcements_player(),
  announcements_player_menu(),
  announcements_announcement(),
  swines_separator(),
  swines_announcement(),
  hyperswines_announcement(),
  preferences_menu(NULL),
  preferences(NULL),
  emphasize_valid_cards(NULL),
  show_all_hands(NULL),
  cards_order(NULL),
  preferences_preferences(NULL),
  bug_report(NULL),
  help_menu(NULL),
  help(NULL),
  help_index(NULL),
  license(NULL),
  cardset_license(NULL),
  changelog(NULL),
  about(NULL),
  generate_error(NULL),
  party_points_present_connection()
  {
    this->init();
    this->signal_realize().connect(SigC::slot(*this, &Menu::language_update));

    return ;
  } // Menu::Menu(MainWindow* const main_window)

  /**
   **
   ** Destruktor
   **
   ** @param	-
   **
   ** @return	-
   ** 
   ** @author	Diether Knof
   **
   ** @version	0.5.4
   **
   **/
  Menu::~Menu()
  {
    return ;
  } // Menu::~Menu()

  /**
   **
   ** creates all subelements
   **
   ** @param	-
   **
   ** @return	-
   **
   ** @version	0.5.4
   **
   ** @author	Diether Knof
   **
   **/
  void
    Menu::init()
    {
      //*(Gtk::manage(new Gtk::Image(Gtk::Stock::QUIT, Gtk::ICON_SIZE_MENU)))

      this->party_menu = Gtk::manage(new Gtk::Menu());

      this->party = Gtk::manage(new Gtk::ImageMenuItem("party"));
      this->ui->translations->add(*(dynamic_cast<Gtk::Label*>(this->party->get_child())),
				  ::translator("Menu: party"));

#if 0
      this->new_party = Gtk::manage(new Gtk::ImageMenuItem(*(Gtk::manage(new Gtk::Image(Gtk::Stock::NEW, Gtk::ICON_SIZE_MENU))),
							   "new party"));
#endif
      this->new_party = Gtk::manage(new Gtk::ImageMenuItem("new party"));
      this->ui->translations->add(*(dynamic_cast<Gtk::Label*>(this->new_party->get_child())),
				  ::translator("Menuitem: new party"));

      this->load_party = Gtk::manage(new Gtk::ImageMenuItem(*(Gtk::manage(new Gtk::Image(Gtk::Stock::OPEN, Gtk::ICON_SIZE_MENU))),
							    "load party"));
      this->ui->translations->add(*(dynamic_cast<Gtk::Label*>(this->load_party->get_child())),
				  ::translator("Menuitem: load party"));

      this->save_party = Gtk::manage(new Gtk::ImageMenuItem(*(Gtk::manage(new Gtk::Image(Gtk::Stock::SAVE_AS, Gtk::ICON_SIZE_MENU))),
							    "save party"));
      this->ui->translations->add(*(dynamic_cast<Gtk::Label*>(this->save_party->get_child())),
				  ::translator("Menuitem: save party"));

      this->end_party = Gtk::manage(new Gtk::ImageMenuItem(*(Gtk::manage(new Gtk::Image(Gtk::Stock::SAVE_AS, Gtk::ICON_SIZE_MENU))),
							    "end party"));
      this->ui->translations->add(*(dynamic_cast<Gtk::Label*>(this->end_party->get_child())),
				  ::translator("Menuitem: end party"));

      this->quit = Gtk::manage(new Gtk::ImageMenuItem(*(Gtk::manage(new Gtk::Image(Gtk::Stock::QUIT, Gtk::ICON_SIZE_MENU))),
						      "quit"));
      this->ui->translations->add(*(dynamic_cast<Gtk::Label*>(this->quit->get_child())),
				  ::translator("Menuitem: quit"));



      this->information_menu = Gtk::manage(new Gtk::Menu());

      this->information = Gtk::manage(new Gtk::ImageMenuItem("information"));
      this->ui->translations->add(*(dynamic_cast<Gtk::Label*>(this->information->get_child())),
				  ::translator("Menu: information"));

      this->card_suggestion = Gtk::manage(new Gtk::ImageMenuItem("card suggestion"));
      this->ui->translations->add(*(dynamic_cast<Gtk::Label*>(this->card_suggestion->get_child())),
				  ::translator("Menuitem: card suggestion"));

      this->last_trick = Gtk::manage(new Gtk::ImageMenuItem("last trick"));
      this->ui->translations->add(*(dynamic_cast<Gtk::Label*>(this->last_trick->get_child())),
				  ::translator("Menuitem: last trick"));

      this->game_info = Gtk::manage(new Gtk::ImageMenuItem("game info"));
      this->ui->translations->add(*(dynamic_cast<Gtk::Label*>(this->game_info->get_child())),
				  ::translator("Menuitem: game info"));

      this->bug_report_replay = Gtk::manage(new Gtk::ImageMenuItem("game info"));
      this->ui->translations->add(*(dynamic_cast<Gtk::Label*>(this->bug_report_replay->get_child())),
				  ::translator("Menuitem: bug report replay"));

      this->rules = Gtk::manage(new Gtk::ImageMenuItem(*(Gtk::manage(new Gtk::Image(Gtk::Stock::PROPERTIES, Gtk::ICON_SIZE_MENU))),
						       "rules"));
      this->ui->translations->add(*(dynamic_cast<Gtk::Label*>(this->rules->get_child())),
				  ::translator("Menuitem: rules"));

      this->party_points = Gtk::manage(new Gtk::ImageMenuItem("party points"));
      this->ui->translations->add(*(dynamic_cast<Gtk::Label*>(this->party_points->get_child())),
				  ::translator("Menuitem: party points"));

      this->players = Gtk::manage(new Gtk::ImageMenuItem("players"));
      this->ui->translations->add(*(dynamic_cast<Gtk::Label*>(this->players->get_child())),
				  ::translator("Menuitem: players"));

      this->players_db = Gtk::manage(new Gtk::ImageMenuItem("players database"));
      this->ui->translations->add(*(dynamic_cast<Gtk::Label*>(this->players_db->get_child())),
				  ::translator("Menuitem: players database"));


      this->announcements = Gtk::manage(new Gtk::MenuItem("announcements"));
      this->ui->translations->add(*(dynamic_cast<Gtk::Label*>(this->announcements->get_child())),
				  ::translator("Menu: announcements"));


      this->preferences_menu = Gtk::manage(new Gtk::Menu());

      this->preferences = Gtk::manage(new Gtk::MenuItem("preferences"));
      this->ui->translations->add(*(dynamic_cast<Gtk::Label*>(this->preferences->get_child())),
				  ::translator("Menu: preferences"));

      this->emphasize_valid_cards
	= Gtk::manage(new Gtk::CheckMenuItem(::name(Setting::EMPHASIZE_VALID_CARDS)));
      this->ui->translations->add(*(dynamic_cast<Gtk::Label*>(this->emphasize_valid_cards->get_child())),
				  ::translator(::name(Setting::EMPHASIZE_VALID_CARDS)));

      this->show_all_hands
	= Gtk::manage(new Gtk::CheckMenuItem(::name(Setting::SHOW_ALL_HANDS)));
      this->ui->translations->add(*(dynamic_cast<Gtk::Label*>(this->show_all_hands->get_child())),
				  ::translator(::name(Setting::SHOW_ALL_HANDS)));

      this->cards_order = Gtk::manage(new Gtk::ImageMenuItem(::name(Setting::CARDS_ORDER)));
      this->ui->translations->add(*(dynamic_cast<Gtk::Label*>(this->cards_order->get_child())),
				  ::translator(::name(Setting::CARDS_ORDER)));

      this->preferences_preferences = Gtk::manage(new Gtk::ImageMenuItem(*(Gtk::manage(new Gtk::Image(Gtk::Stock::PREFERENCES, Gtk::ICON_SIZE_MENU))),
									 "preferences"));
      this->ui->translations->add(*(dynamic_cast<Gtk::Label*>(this->preferences_preferences->get_child())),
				  ::translator("Menuitem: preferences"));


      this->bug_report = Gtk::manage(new Gtk::ImageMenuItem("bug report"));
      this->ui->translations->add(*(dynamic_cast<Gtk::Label*>(this->bug_report->get_child())),
				  ::translator("Menuitem: bug report"));


      this->help_menu = Gtk::manage(new Gtk::Menu());

      this->help = Gtk::manage(new Gtk::ImageMenuItem("help"));
      this->ui->translations->add(*(dynamic_cast<Gtk::Label*>(this->help->get_child())),
				  ::translator("Menu: help"));

      this->help_index = Gtk::manage(new Gtk::ImageMenuItem(*(Gtk::manage(new Gtk::Image(Gtk::Stock::HELP, Gtk::ICON_SIZE_MENU))),
							    "help"));
      this->ui->translations->add(*(dynamic_cast<Gtk::Label*>(this->help_index->get_child())),
				  ::translator("Menuitem: help index"));

      this->license = Gtk::manage(new Gtk::ImageMenuItem("license"));
      this->ui->translations->add(*(dynamic_cast<Gtk::Label*>(this->license->get_child())),
				  ::translator("Menuitem: license"));

      this->cardset_license = Gtk::manage(new Gtk::ImageMenuItem("cardset license"));
      this->ui->translations->add(*(dynamic_cast<Gtk::Label*>(this->cardset_license->get_child())),
				  ::translator("Menuitem: cardset license"));

      this->changelog = Gtk::manage(new Gtk::ImageMenuItem("changelog"));
      this->ui->translations->add(*(dynamic_cast<Gtk::Label*>(this->changelog->get_child())),
				  ::translator("Menuitem: changelog"));

      this->about = Gtk::manage(new Gtk::ImageMenuItem("about"));
      this->ui->translations->add(*(dynamic_cast<Gtk::Label*>(this->about->get_child())),
				  ::translator("Menuitem: about"));

      this->generate_error = Gtk::manage(new Gtk::ImageMenuItem(*(Gtk::manage(new Gtk::Image(Gtk::Stock::DIALOG_ERROR, Gtk::ICON_SIZE_MENU))),
								"generate error"));
      this->ui->translations->add(*(dynamic_cast<Gtk::Label*>(this->generate_error->get_child())),
				  ::translator("Menuitem: generate error"));

      this->append(*this->party);
      this->append(*this->information);
      this->append(*this->announcements);
      this->append(*this->preferences);
      // ToDo: make the bug report be right
      // the following does not work (I think because the 'help' menu is 
      // on the right, also
      //this->bug_report->set_right_justified();
      this->append(*this->bug_report);
      this->append(*this->help);
      this->help->set_right_justified();

      // the party menu
      this->party->set_submenu(*this->party_menu);
      this->party_menu->append(*Gtk::manage(new Gtk::TearoffMenuItem()));

      this->party_menu->append(*this->new_party);
      this->party_menu->append(*this->load_party);
      this->party_menu->append(*this->save_party);
      this->party_menu->append(*this->end_party);
      this->party_menu->append(*Gtk::manage(new Gtk::SeparatorMenuItem()));
      this->party_menu->append(*this->quit);
      // the information menu
      this->information->set_submenu(*this->information_menu);
      this->information_menu->append(*Gtk::manage(new Gtk::TearoffMenuItem()));
      this->information_menu->append(*this->card_suggestion);
      this->information_menu->append(*this->last_trick);
#ifndef RELEASE
      this->information_menu->append(*this->game_info);
      this->information_menu->append(*this->bug_report_replay);
#endif
      this->information_menu->append(*Gtk::manage(new Gtk::SeparatorMenuItem()));
      this->information_menu->append(*this->rules);
      this->information_menu->append(*this->party_points);
      this->information_menu->append(*Gtk::manage(new Gtk::SeparatorMenuItem()));
      this->information_menu->append(*this->players);
      this->information_menu->append(*this->players_db);
      // the preferences menu
      this->preferences->set_submenu(*this->preferences_menu);
      this->preferences_menu->append(*Gtk::manage(new Gtk::TearoffMenuItem()));
      this->preferences_menu->append(*this->emphasize_valid_cards);
      this->preferences_menu->append(*this->show_all_hands);
      this->preferences_menu->append(*this->cards_order);
      this->preferences_menu->append(*this->preferences_preferences);
      // the help menu
      this->help->set_submenu(*this->help_menu);
      this->help_menu->append(*Gtk::manage(new Gtk::TearoffMenuItem()));
      this->help_menu->append(*this->help_index);
      this->help_menu->append(*this->license);
      this->help_menu->append(*this->cardset_license);
      this->help_menu->append(*this->changelog);
      this->help_menu->append(*this->about);
#ifndef RELEASE
      this->help_menu->append(*Gtk::manage(new Gtk::SeparatorMenuItem()));
      this->help_menu->append(*this->generate_error);
#endif

#ifndef POSTPHONED
      this->load_party->set_sensitive(false);
      this->save_party->set_sensitive(false);
#endif

      this->card_suggestion->set_sensitive(false);
      this->last_trick->set_sensitive(false);
      this->game_info->set_sensitive(false);
      this->information->set_sensitive(false);

      this->emphasize_valid_cards->set_active(::setting.value(Setting::EMPHASIZE_VALID_CARDS));
      this->show_all_hands->set_active(::setting.value(Setting::SHOW_ALL_HANDS));

      this->show_all();
      this->bug_report_replay->hide();

      return ;
    } // void Menu::init()

  /**
   **
   ** set the signals
   **
   ** @param	-
   **
   ** @return	-
   **
   ** @version	0.6.3
   **
   ** @author	Diether Knof
   **
   **/
  void
    Menu::set_signals()
    {
      // the signals
      this->new_party->signal_activate().connect(SigC::slot(*this->main_window,
							    &MainWindow::start_new_party_event)
						);
      this->end_party->signal_activate().connect(SigC::slot(*this->main_window,
							    &MainWindow::end_party_event)
						);
      this->quit->signal_activate().connect(SigC::slot(*this->main_window,
						       &MainWindow::quit_program_event)
					   );


      this->card_suggestion->signal_activate().connect(SigC::bind<bool const>(SigC::slot(*(this->ui->table), &Table::show_card_suggestion), true));
      this->last_trick->signal_activate().connect(SigC::slot(*this->ui->table,
							     &Table::show_last_trick));

#ifndef RELEASE
      this->game_info->signal_activate().connect(SigC::slot(*this->ui->game_info, &Gtk::Window::present));
      //this->bug_report_replay->signal_activate().connect(SigC::slot(*this->ui->bug_report_replay, &Gtk::Window::present));
#endif

      this->rules->signal_activate().connect(SigC::slot(*this->ui->party_settings->rules, &Gtk::Window::present));
      this->players->signal_activate().connect(SigC::slot(*this->ui->party_settings->players, &Gtk::Window::present));
      this->players_db->signal_activate().connect(SigC::slot(*this->ui->players_db, &Gtk::Window::present));


      this->emphasize_valid_cards->signal_toggled().connect(SigC::slot(*this, &Menu::emphasize_valid_cards_set)
							   );
      this->show_all_hands->signal_toggled().connect(SigC::slot(*this, &Menu::show_all_hands_set)
						    );
      this->cards_order->signal_activate().connect(SigC::slot(*this->ui->preferences, &Preferences::show_cards_order));
      this->preferences_preferences->signal_activate().connect(SigC::slot(*this->ui->preferences, &Gtk::Window::present));


      this->bug_report->signal_activate().connect(SigC::slot(*this->ui->bug_report, &BugReport::create_report));


#if GTKMM_MINOR_VERSION < 4
      this->help_index->signal_activate().connect(SigC::slot(&Help::show_manual));
#else
      this->help_index->signal_activate().connect(sigc::ptr_fun(&Help::show_manual));
#endif
      this->license->signal_activate().connect(SigC::slot(*(this->ui->license),
							  &Gtk::Window::present));
      this->cardset_license->signal_activate().connect(SigC::slot(*(this->ui->cardset_license),
								  &Gtk::Window::present));
      this->changelog->signal_activate().connect(SigC::slot(*(this->ui->changelog),
							    &Gtk::Window::present));
      this->about->signal_activate().connect(SigC::slot(*(this->ui->about),
							&Gtk::Window::present));
      this->generate_error->signal_activate().connect(SigC::slot(*(this->main_window),
								 &MainWindow::generate_error_event));

      // keys

      // I have here some notes, whenever I differ from the HIG ('GNOME Human Interface Guidelines (1.0)', see http://developer.gnome.org/projects/gup/hig/)

      this->new_party->add_accelerator("activate",
				       this->main_window->get_accel_group(),
				       GDK_n,
				       Gdk::CONTROL_MASK,
				       Gtk::ACCEL_VISIBLE);
      // Note:
      // The HIG says 'C-o' for 'open a new document', but 'open' says to open in a new window (see HIG, the file menu). Here I do not want to open another FreeDoko window but to replace the existing party.
      // So I use 'C-l' (load) in contrast to 'C-s' (save).
      this->load_party->add_accelerator("activate",
					this->main_window->get_accel_group(),
					GDK_l,
					Gdk::CONTROL_MASK,
					Gtk::ACCEL_VISIBLE);
      this->save_party->add_accelerator("activate",
					this->main_window->get_accel_group(),
					GDK_s,
					Gdk::CONTROL_MASK,
					Gtk::ACCEL_VISIBLE);
      this->quit->add_accelerator("activate",
				  this->main_window->get_accel_group(),
				  GDK_q,
				  Gdk::CONTROL_MASK,
				  Gtk::ACCEL_VISIBLE);
      this->card_suggestion->add_accelerator("activate",
					     this->main_window->get_accel_group(),
					     GDK_h,
					     Gdk::ModifierType(0),
					     Gtk::ACCEL_VISIBLE);
      this->last_trick->add_accelerator("activate",
					this->main_window->get_accel_group(),
					GDK_l,
					Gdk::ModifierType(0),
					Gtk::ACCEL_VISIBLE);
      this->rules->add_accelerator("activate",
				   this->main_window->get_accel_group(),
				   GDK_r,
				   Gdk::ModifierType(0),
				   Gtk::ACCEL_VISIBLE);
      this->party_points->add_accelerator("activate",
					  this->main_window->get_accel_group(),
					  GDK_p,
					  Gdk::ModifierType(0),
					  Gtk::ACCEL_VISIBLE);
#ifndef WORKAROUND
      // does not work
      this->players->add_accelerator("activate",
				     this->main_window->get_accel_group(),
				     GDK_P,
				     Gdk::ModifierType(0),
				     Gtk::ACCEL_VISIBLE);
#endif
#ifndef RELEASE
      this->game_info->add_accelerator("activate",
				       this->main_window->get_accel_group(),
				       GDK_i,
				       Gdk::ModifierType(0),
				       Gtk::ACCEL_VISIBLE);
#endif
#ifdef OUTDATED
      // HIG: C-a should select all
      this->show_all_hands->add_accelerator("activate",
					    this->main_window->get_accel_group(),
					    GDK_a,
					    Gdk::CONTROL_MASK,
					    Gtk::ACCEL_VISIBLE);
      // HIG: C-o should open a new document / party
      this->cards_order->add_accelerator("activate",
					 this->main_window->get_accel_group(),
					 GDK_o,
					 Gdk::CONTROL_MASK,
					 Gtk::ACCEL_VISIBLE);
#endif
      this->emphasize_valid_cards->add_accelerator("activate",
						   this->main_window->get_accel_group(),
						   GDK_period,
						   Gdk::ModifierType(0),
						   Gtk::ACCEL_VISIBLE);
      // Note:
      // The HIG uses F2 for 'Rename' (p.e. a filename in the file manager).
      // Since I did not find some shortcut for preferences I use F2 because
      // it is beside F1 for help.
      // Later I will use S-F2 for context sensitive preferences
      // as S-F1 for context sensitive help.
      this->preferences_preferences->add_accelerator("activate",
						     this->main_window->get_accel_group(),
						     GDK_F2,
						     Gdk::ModifierType(0),
						     Gtk::ACCEL_VISIBLE);
      this->help_index->add_accelerator("activate",
					this->main_window->get_accel_group(),
					GDK_F1,
					Gdk::ModifierType(0),
					Gtk::ACCEL_VISIBLE);
#ifdef OUTDATED
      // F1 should suffice
      this->help_index->add_accelerator("activate",
					this->main_window->get_accel_group(),
					GDK_m,
					Gdk::CONTROL_MASK,
					Gtk::ACCEL_VISIBLE);
#endif
#ifdef OUTDATED
      // any suggestions?
      // Ctrl-l is used for loading a party.
      // Further I do not think that Ctrl-Shift-something is good usability (which program (but emacs) does use such shortcuts?).
      this->license->add_accelerator("activate",
				     this->main_window->get_accel_group(),
				     GDK_l,
				     Gdk::CONTROL_MASK,
				     Gtk::ACCEL_VISIBLE);
      this->cardset_license->add_accelerator("activate",
					     this->main_window->get_accel_group(),
					     GDK_L,
					     Gdk::CONTROL_MASK,
					     Gtk::ACCEL_VISIBLE);
#endif

      return ;
    } // void Menu::set_signals()

  /**
   **
   ** sets the setting 'emphasize valid cards'
   **
   ** @param	-
   **
   ** @return	-
   **
   ** @version	0.6.7
   **
   ** @author	Diether Knof
   **
   **/
  void
    Menu::emphasize_valid_cards_set()
    {
      ::setting.set(Setting::EMPHASIZE_VALID_CARDS,
		    this->emphasize_valid_cards->get_active());

      return ;
    } // void Menu::emphasize_valid_cards_set()

  /**
   **
   ** sets the setting 'show all hands'
   **
   ** @param	-
   **
   ** @return	-
   **
   ** @version	0.5.4
   **
   ** @author	Diether Knof
   **
   **/
  void
    Menu::show_all_hands_set()
    {
      ::setting.set(Setting::SHOW_ALL_HANDS,
		    this->show_all_hands->get_active());

      return ;
    } // void Menu::show_all_hands_set()

  /**
   **
   ** event: make the announcement 'announcement' for player 'playerno'
   **
   ** @param	playerno	the number of the player who announces
   ** @param	announcement	the announcement to make
   **
   ** @return	-
   **
   ** @version	0.6.1
   **
   ** @author	Diether Knof
   **
   **/
  void
    Menu::announcement_event(unsigned const playerno, int const announcement)
    {
      // note, that here it is not the playernumber in the game but in the party
      ::party.game().announcement_make(Announcement(announcement),
				       ::party.player(playerno));

      return ;
    } // void Menu::announcement_event(unsigned const playerno, int const announcement)

  /**
   **
   ** event: announce 'swines' for player 'playerno'
   **
   ** @param	playerno	the number of the player who announces swines
   **				if it is 'UINT_MAX' the player is determined
   **				automatically
   **
   ** @return	-
   **
   ** @version	0.6.6
   **
   ** @author	Diether Knof
   **
   **/
  void
    Menu::swines_announcement_event(unsigned const playerno)
    {
      // note, that here it is not the playernumber in the game but in the party
      if (playerno == UINT_MAX) {
	for (vector<Player*>::const_iterator p = ::party.game().player_begin();
	     p != ::party.game().player_end();
	     p++) {
	  if (::party.game().swines_announcement_valid(**p)) {
	    ::party.game().swines_announce(**p);
	    break;
	  } 
	} // for (p \in ::party.game().players)
      } else { // if !(playerno == UINT_MAX)
	::party.game().swines_announce(::party.player(playerno));
      } // if !(playerno == UINT_MAX)

      return ;
    } // void Menu::swines_announcement_event(unsigned const playerno)

  /**
   **
   ** event: announce 'hyperswines' for player 'playerno'
   **
   ** @param	playerno	the number of the player with hyperswines
   **				if it is 'UINT_MAX' the player is determined
   **				automatically
   **
   ** @return	-
   **
   ** @version	0.6.6
   **
   ** @author	Diether Knof
   **
   **/
  void
    Menu::hyperswines_announcement_event(unsigned const playerno)
    {
      // note, that here it is not the playernumber in the game but in the party
      if (playerno == UINT_MAX) {
	for (vector<Player*>::const_iterator p = ::party.game().player_begin();
	     p != ::party.game().player_end();
	     p++) {
	  if (::party.game().hyperswines_announcement_valid(**p)) {
	    ::party.game().hyperswines_announce(**p);
	    break;
	  } 
	} // for (p \in ::party.game().players)
      } else { // if !(playerno == UINT_MAX)
	::party.game().hyperswines_announce(::party.player(playerno));
      } // if !(playerno == UINT_MAX)

      return ;
    } // void Menu::hyperswines_announcement_event(unsigned const playerno)

  /**
   **
   ** the party is opened
   ** some sensitivity is set
   **
   ** @param	-
   **
   ** @return	-
   **
   ** @version	0.6.1
   **
   ** @author	Diether Knof
   **
   **/
  void
    Menu::party_open()
    {
      this->end_party->set_sensitive(false);
      this->information->set_sensitive(false);
      this->card_suggestion->set_sensitive(false);
      this->last_trick->set_sensitive(false);
      this->game_info->set_sensitive(false);
      this->party_points->set_sensitive(false);

      this->announcements->set_sensitive(false);
      this->announcements->remove_submenu();

      return ;
    } // void Menu::party_open()

  /**
   **
   ** the party has started
   ** create the announcements menu
   ** make some information accessable
   **
   ** @param	-
   **
   ** @return	-
   **
   ** @version	0.6.1
   **
   ** @author	Diether Knof
   **
   **/
  void
    Menu::party_start()
    {
      this->end_party->set_sensitive(true);

      this->party_points_present_connection
	= this->party_points->signal_activate().connect(SigC::slot(*(this->ui->table->party_points_),
								   &Gtk::Window::present));

      this->party_points->set_sensitive(true);
      this->information->set_sensitive(true);

      { // create the announcements menu
	this->announcements_player.clear();
	this->announcements_player_menu.clear();
	this->announcements_announcement.clear();
	this->swines_separator.clear();
	this->swines_announcement.clear();
	this->hyperswines_announcement.clear();

	Gtk::Menu* menu = NULL;
	if (::party.humanno() != 1) {
	  menu  = Gtk::manage(new Gtk::Menu());
	  menu->append(*(Gtk::manage(new Gtk::TearoffMenuItem())));
	} // if (::party.humanno() != 1)
	for (unsigned p = 0; p < ::party.playerno(); p++) {
	  this->announcements_player.push_back(Gtk::manage(new Gtk::MenuItem(Glib::locale_to_utf8(::party.player(p).name()))));

	  this->announcements_player_menu.push_back(Gtk::manage(new Gtk::Menu()));
	  this->announcements_player_menu.back()->append(*(Gtk::manage(new Gtk::TearoffMenuItem())));
	  this->announcements_announcement.push_back(vector<Gtk::MenuItem*>()); 

	  this->announcements_announcement.back().push_back(Gtk::manage(new Gtk::MenuItem(Glib::locale_to_utf8(::translator(ANNOUNCEMENT::REPLY).translation()))));
	  if (::party.rule()(Rule::ANNOUNCEMENT_REPLY))
	    this->announcements_player_menu.back()->append(*(this->announcements_announcement.back().back()));

	  this->announcements_announcement.back().back()->signal_activate().connect(SigC::bind<unsigned const, int const>(SigC::slot(*this, &Menu::announcement_event), p, ANNOUNCEMENT::REPLY));
	  for (int a = ANNOUNCEMENT::NO120;
	       a <= ANNOUNCEMENT::NO0;
	       ++a) {
	    this->announcements_announcement.back().push_back(Gtk::manage(new Gtk::MenuItem(Glib::locale_to_utf8(::translator(Announcement(a)).translation()))));
	    this->announcements_player_menu.back()->append(*(this->announcements_announcement.back().back()));

	    this->announcements_announcement.back().back()->signal_activate().connect(SigC::bind<unsigned const, int const>(SigC::slot(*this, &Menu::announcement_event), p, a));

	  } // for (a \in Announcement)

	  { // swines separator
	    this->swines_separator.push_back(Gtk::manage(new Gtk::SeparatorMenuItem()));
	    this->announcements_player_menu.back()->append(*this->swines_separator.back());
	  } // swines separator
	  { // swines
	    this->swines_announcement.push_back(Gtk::manage(new Gtk::MenuItem("swines")));
	    this->ui->translations->add(*(dynamic_cast<Gtk::Label*>(this->swines_announcement.back()->get_child())),
					::translator("Menu: swines announcement"));
	    this->announcements_player_menu.back()->append(*(this->swines_announcement.back()));

	    this->swines_announcement.back()->signal_activate().connect(SigC::bind<unsigned const>(SigC::slot(*this, &Menu::swines_announcement_event), p));
	  } // swines
	  { // hyperswines
	    this->hyperswines_announcement.push_back(Gtk::manage(new Gtk::MenuItem("hyperswines")));
	    this->ui->translations->add(*(dynamic_cast<Gtk::Label*>(this->hyperswines_announcement.back()->get_child())),
					::translator("Menu: hyperswines announcement"));
	    this->announcements_player_menu.back()->append(*(this->hyperswines_announcement.back()));

	    this->hyperswines_announcement.back()->signal_activate().connect(SigC::bind<unsigned const>(SigC::slot(*this, &Menu::hyperswines_announcement_event), p));
	  } // hyperswines

	  this->announcements_player_menu.back()->show_all_children();
	  if ((::party.humanno() == 1)
	      && (::party.player(p).type() == Player::HUMAN))
	    menu = this->announcements_player_menu.back();
	  else
	    this->announcements_player.back()->set_submenu(*(this->announcements_player_menu.back()));

	  if ((::party.humanno() != 1)
	      && (::party.player(p).type() == Player::HUMAN))
	    menu->append(*(this->announcements_player.back()));
	} // for (p < ::party.playerno())
	this->announcements->set_submenu(*menu);
	menu->show_all_children();
      } // create the announcements menu

      return ;
    } // void Menu::party_start()

  /**
   **
   ** the party is finished
   **
   ** @param	-
   **
   ** @return	-
   **
   ** @version	0.6.8
   **
   ** @author	Diether Knof
   **
   **/
  void
    Menu::party_finish()
    {
      this->end_party->set_sensitive(false);

      return ;
    } // void Menu::party_finish()

  /**
   **
   ** the party has closed
   **
   ** @param	-
   **
   ** @return	-
   **
   ** @version	0.6.1
   **
   ** @author	Diether Knof
   **
   ** @todo	better signal disconnection
   **
   **/
  void
    Menu::party_close()
    {
      // ToDo: disconnection without extra variables
      this->party_points_present_connection.disconnect();

      this->party_points->set_sensitive(false);
      this->information->set_sensitive(false);
      this->last_trick->set_sensitive(false);
      this->game_info->set_sensitive(false);

      return ;
    } // void Menu::party_close()

  /**
   **
   ** the game has started
   ** make the announcements menu accessable
   **
   ** @param	-
   **
   ** @return	-
   **
   ** @version	0.6.1
   **
   ** @author	Diether Knof
   **
   **/
  void
    Menu::game_start()
    {
      this->announcements->set_sensitive(::party.game().humanno() > 0);
      this->game_info->set_sensitive(true);

      // to have 're'/'contra' instead of 'no 120'
      this->language_update();

      return ;
    } // void Menu::game_start()

  /**
   **
   ** a new trick is opened
   **
   ** @param	-
   **
   ** @return	-
   **
   ** @version	0.6.1
   **
   ** @author	Diether Knof
   **
   **/
  void
    Menu::trick_open()
    {
      this->last_trick->set_sensitive(this->ui->game().real_trick_current_no() >= 1);
      this->announcements_update();

      return ;
    } // void Menu::trick_open()

  /**
   **
   ** the (human) player has to play a card
   **
   ** @param	-
   **
   ** @return	-
   **
   ** @version	0.6.1
   **
   ** @author	Diether Knof
   **
   **/
  void
    Menu::card_get()
    {
      this->card_suggestion->set_sensitive(::party.rule()(Rule::CARD_HINT));

      return ;
    } // void Menu::card_get()

  /**
   **
   ** the (human) player has played a card
   **
   ** @param	-
   **
   ** @return	-
   **
   ** @version	0.6.1
   **
   ** @author	Diether Knof
   **
   **/
  void
    Menu::card_got()
    {
      this->card_suggestion->set_sensitive(false);

      return ;
    } // void Menu::card_got()

  /**
   **
   ** the game is finished
   **
   ** @param	-
   **
   ** @return	-
   **
   ** @version	0.6.1
   **
   ** @author	Diether Knof
   **
   **/
  void
    Menu::game_finish()
    {
      this->last_trick->set_sensitive(false);
      this->game_info->set_sensitive(false);

      return ;
    } // void Menu::game_finish()

  /**
   **
   ** updates the announcements, that is the sensitivity of them
   **
   ** @param	-
   **
   ** @return	-
   **
   ** @version	0.6.1
   **
   ** @author	Diether Knof
   **
   ** @todo	change the name of the 'reply' item
   **
   **/
  void
    Menu::announcements_update()
    {
      bool one_valid = false;
      for (unsigned  p = 0; p < ::party.playerno(); p++) {
	Player const& player = ::party.player(p);
	bool valid = false;

	valid |= (::party.game().announcement_valid(ANNOUNCEMENT::REPLY,
						    player));
	if ( ::party.game().announcement_valid(ANNOUNCEMENT::REPLY,
					       player) ) {
	  dynamic_cast<Gtk::Label*>(this->announcements_announcement[p][0]->get_child())->set_text(Glib::locale_to_utf8(::translator(ANNOUNCEMENT::to_reply(player.game().announcement_of_team(opposite(player.team())).announcement)).translation()));
	  this->announcements_announcement[p][0]->set_sensitive(true);
	} else { // if !(REPLY valid)
	  dynamic_cast<Gtk::Label*>(this->announcements_announcement[p][0]->get_child())->set_text(Glib::locale_to_utf8(::translator(ANNOUNCEMENT::REPLY).translation()));
	  this->announcements_announcement[p][0]->set_sensitive(false);
	} // if !(REPLY valid)

	for (int a = ANNOUNCEMENT::NO120;
	     a <= ANNOUNCEMENT::NO0;
	     ++a) {
	  bool const v
	    = (::party.game().announcement_valid(Announcement(a),
						 ::party.player(p)));
	  this->announcements_announcement[p][a - ANNOUNCEMENT::NO120 + 1]->set_sensitive(v);
	  valid |= v;
	} // for (a \in Announcement)
	{ // swines
	  valid |= (player.game().swines_announcement_valid(player)
		    || player.game().hyperswines_announcement_valid(player));
	  if (player.game().rule()(Rule::SWINES)) {
	    this->swines_separator[p]->show();
	    this->swines_announcement[p]->show();
	  } else {
	    this->swines_separator[p]->hide();
	    this->swines_announcement[p]->hide();
	  }
	  if (player.game().rule()(Rule::HYPERSWINES))
	    this->hyperswines_announcement[p]->show();
	  else
	    this->hyperswines_announcement[p]->hide();

	  this->swines_announcement[p]->set_sensitive(player.game().swines_announcement_valid(player));
	  this->hyperswines_announcement[p]->set_sensitive(player.game().hyperswines_announcement_valid(player));
	} // swines

	this->announcements_player[p]->set_sensitive(valid);
	valid &= ((::party.player(p).type() == Player::HUMAN));
	one_valid |= valid;
      } // for (p < ::party.playerno())
      this->announcements->set_sensitive(one_valid);

      return ;
    } // void Menu::announcements_update()

  /**
   **
   ** updates all language elements
   **
   ** @param	-
   **
   ** @return	-
   **
   ** @version	0.6.2
   **
   ** @author	Diether Knof
   **
   ** @todo	'last trick' -> 'tricks' (when game is finished)
   ** @todo	change the name of the 'reply' item
   **
   **/
  void
    Menu::language_update()
    {
      // update the announcements
      if (::game_status >= GAMESTATUS::GAME_INIT)
	for (unsigned p = 0; p < ::party.game().playerno(); ++p) {
	  dynamic_cast<Gtk::Label*>(this->announcements_announcement[p][0]->get_child()
				   )->set_text(Glib::locale_to_utf8(::translator(ANNOUNCEMENT::REPLY).translation()));
	  for (int a = ANNOUNCEMENT::NO120; a <= ANNOUNCEMENT::NO0; ++a)
	    // if the team is 're' or 'contra'
	    // take 're'/'contra' instead of 'no 120'
	    if ( (a == ANNOUNCEMENT::NO120)
		 && ((::party.game().player(p).team() == TEAM::RE)
		     || (::party.game().player(p).team() == TEAM::CONTRA)) )
	      dynamic_cast<Gtk::Label*>(this->announcements_announcement[p][a - ANNOUNCEMENT::NO120 + 1]->get_child()
				       )->set_text(Glib::locale_to_utf8(::translator(::party.game().player(p).team()).translation()));
	    else
	      dynamic_cast<Gtk::Label*>(this->announcements_announcement[p][a - ANNOUNCEMENT::NO120 + 1]->get_child()
				       )->set_text(Glib::locale_to_utf8(::translator(Announcement(a)).translation()));
	} // for (p < ::party.game().playerno())

      return ;
    } // void Menu::language_update()

} // namespace UI_GTKMM_NS

#endif // #ifdef USE_UI_GTKMM
