/**********************************************************************
 *
 *   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_GTK

#include "gtk_gui.h"
#include "splash.h"
#include "card.h"
#include "icon.h"
#include "main_window.h"
#include "settings.h"
#include "bug_report.h"
#include "playfield.h"
#include "table.h"
#include "party_settings.h"
#include "reservation.h"
#include "gametype.h"
#include "party_points.h"
#include "help.h"
#include "license.h"
#include "license.cardset.h"
#include "about.h"

#include "../../utils/file.h"
#include "../../party/party.h"
#include "../../card/hand.h"
#include "../../misc/language.h"

#define SPLASH_UPDATE_STEP_GUI (1.0 / 14)

namespace GTK_DOKO
{
#include <gdk/gdkkeysyms.h>

  GTK_GUI* gui = NULL;


  /**
   **
   ** updates the gui
   **
   ** @param	sleep_usec	thousands of seconds to sleep (<0 for infinity)
   **
   ** @return	-
   ** 
   ** @version	0.4.5
   **
   ** @author	dknof
   **
   **/
  void
    GTK_GUI::update()
    {
      DEBUG_CALLING(INFO_GTK_EVENT && false,
		    "GTK_GUI::update()");

      while (gtk_events_pending())
	gtk_main_iteration();

      DEBUG_RETURNING(VOID,
		      INFO_GTK_EVENT && false,
		      "GTK_GUI::update()");
    } // void GTK_GUI::update()

  /**
   **
   ** sleeps the given time
   ** (in miliseconds, UINT_MAX for infinity)
   **
   ** @param	sleep_usec	time to sleep
   **
   ** @return	-
   ** 
   ** @version	0.4.5
   **
   ** @author	dknof
   **
   **/
  void
    GTK_GUI::sleep(unsigned const sleep_usec)
    {
      DEBUG_CALLING(INFO_GTK_EVENT && false,
		    "GTK_GUI::sleep()");

      GTK_GUI::update();

      gint const timeout_id = ((sleep_usec == UINT_MAX)
			       ? 0
			       : gtk_timeout_add(sleep_usec, main_quit, NULL));

      gtk_main();

      if (timeout_id != 0)
	gtk_timeout_remove(timeout_id);

      GTK_GUI::update();

      DEBUG_RETURNING(VOID,
		      INFO_GTK_EVENT && false,
		      "GTK_GUI::sleep()");
    } // void GTK_GUI::sleep(unsigned const sleep_usec)

  /*****************************************************************************
   *
   * static void GTK_GUI::main_quit()
   *
   * Parameters:	none
   *
   * Result:	none
   * 
   * Version:	0.3.7
   *
   * Description:	quits the 'gtk_main' function
   *
   ****************************************************************************/
  void
    GTK_GUI::main_quit()
    {
      DEBUG_CALLING(INFO_GTK_EVENT,
		    "GTK_GUI::main_quit()");


      if (gtk_main_level() > 0)
	gtk_main_quit();

      DEBUG_RETURNING(VOID,
		      INFO_GTK_EVENT,
		      "GTK_GUI::main_quit()");
    } // static void GTK_GUI::main_quit()

  /*****************************************************************************
   *
   * static gint GTK_GUI::main_quit(gpointer)
   *
   * Parameters:	none
   *
   * Result:	none
   * 
   * Version:	0.3.7
   *
   * Description:	calls main_quit()
   *
   ****************************************************************************/
  gint
    GTK_GUI::main_quit(gpointer)
    {
      DEBUG_CALLING(INFO_GTK_EVENT && false,
		    "GTK_GUI::main_quit()");

      GTK_GUI::main_quit();

      DEBUG_RETURNING(gtk_false(),
		      INFO_GTK_EVENT && false,
		      "GTK_GUI::main_quit()");
    } // static gint GTK_GUI::main_quit(gpointer)

  /*****************************************************************************
   *
   * GTK_GUI::GTK_GUI(int& argc, char**& argv)
   *
   * Parameters:	argc - number of arguments
   * 		argv - arguments
   *
   * Result:	none
   * 
   * Version:	0.3.6
   *
   * Description:	Constructor: create the objects
   *
   ****************************************************************************/
  GTK_GUI::GTK_GUI(int& argc, char**& argv) :
    color_depth(0),
  ref_window(NULL),
  gc(NULL),
  selected_card_p(UINT_MAX),
  logo_p(),
  cards_p(NULL),
  icons_p(NULL),
  splash_p(NULL),
  settings_p(NULL),
  bug_report_p(NULL),
  help_p(NULL),
  license_p(NULL),
  license_cardset_p(NULL),
  about_p(NULL),
  main_window_p(NULL),
  playfield_p(NULL)
  {
    DEBUG_CALLING(INFO_GTK_GUI && INFO_GTK_INIT,
		  "GTK_GUI::GTK_GUI()");

    // the only valid option is the programname
    int argc_gtk = 1;
    char** argv_gtk = new char*[2];
    argv_gtk[0] = argv[0];
    argv_gtk[1] = NULL;

    // add the current directory for files to be parsed
    gtk_rc_add_default_file(DK::Utils::File::filename_expand("~/.gtkrc"
							    ).c_str());
    gtk_rc_add_default_file((::setting(Setting::PRIVATE_DATA_DIRECTORY)
			     + "/gtkrc").c_str());
    gtk_rc_add_default_file("./gtkrc.FreeDoko");

    // init the gtk-environment
    gtk_init(&argc_gtk, &argv_gtk);

    this->color_depth = gdk_visual_get_best_depth();
    GdkWindowAttr attributes = {
      "ref window", // title
      0, // event_mask
      0, 0, // x and y position
      1, 1, // width and height
      GDK_INPUT_OUTPUT, // window class
      NULL, // visual
      NULL, // colormap
      GDK_WINDOW_TOPLEVEL, // window type
      NULL, // cursor
      NULL, // wmclass_name
      NULL, // wmclass_class
      FALSE // override_redirect
    };   
    this->ref_window = gdk_window_new(NULL, &attributes, 0);
    this->gc = gdk_gc_new(this->ref_window);

    DEBUG_RETURNING(VOID,
		    INFO_GTK_GUI && INFO_GTK_INIT,
		    "GTK_GUI::GTK_GUI()");
  } // GTK_GUI::GTK_GUI(int& argc, char**& argv)

  /*****************************************************************************
   *
   * void GTK_GUI::init()
   *
   * Parameters:	none
   *
   * Result:	none
   * 
   * Version:	0.3.6
   *
   * Description:	inits the gui
   *
   ****************************************************************************/
  void
    GTK_GUI::init()
    {
      DEBUG_CALLING(INFO_GTK_GUI && INFO_GTK_INIT,
		    "GTK_GUI::init()");


      // create the subelements

      { // transform the logo
#include "../../logo.xpm"

	GdkPixmap* pixmap = NULL;
	GdkBitmap* mask = NULL;
	pixmap = gdk_pixmap_create_from_xpm_d(this->ref_window,
					      &mask, NULL,
					      logo_xpm);
	logo_p = Pixmap(pixmap, mask);
	gdk_pixmap_unref(pixmap);
	gdk_bitmap_unref(mask);
      }


      // create the splash-screen
      splash_p = new Splash(this);

      splash().init();


      // loads the cards
      cards_p = new Cards(this);
      cards().init();

      // load the icons
      icons_p = new Icons(this);
      icons().init();

      splash().set_text(language("Initiating the GUI"));

      splash().progress_add(SPLASH_UPDATE_STEP_GUI);
      settings_p = new Settings(this);
      splash().progress_add(SPLASH_UPDATE_STEP_GUI);
      bug_report_p = new BugReport(this);
      splash().progress_add(SPLASH_UPDATE_STEP_GUI);
      help_p = new Help(this);
      splash().progress_add(SPLASH_UPDATE_STEP_GUI);
      license_p = new License(this);
      splash().progress_add(SPLASH_UPDATE_STEP_GUI);
      license_cardset_p = new LicenseCardset(this);
      splash().progress_add(SPLASH_UPDATE_STEP_GUI);
      about_p = new About(this);

      splash().progress_add(SPLASH_UPDATE_STEP_GUI);
      main_window_p = new MainWindow(this);

      splash().progress_add(SPLASH_UPDATE_STEP_GUI);
      playfield_p = new Playfield(this);

      splash().progress_add(SPLASH_UPDATE_STEP_GUI);

      // init the objects
      settings().init();
      splash().progress_add(SPLASH_UPDATE_STEP_GUI);
      bug_report().init();
      splash().progress_add(SPLASH_UPDATE_STEP_GUI);
      help().init();
      splash().progress_add(SPLASH_UPDATE_STEP_GUI);
      about().init();
      splash().progress_add(SPLASH_UPDATE_STEP_GUI);
      license().init();

      splash().progress_add(SPLASH_UPDATE_STEP_GUI);
      main_window().init();

      // last entry in the splash-window
      splash().set_text(language("finished"));

      // show the window
      gtk_widget_show(main_window().window());
      update();

      // remove the splash window
      splash().deinit();

      DEBUG_RETURNING(VOID,
		      INFO_GTK_GUI && INFO_GTK_INIT,
		      "GTK_GUI::init()");
    } // void GTK_GUI::init()

  /*****************************************************************************
   *
   * Pixmap& GTK_GUI::logo() const
   *
   * Parameters:	none
   *
   * Result:	The logo
   * 
   * Version:	0.3.6
   *
   * Description:	Result
   *
   ****************************************************************************/
  Pixmap&
    GTK_GUI::logo()
    {
      DEBUG_CALLING(INFO_GTK_GUI && INFO_GTK_VALUE,
		    "GTK_GUI::logo()");

      DEBUG_ASSERTION(logo_p,
		      "GTK_GUI::logo()\n"
		      "  'logo_p' == Pixmap()");

      DEBUG_RETURNING(logo_p,
		      INFO_GTK_GUI && INFO_GTK_VALUE,
		      "GTK_GUI::logo()");
    } // Pixmap& GTK_GUI::logo()

  /*****************************************************************************
   *
   * Cards& GTK_GUI::cards()
   *
   * Parameters:	none
   *
   * Result:	The cards
   * 
   * Version:	0.3.6
   *
   * Description:	Result
   *
   ****************************************************************************/
  Cards&
    GTK_GUI::cards()
    {
      DEBUG_CALLING(INFO_GTK_GUI && INFO_GTK_VALUE,
		    "GTK_GUI::cards()");

      DEBUG_ASSERTION((cards_p != NULL),
		      "GTK_GUI::cards()\n"
		      "  'cards_p' == NULL");

      DEBUG_RETURNING(*cards_p,
		      INFO_GTK_GUI && INFO_GTK_VALUE,
		      "GTK_GUI::cards()");
    } // Cards& GTK_GUI::cards()

  /*****************************************************************************
   *
   * Icons& GTK_GUI::icons()
   *
   * Parameters:	none
   *
   * Result:	The icons
   * 
   * Version:	0.3.6
   *
   * Description:	Result
   *
   ****************************************************************************/
  Icons&
    GTK_GUI::icons()
    {
      DEBUG_CALLING(INFO_GTK_GUI && INFO_GTK_VALUE,
		    "GTK_GUI::icons()");

      DEBUG_ASSERTION((icons_p != NULL),
		      "GTK_GUI::icons()\n"
		      "  'icons_p' == NULL");

      DEBUG_RETURNING(*icons_p,
		      INFO_GTK_GUI && INFO_GTK_VALUE,
		      "GTK_GUI::icons()");
    } // Icons& GTK_GUI::icons()

  /*****************************************************************************
   *
   * Splash& GTK_GUI::splash()
   *
   * Parameters:	none
   *
   * Result:	The main window
   * 
   * Version:	0.3.6
   *
   * Description:	Result
   *
   ****************************************************************************/
  Splash&
    GTK_GUI::splash()
    {
      DEBUG_CALLING(INFO_GTK_GUI && INFO_GTK_VALUE,
		    "GTK_GUI::splash()");

      DEBUG_ASSERTION((splash_p != NULL),
		      "GTK_GUI::splash()\n"
		      "  'splash_p' == NULL");

      DEBUG_RETURNING(*splash_p,
		      INFO_GTK_GUI && INFO_GTK_VALUE,
		      "GTK_GUI::splash()");
    } // Splash& GTK_GUI::splash()

  /*****************************************************************************
   *
   * Settings& GTK_GUI::settings()
   *
   * Parameters:	none
   *
   * Result:	The settings
   * 
   * Version:	0.3.6
   *
   * Description:	Result
   *
   ****************************************************************************/
  Settings&
    GTK_GUI::settings()
    {
      DEBUG_CALLING(INFO_GTK_GUI && INFO_GTK_VALUE,
		    "GTK_GUI::settings()");

      DEBUG_ASSERTION((settings_p != NULL),
		      "GTK_GUI::settings()\n"
		      "  'settings_p' == NULL");

      DEBUG_RETURNING(*settings_p,
		      INFO_GTK_GUI && INFO_GTK_VALUE,
		      "GTK_GUI::settings()");
    } // Settings& GTK_GUI::settings()

  /*****************************************************************************
   *
   * BugReport& GTK_GUI::bug_report()
   *
   * Parameters:	none
   *
   * Result:	The main window
   * 
   * Version:	0.3.6
   *
   * Description:	Result
   *
   ****************************************************************************/
  BugReport&
    GTK_GUI::bug_report()
    {
      DEBUG_CALLING(INFO_GTK_GUI && INFO_GTK_VALUE,
		    "GTK_GUI::bug_report()");

      DEBUG_ASSERTION((bug_report_p != NULL),
		      "GTK_GUI::bug_report()\n"
		      "  'bug_report_p' == NULL");

      DEBUG_RETURNING(*bug_report_p,
		      INFO_GTK_GUI && INFO_GTK_VALUE,
		      "GTK_GUI::bug_report()");
    } // BugReport& GTK_GUI::bug_report()

  /**
   **
   ** -> result
   **
   ** @param	-
   **
   ** @return	The help class
   ** 
   ** @version	0.4.4
   **
   ** @author	Diether Knof
   **
   **/
  Help&
    GTK_GUI::help()
    {
      DEBUG_CALLING(INFO_GTK_GUI && INFO_GTK_VALUE,
		    "GTK_GUI::help()");

      DEBUG_ASSERTION((this->help_p != NULL),
		      "GTK_GUI::help()\n"
		      "  'this->help_p' == NULL");

      DEBUG_RETURNING(*(this->help_p),
		      INFO_GTK_GUI && INFO_GTK_VALUE,
		      "GTK_GUI::help()");
    } // Help& GTK_GUI::help()

  /**
   **
   ** -> result
   **
   ** @param	-
   **
   ** @return	The about class
   ** 
   ** @version	0.4.4
   **
   ** @author	Diether Knof
   **
   **/
  About&
    GTK_GUI::about()
    {
      DEBUG_CALLING(INFO_GTK_GUI && INFO_GTK_VALUE,
		    "GTK_GUI::about()");

      DEBUG_ASSERTION((this->about_p != NULL),
		      "GTK_GUI::about()\n"
		      "  'this->about_p' == NULL");

      DEBUG_RETURNING(*(this->about_p),
		      INFO_GTK_GUI && INFO_GTK_VALUE,
		      "GTK_GUI::about()");
    } // About& GTK_GUI::about()

  /**
   **
   ** -> result
   **
   ** @param	-
   **
   ** @return	The license class
   ** 
   ** @version	0.4.4
   **
   ** @author	Diether Knof
   **
   **/
  License&
    GTK_GUI::license()
    {
      DEBUG_CALLING(INFO_GTK_GUI && INFO_GTK_VALUE,
		    "GTK_GUI::license()");

      DEBUG_ASSERTION((this->license_p != NULL),
		      "GTK_GUI::license()\n"
		      "  'this->license_p' == NULL");

      DEBUG_RETURNING(*(this->license_p),
		      INFO_GTK_GUI && INFO_GTK_VALUE,
		      "GTK_GUI::license()");
    } // License& GTK_GUI::license()

  /**
   **
   ** -> result
   **
   ** @param	-
   **
   ** @return	The license cardset class
   ** 
   ** @version	0.5.4
   **
   ** @author	Diether Knof
   **
   **/
  LicenseCardset&
    GTK_GUI::license_cardset()
    {
      DEBUG_CALLING(INFO_GTK_GUI && INFO_GTK_VALUE,
		    "GTK_GUI::license_cardset()");

      DEBUG_ASSERTION((this->license_cardset_p != NULL),
		      "GTK_GUI::license()\n"
		      "  'this->license_cardset_p' == NULL");

      DEBUG_RETURNING(*(this->license_cardset_p),
		      INFO_GTK_GUI && INFO_GTK_VALUE,
		      "GTK_GUI::license_cardset()");
    } // LicenseCardset& GTK_GUI::license_cardset()

  /*****************************************************************************
   *
   * MainWindow& GTK_GUI::main_window()
   *
   * Parameters:	none
   *
   * Result:	The main window
   * 
   * Version:	0.3.6
   *
   * Description:	Result
   *
   ****************************************************************************/
  MainWindow&
    GTK_GUI::main_window()
    {
      DEBUG_CALLING(INFO_GTK_GUI && INFO_GTK_VALUE,
		    "GTK_GUI::main_window()");

      DEBUG_ASSERTION((main_window_p != NULL),
		      "GTK_GUI::main_window()\n"
		      "  'main_window_p' == NULL");

      DEBUG_RETURNING(*main_window_p,
		      INFO_GTK_GUI && INFO_GTK_VALUE,
		      "GTK_GUI::main_window()");
    } // MainWindow& GTK_GUI::main_window()

  /*****************************************************************************
   *
   * Playfield& GTK_GUI::playfield()
   *
   * Parameters:	none
   *
   * Result:	The playfield class
   * 
   * Version:	0.3.6
   *
   * Description:	Result
   *
   ****************************************************************************/
  Playfield&
    GTK_GUI::playfield()
    {
      DEBUG_CALLING(INFO_GTK_GUI && INFO_GTK_VALUE,
		    "GTK_GUI::playfield()");

      DEBUG_ASSERTION((playfield_p != NULL),
		      "GTK_GUI::playfield()\n"
		      "  'playfield_p' == NULL");

      DEBUG_RETURNING(*playfield_p,
		      INFO_GTK_GUI && INFO_GTK_VALUE,
		      "GTK_GUI::playfield()");
    } // Playfield& GTK_GUI::playfield()

  /*****************************************************************************
   *
   * static void GTK_GUI::quit_event(GtkWidget*, gpointer gui)
   *
   * Parameters:	gui - gui of the event
   *
   * Result:	none
   *
   * Version:	0.3.7
   *
   * Description:	calls gui->quit()
   *
   ****************************************************************************/
  void
    GTK_GUI::quit_event(GtkWidget*, gpointer gui)
    {
      DEBUG_CALLING(INFO_GTK_GUI && INFO_GTK_EVENT,
		    "GTK_GUI::quit_event()");

      ((GTK_GUI*)gui)->quit();
      DEBUG_RETURNING(VOID,
		      INFO_GTK_GUI && INFO_GTK_EVENT,
		      "GTK_GUI::quit_event()");
    } // static void GTK_GUI::quit_event(GtkWidget*, gpointer gui)

  /*****************************************************************************
   *
   * void GTK_GUI::quit()
   *
   * Parameters:	none
   *
   * Result:	none
   *
   * Version:	0.3.7
   *
   * Description:	quits the program
   *
   ****************************************************************************/
  void
    GTK_GUI::quit()
    {
      DEBUG_CALLING(INFO_GTK_GUI && INFO_GTK_EVENT,
		    "GTK_GUI::quit()");

      game_status = GAMESTATUS::QUIT;
      main_quit();

      DEBUG_RETURNING(VOID,
		      INFO_GTK_GUI && INFO_GTK_EVENT,
		      "GTK_GUI::quit()");
    } // void GTK_GUI::quit()

  /*****************************************************************************
   *
   * void GTK_GUI::party_open()
   *
   * Parameters:	none
   *
   * Result:	none
   * 
   * Version:	0.3.7
   *
   * Description:	the party is opened
   *
   ****************************************************************************/
  void
    GTK_GUI::party_open()
    {
      DEBUG_CALLING(INFO_GTK_GUI && INFO_GTK_GAMEPLAY,
		    "GTK_GUI::party_open()");

      main_window().party_open();
      playfield().party_open();

      DEBUG_RETURNING(VOID,
		      INFO_GTK_GUI && INFO_GTK_GAMEPLAY,
		      "GTK_GUI::party_open()");
    } // void GTK_GUI::party_open()

  /*****************************************************************************
   *
   * void GTK_GUI::party_start()
   *
   * Parameters:	none
   *
   * Result:	none
   * 
   * Version:	0.3.7
   *
   * Description:	the party is started
   *
   ****************************************************************************/
  void
    GTK_GUI::party_start()
    {
      DEBUG_CALLING(INFO_GTK_GUI && INFO_GTK_GAMEPLAY,
		    "GTK_GUI::party_start()");

      main_window().party_start();
      playfield().party_start();

      update();

      DEBUG_RETURNING(VOID,
		      INFO_GTK_GUI && INFO_GTK_GAMEPLAY,
		      "GTK_GUI::party_start()");
    } // void GTK_GUI::party_start()

  /*****************************************************************************
   *
   * void GTK_GUI::game_open()
   *
   * Parameters:	none
   *
   * Result:	none
   * 
   * Version:	0.4.4
   *
   * Description:	the game is opened
   *
   ****************************************************************************/
  void
    GTK_GUI::game_open()
    {
      DEBUG_CALLING(INFO_GTK_GUI && INFO_GTK_GAMEPLAY,
		    "GTK_GUI::game_open()");

      this->main_window().game_open();
      this->playfield().game_open();
      this->bug_report().game_open();

      this->update();

      DEBUG_RETURNING(VOID,
		      INFO_GTK_GUI && INFO_GTK_GAMEPLAY,
		      "GTK_GUI::game_open()");
    } // void GTK_GUI::game_open()

  /*****************************************************************************
   *
   * void GTK_GUI::game_start()
   *
   * Parameters:	none
   *
   * Result:	none
   * 
   * Version:	0.3.6
   *
   * Description:	the game is started
   *
   ****************************************************************************/
  void
    GTK_GUI::game_start()
    {
      DEBUG_CALLING(INFO_GTK_GUI && INFO_GTK_GAMEPLAY,
		    "GTK_GUI::game_start()");

      main_window().game_start();
      playfield().game_start();

      update();

      DEBUG_RETURNING(VOID,
		      INFO_GTK_GUI && INFO_GTK_GAMEPLAY,
		      "GTK_GUI::game_start()");
    } // void GTK_GUI::game_start()

  /*****************************************************************************
   *
   * void GTK_GUI::game_finish()
   *
   * Parameters:	none
   *
   * Result:	none
   * 
   * Version:	0.3.6
   *
   * Description:	the game is finished
   *
   ****************************************************************************/
  void
    GTK_GUI::game_finish()
    {
      DEBUG_CALLING(INFO_GTK_GUI && INFO_GTK_GAMEPLAY,
		    "GTK_GUI::game_finish()");

      this->main_window().game_finish();
      this->playfield().game_finish();

      this->update();

      DEBUG_RETURNING(VOID,
		      INFO_GTK_GUI && INFO_GTK_GAMEPLAY,
		      "GTK_GUI::game_finish()");
    } // void GTK_GUI::game_finish()

  /*****************************************************************************
   *
   * void GTK_GUI::game_close()
   *
   * Parameters:	-
   *
   * Result:	-
   * 
   * Version:	0.4.4
   *
   * Description:	the game is closeed
   *
   ****************************************************************************/
  void
    GTK_GUI::game_close()
    {
      DEBUG_CALLING(INFO_GTK_GUI && INFO_GTK_GAMEPLAY,
		    "GTK_GUI::game_close()");

      this->main_window().game_close();
      this->playfield().game_close();
      this->bug_report().game_close();

      this->update();

      DEBUG_RETURNING(VOID,
		      INFO_GTK_GUI && INFO_GTK_GAMEPLAY,
		      "GTK_GUI::game_close()");
    } // void GTK_GUI::game_close()

  /*****************************************************************************
   *
   * void GTK_GUI::party_finish()
   *
   * Parameters:	none
   *
   * Result:	none
   * 
   * Version:	0.3.6
   *
   * Description:	the party is finished
   *
   ****************************************************************************/
  void
    GTK_GUI::party_finish()
    {
      DEBUG_CALLING(INFO_GTK_GUI && INFO_GTK_GAMEPLAY,
		    "GTK_GUI::party_finish()");

      main_window().party_finish();
      playfield().party_finish();

      update();

      DEBUG_RETURNING(VOID,
		      INFO_GTK_GUI && INFO_GTK_GAMEPLAY,
		      "GTK_GUI::party_finish()");
    } // void GTK_GUI::party_finish()

  /*****************************************************************************
   *
   * void GTK_GUI::party_close()
   *
   * Parameters:	none
   *
   * Result:	none
   * 
   * Version:	0.3.6
   *
   * Description:	the party is closeed
   *
   ****************************************************************************/
  void
    GTK_GUI::party_close()
    {
      DEBUG_CALLING(INFO_GTK_GUI && INFO_GTK_GAMEPLAY,
		    "GTK_GUI::party_close()");

      main_window().party_close();
      playfield().party_close();

      update();

      DEBUG_RETURNING(VOID,
		      INFO_GTK_GUI && INFO_GTK_GAMEPLAY,
		      "GTK_GUI::party_close()");
    } // void GTK_GUI::party_close()

  /*****************************************************************************
   *
   * ::Reservation GTK_GUI::reservation_get(Player const& player)
   *
   * Parameters:	player - player, whose reservation should be returned
   *
   * Result:	reservation of the player 'player'
   * 
   * Version:	0.3.6
   *
   * Description:	Result
   *
   ****************************************************************************/
  ::Reservation
    GTK_GUI::reservation_get(Player const& player)
    {
      DEBUG_CALLING(INFO_GTK_GUI && INFO_GTK_GAMEPLAY,
		    "GTK_GUI::reservation_get()");

      DEBUG_RETURNING(playfield().reservation().get(player),
		      INFO_GTK_GUI && INFO_GTK_GAMEPLAY,
		      "GTK_GUI::reservation_get()");
    } // void GTK_GUI::reservation_get(Player const& player)

  /*****************************************************************************
   *
   * void GTK_GUI::gametype_show()
   *
   * Parameters:	none
   *
   * Result:	none
   * 
   * Version:	0.3.6
   *
   * Description:	show the gametype
   *
   ****************************************************************************/
  void
    GTK_GUI::gametype_show()
    {
      DEBUG_CALLING(INFO_GTK_GUI && INFO_GTK_GAMEPLAY,
		    "GTK_GUI::gametype_show()");

      playfield().gametype().show();

      DEBUG_RETURNING(VOID,
		      INFO_GTK_GUI && INFO_GTK_GAMEPLAY,
		      "GTK_GUI::gametype_show()");
    } // void GTK_GUI::gametype_show()

  /*****************************************************************************
   *
   * Card GTK_GUI::card_get(Player const& player)
   *
   * Parameters:	player - player, who has to play a card
   *
   * Result:	played card of the player
   * 
   * Version:	0.3.6
   *
   * Description:	Result
   *
   ****************************************************************************/
  Card
    GTK_GUI::card_get(Player const& player)
    {
      DEBUG_CALLING(INFO_GTK_GUI && INFO_GTK_GAMEPLAY,
		    "GTK_GUI::card_get(player)");

      this->selected_card_p = UINT_MAX;

      while ( (selected_card() == UINT_MAX)
	      && (game_status == GAMESTATUS::GAME_PLAY) )
	gtk_main();

      if (!(::game_status & GAMESTATUS::GAME))
	DEBUG_RETURNING(player.hand().card(0),
			INFO_GTK_GUI && INFO_GTK_GAMEPLAY,
			"GTK_GUI::card_get(player)");

      DEBUG_ASSERTION((game_status == GAMESTATUS::GAME_PLAY),
		      "GTK_GUI::card_get(player):\n"
		      "  'game_status' != GAME_PLAY");

      // request that that card is to be played
      // (that is needed, if the player has two cards, that are the same)
      const_cast<Player&>(player).hand().request_position(this->selected_card());

      Card const& card = player.hand().card(this->selected_card());

      if (!::party.game().trick_current().isvalid(card, player.hand())
	  && (::setting(Setting::CARD_INVALID_DELAY) > 0)) {
	// the card is not valid -- change the cursor for a little time
	gdk_window_set_cursor(this->playfield().table().widget()->window,
			      gdk_cursor_new(GDK_GUMBY));
	gtk_timeout_add(::setting(Setting::CARD_INVALID_DELAY),
			GTK_GUI::cursor_reset_event,
			gpointer(this));
      }

      DEBUG_RETURNING(card,
		      INFO_GTK_GUI && INFO_GTK_GAMEPLAY,
		      "GTK_GUI::card_get(player)");
    } // Card const& GTK_GUI::card_get(Player const& player)

  /*****************************************************************************
   *
   * unsigned GTK_GUI::selected_card() const
   *
   * Parameters:	none
   *
   * Result:	the selected card
   *		UINT_MAX if none is selected
   * 
   * Version:	0.3.7
   *
   * Description:	Result
   *
   ****************************************************************************/
  unsigned
    GTK_GUI::selected_card() const
    {
      DEBUG_CALLING(INFO_GTK_GUI && INFO_GTK_VALUE,
		    "GTK_GUI::selected_card()");

      DEBUG_RETURNING(selected_card_p,
		      INFO_GTK_GUI && INFO_GTK_VALUE,
		      "GTK_GUI::selected_card()");
    } // unsigned GTK_GUI::selected_card() const

  /*****************************************************************************
   *
   * bool GTK_GUI::select_card_all(unsigned const card_all_nr_a)
   *
   * Parameters:	card_all_no - position in the hand (all cards)
   *
   * Result:	if the card can be selected
   * 
   * Version:	0.3.7
   *
   * Description:	selects the card, if a card can be selected
   *		and the card is valid
   *
   ****************************************************************************/
  bool
    GTK_GUI::select_card_all(unsigned const card_all_nr_a)
    {
      DEBUG_CALLING(INFO_GTK_GUI && INFO_GTK_GAMEPLAY,
		    "GTK_GUI::select_card_all()");


      if ((::game_status == GAMESTATUS::GAME_PLAY)
	  || ((::game_status == GAMESTATUS::GAME_POVERTY_SHIFT)
	      && this->playfield().table().poverty().accept_cards)
	     ) {
	Hand const& hand = party.game().player_current().hand();

	DEBUG_ASSERTION((card_all_nr_a < hand.cardsnumber_all()),
			"GTK_GUI::selected_card_all(card_all_nr_a):\n"
			"  'card_all_nr_a' is not valid");

	if (!hand.played(card_all_nr_a)) {
	  this->selected_card_p = hand.pos_all_to_pos(card_all_nr_a);
	  main_quit();

	  if (::game_status == GAMESTATUS::GAME_POVERTY_SHIFT) {
	    this->playfield().table().poverty().add_card_to_shift(this->selected_card());
	  } 

	  DEBUG_RETURNING(true,
			  INFO_GTK_GUI && INFO_GTK_GAMEPLAY,
			  "GTK_GUI::select_card_all()");
	} // if (!card played)
      } // if (game_status == GAMESTATUS::GAME_PLAY)

      DEBUG_RETURNING(false,
		      INFO_GTK_GUI && INFO_GTK_GAMEPLAY,
		      "GTK_GUI::select_card_all()");
    } // bool GTK_GUI::selected_card(unsigned const card_all_nr_a)

  /*****************************************************************************
   *
   * void GTK_GUI::language_update()
   *
   * Parameters:	none
   *
   * Result:	none
   * 
   * Version:	0.3.6
   *
   * Description:	updates the language in the gui
   *
   ****************************************************************************/
  void
    GTK_GUI::language_update()
    {
      DEBUG_CALLING(INFO_GTK_GUI && INFO_GTK_UPDATE,
		    "GTK_GUI::language_update()");

      this->settings().language_update();
      this->bug_report().language_update();
      this->help().language_update();
      this->license().language_update();
      this->license_cardset().language_update();
      this->about().language_update();
      this->main_window().language_update();
      this->playfield().language_update();


      DEBUG_RETURNING(VOID,
		      INFO_GTK_GUI && INFO_GTK_UPDATE,
		      "GTK_GUI::language_update()");
    } // void GTK_GUI::language_update()

  /**
   **
   ** show the window
   **
   ** @param	window	window, that shall be shown
   **
   ** @return	-
   **
   ** @author	Diether Knof
   **
   ** @version	0.5.4
   **
   **/
  void
    GTK_GUI::window_show(GtkWidget*, gpointer window)
    {
      DEBUG_CALLING(INFO_GTK_EVENT,
		    "GTK_DOKO::GTK_GUI::window_show()");

      if (!GTK_WIDGET_VISIBLE(GTK_WIDGET(window)))
	gtk_widget_show(GTK_WIDGET(window));

      DEBUG_RETURNING(VOID,
		      INFO_GTK_EVENT,
		      "GTK_DOKO::GTK_GUI::window_show()");
    } // static void GTK_GUI::window_show(GtkWidget*, gpointer window)

  /**
   **
   ** hide the window
   **
   ** @param	window	window, that shall be hidden
   **
   ** @return	-
   **
   ** @author	Diether Knof
   **
   ** @version	0.5.4
   **
   **/
  void
    GTK_GUI::window_hide(GtkWidget*, gpointer window)
    {
      DEBUG_CALLING(INFO_GTK_EVENT,
		    "GTK_DOKO::GTK_GUI::window_hide()");

      if (GTK_WIDGET_VISIBLE(GTK_WIDGET(window)))
	gtk_widget_hide(GTK_WIDGET(window));

      DEBUG_RETURNING(VOID,
		      INFO_GTK_EVENT,
		      "GTK_DOKO::GTK_GUI::window_hide()");
    } // static void GTK_GUI::window_hide(GtkWidget*, gpointer window)

  /*****************************************************************************
   *
   * static gboolean GTK_GUI::key_event_in_entry(GtkWidget*, GdkEventKey* key,
   *					       gpointer)
   *
   * Parameters:	key - the pressed key
   *
   * Result:	none
   *
   * Version:	0.4.2
   *
   * Description:	takes <Escape> for quitting the program
   *
   ****************************************************************************/
  gboolean
    GTK_GUI::key_event_in_entry(GtkWidget*, GdkEventKey* key, gpointer)
    {
      DEBUG_CALLING(INFO_GTK_GUI && INFO_GTK_KEY && INFO_GTK_EVENT,
		    "GTK_GUI::key_event_in_entry()");

#ifndef RELEASE
      switch (key->keyval) {
      case GDK_Escape:
	// quit the program
	GTK_GUI::quit_event(NULL, key);
	break;
      } // switch (key->keyval)
#endif

      DEBUG_RETURNING(FALSE,
		      INFO_GTK_GUI && INFO_GTK_KEY && INFO_GTK_EVENT,
		      "GTK_GUI::key_event_in_entry()");
    } // static gboolean GTK_GUI::key_event_in_entry(GtkWidget*, GdkEventKey*, gpointer)

  /**
   **
   ** manages the pressed key:
   **   C-q quits the program,
   **   C-n starts a new party,
   **   C-s toggles the settings window,
   **   C-r toggles the rules
   **   C-p toggles the party points window
   **   C-a toggles the about window
   **   C-i toggles the license window
   **
   ** @param	key	the pressed key
   **
   ** @return	-
   **
   ** @author	Diether Knof
   **
   ** @version	0.5.4
   **
   **/
  void
    GTK_GUI::key(GdkEventKey* key)
    {
      DEBUG_CALLING(INFO_GTK_GUI && INFO_GTK_KEY,
		    "GTK_GUI::key()");

      switch (key->keyval) {
#ifndef RELEASE
      case GDK_Escape:
	// quit the program
	this->quit();
	break;
#endif
      } // switch (key->keyval)

      if (key->state & GDK_SHIFT_MASK) {
	switch (key->keyval) {
	case GDK_Escape:
	  // quit the program
	  this->quit();
	  break;
	} // switch (key->keyval)
      } // if (key->state & GDK_SHIFT_MASK)


      if (key->state & GDK_CONTROL_MASK) {
	// with <Control>

	// toggle some windows
	switch (key->keyval) {
	case GDK_q: // quit the program
	  this->quit();
	  break;
	case GDK_n: // new party
	  ::game_status = GAMESTATUS::PARTY_NEW;
	  this->main_quit();
	  break;
	case GDK_s: // 'Setting'-window
	  this->settings().toggle();
	  break;
	case GDK_r: // rules: 'party_settings'-window
	  if (game_status & GAMESTATUS::GAME)
	    this->playfield().party_settings().toggle();
	  break;
	case GDK_p: // 'Party points'-window
	  this->playfield().table().party_points().toggle();
	  break;
	case GDK_a: // 'About'-window
	  this->about().toggle();
	  break;
	case GDK_l: // 'License'-window
	  this->license().toggle();
	  break;
	case GDK_L: // 'LicenseCardset'-window
	  this->license_cardset().toggle();
	  break;
#ifndef RELEASE
	case GDK_g: // the gamestatus
	  cout << "gamestatus: " << ::game_status << endl;
	  break;
#endif
	} // switch (key->keyval)
      } // if (key->state & GDK_CONTROL_MASK)

      DEBUG_RETURNING(VOID,
		      INFO_GTK_GUI && INFO_GTK_KEY,
		      "GTK_GUI::key()");
    } // void GTK_GUI::key(GdkKeyEvent);

  /*****************************************************************************
   *
   * static gint GTK_GUI::cursor_reset_event(gpointer gtk_gui)
   *
   * Parameters:	gtk_gui - gui of the event
   *
   * Result:	FALSE (do not call this timer event again)
   *
   * Version:	0.4
   *
   * Description:	the cursor is resetted
   *
   ****************************************************************************/
  gint
    GTK_GUI::cursor_reset_event(gpointer gtk_gui)
    {
      DEBUG_CALLING(INFO_GTK_GUI && INFO_GTK_EVENT,
		    "GTK_GUI::cursor_reset_event()");

      ((GTK_GUI*)gtk_gui)->cursor_reset();
      DEBUG_RETURNING(FALSE,
		      INFO_GTK_GUI && INFO_GTK_EVENT,
		      "GTK_GUI::cursor_reset_event()");
    } // static gint GTK_GUI::cursor_reset_event(gpointer gtk_gui)

  /*****************************************************************************
   *
   * void GTK_GUI::cursor_reset()
   *
   * Parameters:	-
   *
   * Result:	none
   *
   * Version:	0.4
   *
   * Description:	the cursor is resetted
   *
   ****************************************************************************/
  void
    GTK_GUI::cursor_reset()
    {
      DEBUG_CALLING(INFO_GTK_GUI && INFO_GTK_EVENT,
		    "GTK_GUI::cursor_reset()");

      gdk_window_set_cursor(this->playfield().table().widget()->window,
			    gdk_cursor_new(GDK_HAND1));

      DEBUG_RETURNING(VOID,
		      INFO_GTK_GUI && INFO_GTK_EVENT,
		      "GTK_GUI::cursor_reset()");
    } // void GTK_GUI::cursor_reset()


} // namespace GTK_DOKO
#endif // #ifdef USE_UI_GTK

