/**********************************************************************
 *
 *   FreeDoko a Doppelkopf-Game
 * 
 *   Copyright (C) 2001-2006  by Diether Knof and Borg Enders
 *
 *   This program is free software; you can redistribute it and/or 
 *   modify it under the terms of the GNU General Public License as 
 *   published by the Free Software Foundation; either version 2 of 
 *   the License, or (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details. 
 *   You can find this license in the file 'gpl.txt'.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program; if not, write to the Free Software
 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
 *   MA  02111-1307  USA
 *
 *  Contact:
 *    Diether Knof dknof@gmx.de
 *    Borg Enders  borg@borgsoft.de
 *
 ********************************************************************/

#include "constants.h"
#include "../utils/file.h"
#include "../utils/string.h"
#include "../utils/windows.h"

#include "setting.h"

#ifdef LINUX
#include <unistd.h>
#include <pwd.h>
#include <sys/types.h>
#endif
#include <sys/stat.h>

#include "translator.h"
#include "translations.h"

#include "../party/party.h"

#include "../ui/ui.h"
#include "../ui/ui.wrap.h"


#include "../text/gpl.string"
#include "../text/Altenburg.string"


// number of the Type
unsigned const Setting::BOOL_NUMBER = (1 + Setting::BOOL_LAST
				       - Setting::BOOL_FIRST);
unsigned const Setting::UNSIGNED_NUMBER = (1 + Setting::UNSIGNED_LAST
					   - Setting::UNSIGNED_FIRST);
unsigned const Setting::STRING_NUMBER = (1 + Setting::STRING_LAST
					 - Setting::STRING_FIRST);
unsigned const Setting::STRING_CONST_NUMBER = (1 + Setting::STRING_CONST_LAST
					       - Setting::STRING_CONST_FIRST);

string GPL = GPL_string;
string cardset_license;


/**********************************************************************
 *
 ** Setting::Setting()
 *
 ** Parameters:	none
 *
 ** Result:	none
 *
 ** Version:	0.3.7
 *
 ** Description:	Constructor
 **   
 **********************************************************************/
Setting::Setting() :
  bool_p(BOOL_NUMBER),
  unsigned_p(UNSIGNED_NUMBER),
  string_p(STRING_NUMBER, ""),
  cards_order_p()
{
  DEBUG_CALLING(INFO_SETTING && INFO_INIT,
		"Setting::Setting()");

#if 0
  this->set(PUBLIC_DATA_DIRECTORY,	"");
  this->set(PRIVATE_DATA_DIRECTORY,	"");
  this->set(SETTINGS_FILE,		"FreeDokorc");
  this->set(LANGUAGES_DIRECTORY,	"translations");
  this->set(LANGUAGE_FILE,		"text");
  this->set(GRAPHIC_EXTENSION,		"png");
  this->set(CARDSETS_DIRECTORY,		"cardsets");
  this->set(CARDS_DIRECTORY,		"cards");
  this->set(CARDS_BACK_DIRECTORY,	"back");
  this->set(ICONS_DIRECTORY,		"icons");
  this->set(BACKGROUNDS_DIRECTORY,	"backgrounds");
  this->set(SOUND_DIRECTORY,		"sound");
  this->set(AI_DIRECTORY,		"ai");
  this->set(PARTIES_DIRECTORY,		"rules");
  this->set(RULES_DIRECTORY,		"rules");
  this->set(SETTINGS_DIRECTORY,		"settings");
  this->set(HELP_DIRECTORY,		"/usr/share/doc/manual");
#endif

  this->set(SAVE_PARTY_CHANGES,		true);

  if (this == &::setting)
    Translator::dir_scan();

  this->set(LANGUAGE,			"");

  this->set(NAME,			"");

  this->set(SHOW_SPLASH_SCREEN,		true);
  this->set(SPLASH_SCREEN_TRANSPARENT,	false);

  this->set(SHOW_BUG_REPORT_BUTTON_IN_GAME_FINISHED_WINDOW,	true);
  this->set(SAVE_BUG_REPORTS_ON_DESKTOP,	true);

  this->set(SOUND,			true);

  this->set(AUTOMATIC_CARD_SUGGESTION,	false);
  this->set(ANNOUNCE_SWINES_AUTOMATICALLY,	true);
  this->set(SHOW_IF_VALID,		true);
  this->set(EMPHASIZE_VALID_CARDS,	false);
  this->set(ANNOUNCE_IN_TABLE,		true);
  this->set(SHOW_ALL_HANDS,		false);
  this->set(SHOW_AI_INFORMATION_HANDS,	false);
  this->set(SHOW_AI_INFORMATION_TEAMS,	false);
  this->set(SHOW_TRICKPILES_POINTS,	true);
  this->set(SHOW_KNOWN_TEAMS_IN_GAME,	true);
  this->set(SHOW_SOLOPLAYER_IN_GAME,	true);

  this->set(SHOW_FULL_TRICK_WINDOW,	true);
  this->set(SHOW_FULL_TRICK_WINDOW_IF_SPECIAL_POINTS,	true);
  this->set(CLOSE_FULL_TRICK_AUTOMATICALLY,	false);

  this->set(SHOW_GAMETYPE_WINDOW,			true);
  this->set(CLOSE_GAMETYPE_WINDOW_AUTOMATICALLY,	false);
  this->set(SHOW_MARRIAGE_WINDOW,		true);
  this->set(CLOSE_MARRIAGE_WINDOW_AUTOMATICALLY,	false);
  this->set(SHOW_GENSCHER_WINDOW,			true);
  this->set(CLOSE_GENSCHER_WINDOW_AUTOMATICALLY,	false);
  this->set(SHOW_ANNOUNCEMENT_WINDOW,			true);
  this->set(CLOSE_ANNOUNCEMENT_WINDOW_AUTOMATICALLY,	false);
  this->set(SHOW_SWINES_WINDOW,				true);
  this->set(CLOSE_SWINES_WINDOW_AUTOMATICALLY,		false);

  this->set(ROTATE_TRICK_CARDS,		false);
  this->set(CARDS_ORDER,		"trump up, club down, heart down, spade down, diamond down");


  this->set(CARD_PLAY_DELAY,			500);
  this->set(FULL_TRICK_CLOSE_DELAY,		2000);

  this->set(GAMETYPE_WINDOW_CLOSE_DELAY,	2000);
  this->set(MARRIAGE_WINDOW_CLOSE_DELAY,20);
  this->set(GENSCHER_WINDOW_CLOSE_DELAY,	2000);
  this->set(ANNOUNCEMENT_WINDOW_CLOSE_DELAY,	2000);
  this->set(SWINES_WINDOW_CLOSE_DELAY,		2000);

  this->set(ORIGINAL_CARDS_SIZE,		true);
  this->set(CARDS_HEIGHT,			140);

  this->set(OWN_HAND_ON_TABLE_BOTTOM,		true);
  this->set(TABLE_ROTATION,			0);

  //this->set(CARDSET,		"xskat/french");
  //this->set(CARDS_BACK,			"xskat");
  this->set(CARDSET,			"Altenburg/french");
  this->set(CARDS_BACK,			"penguin");
  this->set(BACKGROUND,			"table");


  this->set(NAME_FONT,			"Serif Bold Italic 16");
  this->set(NAME_FONT_COLOR,		"black");
  this->set(NAME_ACTIVE_FONT_COLOR,	"red");
  this->set(TRICKPILE_POINTS_FONT,	"Serif Bold 18");
  this->set(TRICKPILE_POINTS_FONT_COLOR,"black");

  this->set(POVERTY_SHIFT_ARROW_COLOR,"black");

  this->set(BROWSER,			"");

  if (this == &::setting)
    ::translator.load();

  DEBUG_RETURNING(VOID,
		  INFO_SETTING && INFO_INIT,
		  "Setting::Setting()");
} // Setting::Setting

/**********************************************************************
 *
 ** Setting::Setting(Setting const& setting)
 *
 ** Parameters:	setting	- setting to set equal
 *
 ** Result:	-
 *
 ** Version:	0.4.2
 *
 ** Description:	constructor
 *
 **********************************************************************/
Setting::Setting(Setting const& setting):
  bool_p(setting.bool_p),
  unsigned_p(setting.unsigned_p),
  string_p(setting.string_p),
  cards_order_p(setting.cards_order_p)
{
  DEBUG_CALLING(INFO_SETTING && INFO_VALUE,
		"Setting::Setting(Setting)");

  this->update_all();

  DEBUG_RETURNING(VOID,
		  INFO_SETTING && INFO_VALUE,
		  "Setting::Setting(Setting)");
} // Setting::Setting(Setting const& setting) const

/**********************************************************************
 *
 ** Setting& Setting::operator=(Setting const& setting)
 *
 ** Parameters:	setting	- setting to set equal
 *
 ** Result:	new setting
 *
 ** Version:	0.4.2
 *
 ** Description:	sets the setting '*this' equal 'setting'
 *
 **********************************************************************/
Setting&
Setting::operator=(Setting const& setting)
{
  DEBUG_CALLING(INFO_SETTING && INFO_VALUE,
		"Setting::operator=(Setting)");

  unsigned i;
  for (i = BOOL_FIRST; i <= BOOL_LAST; i++)
    this->set(TypeBool(i), setting.value(TypeBool(i)));
  for (i = UNSIGNED_FIRST; i <= UNSIGNED_LAST; i++)
    this->set(TypeUnsigned(i), setting.value(TypeUnsigned(i)));
  for (i = STRING_FIRST; i <= STRING_LAST; i++)
    this->set(TypeString(i), setting.value(TypeString(i)));
  this->set(CARDS_ORDER, setting.value(CARDS_ORDER));

  DEBUG_RETURNING(*this,
		  INFO_SETTING && INFO_VALUE,
		  "Setting::operator=(Setting)");
} // bool Setting::operator=(Setting const& setting) const

/**
 **
 ** -> result
 **
 ** @param	-
 **
 ** @return	a vector with all data directories
 **
 ** @version	0.6.3
 **
 ** @author	Diether Knof
 **
 **/
vector<string>
Setting::data_directories() const
{
  DEBUG_CALLING(INFO_SETTING && INFO_VALUE,
		"Setting::data_directories()");

  // search the directory
  vector<string> data_dirs;
  data_dirs.push_back(this->value(PRIVATE_DATA_DIRECTORY));
  data_dirs.push_back(this->value(PUBLIC_DATA_DIRECTORY));
  if (this->value(PRIVATE_DATA_DIRECTORY)
      != ".")
    data_dirs.push_back(".");
  if (this->value(PRIVATE_DATA_DIRECTORY)
      != ::setting_default(PRIVATE_DATA_DIRECTORY))
    data_dirs.push_back(::setting_default(PRIVATE_DATA_DIRECTORY));
  if (this->value(PUBLIC_DATA_DIRECTORY)
      != ::setting_default(PUBLIC_DATA_DIRECTORY))
    data_dirs.push_back(::setting_default(PRIVATE_DATA_DIRECTORY));

  DEBUG_RETURNING(data_dirs,
		  INFO_SETTING && INFO_VALUE,
		  "Cards::search_directory()");
} // vector<string> Setting::data_directories() const


/**********************************************************************
 *
 ** bool Setting::operator()(const TypeBool type)
 *
 ** Parameters:	type - Settingtype
 *
 ** Result:	whether the setting 'type' is active
 *
 ** Version:	0.3.7
 *
 ** Description:	-> result
 **   
 **********************************************************************/
bool
Setting::operator()(const TypeBool type) const
{
  DEBUG_CALLING(INFO_SETTING && INFO_VALUE,
		"Setting::operator()(TypeBool)");

  if (FAST_PLAY
      && (type == Setting::SHOW_ALL_HANDS))
    DEBUG_RETURNING(true,
		    INFO_SETTING && INFO_VALUE,
		    "Setting::operator()(TypeBool)");

  DEBUG_RETURNING(this->dependencies(type)
		  && this->value(type),
		  INFO_SETTING && INFO_VALUE,
		  "Setting::operator()(TypeBool)");
} // bool Setting::operator()(const TypeBool type) const

/**********************************************************************
 *
 ** unsigned Setting::operator()(const TypeUnsigned type)
 *
 ** Parameters:	type - Settingtype
 *
 ** Result:	The setting 'type'
 *
 ** Version:	0.3.7
 *
 ** Description:	-> result
 **   
 **********************************************************************/
unsigned
Setting::operator()(const TypeUnsigned type) const
{
  DEBUG_CALLING(INFO_SETTING && INFO_VALUE,
		"Setting::operator()(TypeUnsigned)");

  DEBUG_RETURNING(this->value(type),
		  INFO_SETTING && INFO_VALUE,
		  "Setting::operator()(TypeUnsigned)");
} // unsigned Setting::operator()(const TypeUnsigned type) const

/**
 **
 ** -> result
 **
 ** @param	type	Settingtype
 **
 ** @return	the setting 'type'
 **
 ** @version	0.6.3
 **
 ** @author	Diether Knof
 **   
 **/
string
Setting::operator()(const TypeString type) const
{
  DEBUG_CALLING(INFO_SETTING && INFO_VALUE,
		"Setting::operator()(TypeString)");

  string value = this->value(type);

  if (value.empty()) {
    switch(type) {
    case NAME:
#ifdef LINUX
      value = getpwuid(geteuid())->pw_gecos;
      if (value.empty())
	// no real name - take the login
	value = getpwuid(geteuid())->pw_name;
#endif
#ifdef WINDOWS
#ifdef USE_REGISTRY
      // *** DK value = string(getenv("USERNAME"));
      if (value.empty())
	// Microsoft Windows XP
	value = DK::Utils::Windows::Reg_read(HKEY_CURRENT_USER,
					     "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer",
					     "Logon User Name");
      if (value.empty())
	// Microsoft Windows XP
	value = DK::Utils::Windows::Reg_read(HKEY_LOCAL_MACHINE,
					     "Software\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon",
					     "DefaultUserName");
      if (value.empty())
	// Microsoft Windows XP
	value = DK::Utils::Windows::Reg_read(HKEY_LOCAL_MACHINE,
					     "Software\\Microsoft\\Windows NT\\CurrentVersion",
					     "RegisteredOwner");
      if (value.empty())
	// Microsoft Windows XP: -
	value = DK::Utils::Windows::Reg_read(HKEY_LOCAL_MACHINE,
					     "Network\\Logon",
					     "username");
      if (value.empty())
	// Microsoft Windows XP: USERNAME
	value = DK::Utils::Windows::Reg_read(HKEY_LOCAL_MACHINE,
					     "System\\CurrentControlSet\\Control",
					     "CurrentUser");
      if (value.empty())
	// Microsoft Windows XP: -
	value = DK::Utils::Windows::Reg_read(HKEY_LOCAL_MACHINE,
					     "Software\\Microsoft\\Windows\\CurrentVersion",
					     "CurrentUser");
      if (value.empty())
	value = DK::Utils::Windows::Reg_read(HKEY_LOCAL_MACHINE,
					     "Software\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon",
					     "DefaultUserName");
#else
      value = "Player";
#endif
#endif
      break;
    case LANGUAGE:
      value = "en";
#ifdef LINUX
      if (getenv("LANG"))
	if (string(getenv("LANG"), 0, 2) == string("de"))
	  value = "de";
#endif
#ifdef WINDOWS
      value = DK::Utils::Windows::Reg_read(HKEY_LOCAL_MACHINE,
					   "Software\\FreeDoko",
					   "Language");

      if (value.empty()) {
	// Ein bisschen kompliziert, aus der Registry die Sprache auszulesen:
	// zuerst wird der Laenderkode gelesen (Deutsch: 407),
	// anschliessend wird geschaut, welche Sprache zu dem Laendercode
	// gehoert.
	string const language_code
	  = DK::Utils::Windows::Reg_read(HKEY_CURRENT_USER,
					 "Control Panel\\International",
					 "Locale");

	if (!language_code.empty()) {
	  if (string(language_code, language_code.size() - 1)
	      == "7") { // deutsch
	    value = "de";
	  } else if (string(language_code, language_code.size() - 1)
		     == "9") { // english
	    value = "en";
	  } else if (string(language_code, language_code.size() - 1)
		     == "A") { // spanish
	    value = "en";
	  } else if (string(language_code, language_code.size() - 1)
		     == "C") { // francais
	    value = "en";
	  } else { // unknown language code
	    value = "en";
	  } // unknown langugage code
	} // if (!language_code.empty())

      } // if (value.empty())

      if (value.empty()) {
	// *** DK
	// I didn't find the language in the registry, so I use this workaround
	if ((DK::Utils::Windows::Reg_read(HKEY_LOCAL_MACHINE,
					  "Software\\Microsoft\\Windows\\CurrentVersion",
					  "ProgramFilesDir") == string("C:\\Programme"))
	    && (DK::Utils::Windows::Reg_read(HKEY_LOCAL_MACHINE,
					     "Software\\Microsoft\\Windows\\CurrentVersion",
					     "ProgramFilesPath") == string("C:\\Programme")
	       )
	   )
	  value = "de";
      } // if (value.empty())
#endif
      break;
    case CARDSET:
      value = "xskat/default";
      break;
    case CARDS_BACK:
      value = "default";
      break;
    case BACKGROUND:
      value = "default";
      break;
    case NAME_FONT:
      value = "Serif Bold Italic 16";
      break;
    case NAME_FONT_COLOR:
      value = "black";
      break;
    case NAME_ACTIVE_FONT_COLOR:
      value = "red";
      break;
    case TRICKPILE_POINTS_FONT:
      value = "Serif Bold 18";
      break;
    case TRICKPILE_POINTS_FONT_COLOR:
      value = "black";
      break;
    case POVERTY_SHIFT_ARROW_COLOR:
      value = "black";
      break;
    case BROWSER:
#ifdef LINUX
      value = "echo could not open a browser for"; // if nothing else works
      if (getenv("BROWSER") != NULL) {
	value = string(getenv("BROWSER"));
	break;
      }  // if (getenv("BROWSER") != NULL)

      { // test some browsers and take the first found
	vector<string> browsers;
	browsers.push_back("firefox");
	browsers.push_back("epiphany");
	browsers.push_back("galeon");
	browsers.push_back("mozilla");
	browsers.push_back("opera");
	browsers.push_back("konqueror");
	browsers.push_back("netscape");
	browsers.push_back("xterm -e w3m");
	browsers.push_back("xterm -e links");
	browsers.push_back("xterm -e lynx");

	for (vector<string>::const_iterator browser = browsers.begin();
	     browser != browsers.end();
	     browser++)
	  if (::system(("test -x /usr/bin/" + *browser
			+ " -o -x /usr/bin/X11/" + *browser
			+ " -o -x /usr/local/bin/" + *browser).c_str())
	      == 0) {
	    value = *browser;
	    break;
	  }
      } // test some browsers and take the first found
#endif
#ifdef WINDOWS
      // ***DK look in the registry for the default browser for html
#ifdef USE_REGISTRY
      value = DK::Utils::Windows::Reg_read(HKEY_LOCAL_MACHINE,
					   "Software\\CLASSES\\.html",
					   "");
      if (value != "")
	value = DK::Utils::Windows::Reg_read(HKEY_LOCAL_MACHINE,
					     "Software\\CLASSES\\" + value
					     + "\\shell\\open\\command",
					     "");
      if (string(value, value.size() - 4, std::string::npos) == "\"\%1\"")
	value = string(value, 0, value.size() - 4);
#else
#endif
      if (value == "")
	value = "explorer";
#endif
      break;
    } // switch(type)
  } // if (value.empty())

  switch(type) {
  case CARDSET:
    value = ((*this)(CARDSETS_DIRECTORY) + "/"
	     + value);
    break;
  case CARDS_BACK:
    value = ((*this)(CARDS_BACK_DIRECTORY) + "/"
	     + value);
    break;
  case BACKGROUND:
    value = ((*this)(BACKGROUNDS_DIRECTORY) + "/"
	     + value);
    break;
  case NAME:
  case LANGUAGE:
  case NAME_FONT:
  case NAME_FONT_COLOR:
  case NAME_ACTIVE_FONT_COLOR:
  case TRICKPILE_POINTS_FONT:
  case TRICKPILE_POINTS_FONT_COLOR:
  case POVERTY_SHIFT_ARROW_COLOR:
  case BROWSER:
    break;
  } // switch(type)

  DEBUG_RETURNING(value,
		  INFO_SETTING && INFO_VALUE,
		  "Setting::operator()(TypeString)");
} // string Setting::operator()(const TypeString type) const

/**********************************************************************
 *
 ** string Setting::operator()(const TypeStringConst type)
 *
 ** Parameters:	type - Settingtype
 *
 ** Result:	The setting 'type'
 *
 ** Version:	0.4.3
 *
 ** Description:	-> result
 **   
 **********************************************************************/
string
Setting::operator()(const TypeStringConst type) const
{
  DEBUG_CALLING(INFO_SETTING && INFO_VALUE,
		"Setting::operator()(TypeStringConst)");

  string value;

  switch(type) {
  case PUBLIC_DATA_DIRECTORY:
    value = DK::Utils::File::filename_expand(this->value(PUBLIC_DATA_DIRECTORY));
    break;
  case PRIVATE_DATA_DIRECTORY:
    value = DK::Utils::File::filename_expand(this->value(PRIVATE_DATA_DIRECTORY));
    break;
  case SETTINGS_FILE:
    value = ((*this)(PRIVATE_DATA_DIRECTORY)
	     + "/" + this->value(type));
    break;
  case LANGUAGES_DIRECTORY:
    value = this->value(type);
    break;
  case LANGUAGE_FILE:
    value = ((*this)(LANGUAGES_DIRECTORY) + "/"
	     + (*this)(LANGUAGE) + "/"
	     + this->value(type));
    break;
  case GRAPHIC_EXTENSION:
    value = this->value(type);
    break;
  case CARDSETS_DIRECTORY:
    value = this->value(type);
    break;
  case CARDS_DIRECTORY:
    value = ((*this)(CARDSET) + "/"
	     + this->value(type));
    break;
  case CARDS_BACK_DIRECTORY:
    value = ((*this)(CARDSET) + "/"
	     + this->value(type));
    break;
  case ICONS_DIRECTORY:
    value = ((*this)(CARDSET) + "/"
	     + this->value(type));
    break;
  case BACKGROUNDS_DIRECTORY:
    value = this->value(type);
    break;
  case SOUND_DIRECTORY:
    value = this->value(type);
    break;
  case AI_DIRECTORY:
    value = this->value(type);
    break;
  case PARTIES_DIRECTORY:
    value = this->value(type);
    break;
  case RULES_DIRECTORY:
    value = this->value(type);
    break;
  case SETTINGS_DIRECTORY:
    value = this->value(type);
    break;
  case HELP_DIRECTORY:
    value = this->value(type);
    break;
  } // switch(type)

  DEBUG_RETURNING(value,
		  INFO_SETTING && INFO_VALUE,
		  "Setting::operator()(TypeStringConst)");
} // string Setting::operator()(const TypeStringConst type) const

/**********************************************************************
 *
 ** CardsOrder const& Setting::operator()(const TypeCardsOrder type)
 *
 ** Parameters:	type - Settingtype
 *
 ** Result:	The setting 'type'
 *
 ** Version:	0.3.7
 *
 ** Description:	-> result
 **   
 **********************************************************************/
CardsOrder const&
Setting::operator()(const TypeCardsOrder type) const
{
  DEBUG_CALLING(INFO_SETTING && INFO_VALUE,
		"Setting::operator()(TypeCardsOrder)");

  DEBUG_RETURNING(this->value(type),
		  INFO_SETTING && INFO_VALUE,
		  "Setting::operator()(TypeCardsOrder)");
} // CardsOrder const& Setting::operator()(const TypeCardsOrder type) const

/**********************************************************************
 *
 ** CardsOrder Setting::operator()(const TypeCardsOrder type)
 *
 ** Parameters:	type - Settingtype
 *
 ** Result:	The setting 'type'
 *
 ** Version:	0.3.7
 *
 ** Description:	-> result
 **   
 **********************************************************************/
CardsOrder&
Setting::operator()(const TypeCardsOrder type)
{
  DEBUG_CALLING(INFO_SETTING && INFO_VALUE,
		"Setting::operator()(TypeCardsOrder)");

  DEBUG_RETURNING(this->value(type),
		  INFO_SETTING && INFO_VALUE,
		  "Setting::operator()(TypeCardsOrder)");
} // CardsOrder& Setting::operator()(const TypeCardsOrder type)

/**
 ** -> result
 **
 ** @param	name	name of the type
 **
 ** @return	the type with the name 'name';
 **		-1, if the name is not recognized
 **
 ** @author	Diether Knof
 **
 ** @version	0.7.0
 **/
int
Setting::type(string const& name) const
{
  DEBUG_CALLING(INFO_SETTING && INFO_VALUE,
		"Setting::type(name)");

  for (int t = BOOL_FIRST; t <= BOOL_LAST; ++t)
    if (name == ::name(TypeBool(t)))
      return t;

  for (int t = UNSIGNED_FIRST; t <= UNSIGNED_LAST; ++t)
    if (name == ::name(TypeUnsigned(t)))
      return t;

  for (int t = STRING_FIRST; t <= STRING_LAST; ++t)
    if (name == ::name(TypeString(t)))
      return t;

  if (name == ::name(CARDS_ORDER))
    return CARDS_ORDER;

  return -1;
} // int Setting::type(string const& name) const

/**
 ** -> result
 **
 ** @param	name	name of the type
 **
 ** @return	the type with the translated name 'name';
 **		-1, if the name is not recognized
 **
 ** @author	Diether Knof
 **
 ** @version	0.7.0
 **/
int
Setting::type_translated(string const& name) const
{
  for (int t = BOOL_FIRST; t <= BOOL_LAST; t++)
    if (name == ::translation(TypeBool(t)))
      return t;

  for (int t = UNSIGNED_FIRST; t <= UNSIGNED_LAST; t++)
    if (name == ::translation(TypeUnsigned(t)))
      return t;

  for (int t = STRING_FIRST; t <= STRING_LAST; t++)
    if (name == ::translation(TypeString(t)))
      return t;

  if (name == ::translation(CARDS_ORDER))
    return CARDS_ORDER;

  return -1;
} // int Setting::type_translated(string const& name) const


/**
 ** -> result
 **
 ** @param	name	name of the type
 **
 ** @return	the type with the translated or normal name 'name';
 **		-1, if the name is not recognized
 **
 ** @author	Diether Knof
 **
 ** @version	0.7.0
 **/
int
Setting::type_translated_or_normal(string const& name) const
{
  int type = this->type_translated(name);
  if (type == -1)
    type = this->type(name);

  return type;
} // int Setting::type_translated_or_normal(string const& name) const

/**
 ** -> result
 **
 ** @param	typ	the type (bool)
 **
 ** @return	whether the dependencies of the setting 'type' are met
 **
 ** @author	Diether Knof
 **
 ** @version	0.6.1
 **/
bool
Setting::dependencies(TypeBool const& type) const
{
  switch(type) {
  case SPLASH_SCREEN_TRANSPARENT:
    return (*this)(SHOW_SPLASH_SCREEN);
  case AUTOMATIC_CARD_SUGGESTION:
  case ANNOUNCE_SWINES_AUTOMATICALLY:
  case SHOW_IF_VALID:
  case EMPHASIZE_VALID_CARDS:
  case ANNOUNCE_IN_TABLE:
  case SHOW_ALL_HANDS:
  case SHOW_AI_INFORMATION_HANDS:
  case SHOW_AI_INFORMATION_TEAMS:
  case SHOW_TRICKPILES_POINTS:
  case SHOW_KNOWN_TEAMS_IN_GAME:
  case SHOW_SOLOPLAYER_IN_GAME:
    // the showing is also dependent of the rule
    return true;
  case SHOW_FULL_TRICK_WINDOW_IF_SPECIAL_POINTS:
    return !(*this)(SHOW_FULL_TRICK_WINDOW);
  case CLOSE_GAMETYPE_WINDOW_AUTOMATICALLY:
    return (*this)(SHOW_GAMETYPE_WINDOW);
  case CLOSE_MARRIAGE_WINDOW_AUTOMATICALLY:
    return (*this)(SHOW_MARRIAGE_WINDOW);
  case CLOSE_GENSCHER_WINDOW_AUTOMATICALLY:
    return (*this)(SHOW_GENSCHER_WINDOW);
  case CLOSE_ANNOUNCEMENT_WINDOW_AUTOMATICALLY:
    return (*this)(SHOW_ANNOUNCEMENT_WINDOW);
  case CLOSE_SWINES_WINDOW_AUTOMATICALLY:
    return (*this)(SHOW_SWINES_WINDOW);
  default:
    return true;
  } // switch(type)

  return true;
} // bool Setting::dependencies(TypeBool const& type) const

/**
 ** -> result
 **
 ** @param	typ	the type (unsigned)
 **
 ** @return	whether the dependencies of the setting 'type' are met
 **
 ** @author	Diether Knof
 **
 ** @version	0.7.0
 **/
bool
Setting::dependencies(TypeUnsigned const& type) const
{
  switch(type) {
  case FULL_TRICK_CLOSE_DELAY:
    return (*this)(CLOSE_FULL_TRICK_AUTOMATICALLY);
  case GAMETYPE_WINDOW_CLOSE_DELAY:
    return (*this)(CLOSE_GAMETYPE_WINDOW_AUTOMATICALLY);
  case MARRIAGE_WINDOW_CLOSE_DELAY:
    return (*this)(CLOSE_MARRIAGE_WINDOW_AUTOMATICALLY);
  case GENSCHER_WINDOW_CLOSE_DELAY:
    return (*this)(CLOSE_GENSCHER_WINDOW_AUTOMATICALLY);
  case ANNOUNCEMENT_WINDOW_CLOSE_DELAY:
    return (*this)(CLOSE_ANNOUNCEMENT_WINDOW_AUTOMATICALLY);
  case SWINES_WINDOW_CLOSE_DELAY:
    return (*this)(CLOSE_SWINES_WINDOW_AUTOMATICALLY);
  case CARDS_HEIGHT:
    return !(*this)(ORIGINAL_CARDS_SIZE);
  default:
    return true;
  } // switch(type)

  return true;
} // bool Setting::dependencies(TypeUnsigned const& type) const

/**
 ** -> result
 **
 ** @param	typ	the type (string)
 **
 ** @return	whether the dependencies of the setting 'type' are met
 **
 ** @author	Diether Knof
 **
 ** @version	0.7.0
 **/
bool
Setting::dependencies(TypeString const& type) const
{
  (void)type;
  return true;
} // bool Setting::dependencies(TypeString const& type) const

/**
 ** -> result
 **
 ** @param	type	setting type
 **
 ** @return	the value of the setting 'type'
 ** 
 ** @author	Diether Knof
 **
 ** @version	0.7.0
 **/
bool const&
Setting::value(const TypeBool type) const
{
#ifndef POSTPHONED
  // *** DK
  // else there is a compiler warning: returning reference to temporary
  static bool value = false;
  value = this->bool_p[type - BOOL_FIRST];
  return value;
#else // #ifndef POSTPHONED
  return this->bool_p[type - BOOL_FIRST];
#endif // #ifndef POSTPHONED
} // bool const& Setting::value(const TypeBool type) const

/**
 ** -> result
 **
 ** @param	type	setting type
 **
 ** @return	the value of the (bool) setting 'type'
 ** 
 ** @author	Diether Knof
 **
 ** @version	0.7.0
 **/
unsigned const&
Setting::value(const TypeUnsigned type) const
{
  return this->unsigned_p[type - UNSIGNED_FIRST];
} // unsigned const& Setting::value(const TypeUnsigned type)

/**
 ** -> result
 **
 ** @param	type	setting type
 **
 ** @return	the value of the (unsigned) setting 'type'
 ** 
 ** @author	Diether Knof
 **
 ** @version	0.7.0
 **/
string const&
Setting::value(TypeString const type) const
{
  return this->string_p[type - STRING_FIRST];
} // string const& Setting::value(TypeString const type)

/**
 ** -> result
 **
 ** @param	type	setting type
 **
 ** @return	the value of the (string) setting 'type'
 ** 
 ** @author	Diether Knof
 **
 ** @version	0.7.0
 **/
string const
Setting::value(TypeStringConst const type) const
{
  switch(type) {
  case PUBLIC_DATA_DIRECTORY:
    {
  string value;

#ifdef PUBLIC_DATA_DIRECTORY_VALUE
    value = PUBLIC_DATA_DIRECTORY_VALUE;
#else // !#ifdef PUBLIC_DATA_DIRECTORY_VALUE

#ifdef RELEASE

#ifndef WINDOWS
    value = "/usr/share/games/FreeDoko";
#else // !#ifndef WINDOWS
    value = DK::Utils::Windows::Reg_read(HKEY_LOCAL_MACHINE,
					 "Software\\FreeDoko",
					 "Directory");
#endif // #ifndef WINDOWS

#else // !#ifdef RELEASE
    value = "../data";
#endif // !#ifdef RELEASE

    { // test that the directory exists
      struct stat status;
      stat(value.c_str(), &status);
      if (!S_ISDIR(status.st_mode))
	value = ".";
    } // test that the directory exists

#endif // !#ifdef PUBLIC_DATA_DIRECTORY_VALUE
    if (value.empty())
      value = ".";
    return value;
    }
    break;
  case PRIVATE_DATA_DIRECTORY:
    {
      string value;
#if defined(LINUX) || defined(HPUX)
      value = "~/.FreeDoko";
#endif
#ifdef WINDOWS
      value = "~/FreeDoko";
#endif
      return DK::Utils::File::filename_expand(value);
    }
  case SETTINGS_FILE:
    return "FreeDokorc";
  case LANGUAGES_DIRECTORY:
    return "translations";
  case LANGUAGE_FILE:
    return "text";
  case GRAPHIC_EXTENSION:
    if (::ui) {
      UI* ui = ::ui;
      while (ui->type() == UI_TYPE::WRAP) {
	ui = ((UI_Wrap*)(ui))->ui;
      } // while (ui->type == UI_TYPE::WRAP)

      switch(ui->type()) {
      case UI_TYPE::DUMMY:
#ifdef POSTPHONED
	DEBUG_ASSERTION(false,
			"Call of 'setting.value(GRAPHIC_EXTENSION)'"
			" with 'ui.type() == DUMMY'");
	break;
#endif
	return "";
      case UI_TYPE::WRAP:
	return "";
#ifdef USE_UI_TEXT
      case UI_TYPE::TEXT:
	return "txt";
#endif
#ifdef USE_UI_AATEXT
      case UI_TYPE::AATEXT:
#endif 
	return "txt";
#ifdef USE_UI_GTKMM
      case UI_TYPE::GTKMM_DOKO:
	return "png";
#endif // #ifdef UISE_UI_GTKMM
      } // switch(::ui->type())
    } // if (::ui)
    return "";
  case CARDSETS_DIRECTORY:
    return "cardsets";
  case CARDS_DIRECTORY:
    return "cards";
  case CARDS_BACK_DIRECTORY:
    return "backs";
  case ICONS_DIRECTORY:
    return "icons";
  case BACKGROUNDS_DIRECTORY:
    return "backgrounds";
  case SOUND_DIRECTORY:
    return "sounds";
  case AI_DIRECTORY:
    return "ai";
  case PARTIES_DIRECTORY:
    return "parties";
  case RULES_DIRECTORY:
    return "rules";
  case SETTINGS_DIRECTORY:
    return "settings";
  case HELP_DIRECTORY:
#ifdef RELEASE
    return "doc/manual";
#else
    return "../doc/manual";
#endif
  } // switch(type)

  return "";
} // string const Setting::value(TypeStringConst const type)

/**
 ** -> result
 **
 ** @param	type	setting type (only 'CARDS_ORDER')
 **
 ** @return	the value of the cards order
 ** 
 ** @author	Diether Knof
 **
 ** @version	0.7.0
 **/
CardsOrder const&
Setting::value(TypeCardsOrder const type) const
{
  return this->cards_order_p;
} // CardsOrder const& Setting::value(TypeCardsOrder const type) const

/**
 ** -> result
 **
 ** @param	type	setting type (only 'CARDS_ORDER')
 **
 ** @return	the value of the cards order
 ** 
 ** @author	Diether Knof
 **
 ** @version	0.7.0
 **/
CardsOrder&
Setting::value(TypeCardsOrder const type)
{
  return this->cards_order_p;
} // CardsOrder& Setting::value(TypeCardsOrder const type)

/**
 ** -> result
 **
 ** @param	type	setting type (Type Unsigned)
 **
 ** @return	the minimal value of the setting 'type'
 ** 
 ** @author	Diether Knof
 **
 ** @version	0.7.0
 **/
unsigned
Setting::min(TypeUnsigned const& type) const
{
  switch(type) {
  case TABLE_ROTATION:
    return 0;
  case CARDS_HEIGHT:
    return 2;
  default:
    return 0;
  } // switch(type)
} // unsigned Setting::min(TypeUnsigned const& type) const

/**
 ** -> result
 **
 ** @param	type	setting type (Type Unsigned)
 **
 ** @return	the maximal value of the setting 'type'
 ** 
 ** @author	Diether Knof
 **
 ** @version	0.7.0
 **/
unsigned
Setting::max(TypeUnsigned const& type) const
{
  switch(type) {
  case CARD_PLAY_DELAY:
    return 60000; // 60 seconds
  case FULL_TRICK_CLOSE_DELAY:
  case GAMETYPE_WINDOW_CLOSE_DELAY:
  case MARRIAGE_WINDOW_CLOSE_DELAY:
  case GENSCHER_WINDOW_CLOSE_DELAY:
  case ANNOUNCEMENT_WINDOW_CLOSE_DELAY:
  case SWINES_WINDOW_CLOSE_DELAY:
    return 60000; // 60 seconds
  case TABLE_ROTATION:
    return 3;
  case CARDS_HEIGHT:
    return 1000;
  } // switch(type)

  return 0;
} // unsigned Setting::max(TypeUnsigned const& type) const

/**
 ** sets the 'type' to 'value'
 **
 ** @param	type	setting type (Type Bool)
 ** @param	value	new value
 **
 ** @return	new value
 ** 
 ** @author	Diether Knof
 **
 ** @version	0.7.0
 **/
bool
Setting::set(const TypeBool type, bool const value)
{
  if (this->value(type) == value)
    return this->value(type);

  bool const old_value = this->bool_p[type - BOOL_FIRST];
  this->bool_p[type - BOOL_FIRST] = value;

  if ((ui != NULL)
      && (this == &::setting))
    ui->setting_update(type, &old_value);

  return this->value(type);
} // bool Setting::set(const TypeBool type, bool const value)

/**
 ** sets the 'type' to 'value'
 **
 ** @param	type	setting type (Type Bool)
 ** @param	value	new value (as string)
 **
 ** @return	new value
 ** 
 ** @author	Diether Knof
 **
 ** @version	0.7.0
 **/
bool
Setting::set(const TypeBool type, string const& value)
{
  if ((value != "true")
      && (value != "false")
      && (value != "yes")
      && (value != "no")
      && (value != "0")
      && (value != "1")) {
    cerr << "illegal value '" << value << "' for '" << type << "', "
      << "must be a boolean ('true' or 'false' or 'yes' or 'no' or '1' or '0'. "
      << "Taking 'false'."
      << endl;
  }

  return this->set(type, (((value == "false")
			   || (value == "no")
			   || (value == "0"))
			  ? false : true));
} // bool Setting::set(const TypeBool type, string const& value)

/**
 ** sets the 'type' to 'value'
 **
 ** @param	type	setting type (Type Unsigned)
 ** @param	value	new value
 **
 ** @return	new value
 ** 
 ** @author	Diether Knof
 **
 ** @version	0.7.0
 **/
unsigned
Setting::set(const TypeUnsigned type, unsigned const value)
{
  if (this->value(type) == value)
    return this->value(type);

  unsigned const old_value = this->unsigned_p[type - UNSIGNED_FIRST];
  this->unsigned_p[type - UNSIGNED_FIRST] = value;

  if ((ui != NULL)
      && (this == &::setting))
    ui->setting_update(type, &old_value);

  return this->value(type);
} // unsigned Setting::set(const TypeUnsigned type, unsigned const value)

/**
 ** sets the 'type' to 'value'
 **
 ** @param	type	setting type (Type Unsigned)
 ** @param	value	new value (as string)
 **
 ** @return	new value
 ** 
 ** @author	Diether Knof
 **
 ** @version	0.7.0
 **/
unsigned
Setting::set(const TypeUnsigned type, string const& value)
{
  char* end_ptr;
  unsigned number = strtoul(value.c_str(), &end_ptr, 0);
  if (*end_ptr != '\0') {
    cerr << "illegal value '" << value << "' for '" << type << "', "
      << "must be a digit. "
      << "Taking " << number << "."
      << endl;
  }

  return this->set(type, number);
} // unsigned Setting::set(const TypeUnsigned type, string const& value)

/**
 ** sets the 'type' to 'value'
 **
 ** @param	type	setting type (Type String)
 ** @param	value	new value
 **
 ** @return	new value
 ** 
 ** @author	Diether Knof
 **
 ** @version	0.7.0
 **/
string
Setting::set(TypeString const type, string const& value)
{
  if (this->value(type) == value)
    return this->value(type);

  string const old_value = this->string_p[type - STRING_FIRST];

  // First test, whether this is the default value.
  // If it is, then leave the value empty.
#ifdef POSTPHONED
  this->string_p[type - STRING_FIRST] = "";
#endif // #ifdef POSTPHONED 
  if ((*this)(type) != value)
    this->string_p[type - STRING_FIRST] = value;

  if (this == &::setting) {
    switch(type) {
    case NAME:
      break;
    case PUBLIC_DATA_DIRECTORY:
    case PRIVATE_DATA_DIRECTORY:
      ::setting_default.load((*this)(PUBLIC_DATA_DIRECTORY) + "/"
			     + (*this)(SETTINGS_DIRECTORY) + "/"
			     + "default",
			     false);

      Translator::dir_scan();
      ::translator.load();
      break;
    case SETTINGS_DIRECTORY:
      ::setting_default.load((*this)(PUBLIC_DATA_DIRECTORY) + "/"
			     + (*this)(SETTINGS_DIRECTORY) + "/"
			     + "default",
			     false);
      break;
    case LANGUAGES_DIRECTORY:
      Translator::dir_scan();
    case LANGUAGE:
      ::translator.load();
      break;
    case CARDSET:
      { // read the license
	vector<string> license_files;
	license_files.push_back("copyright");
	license_files.push_back("Copyright");
	license_files.push_back("COPYRIGHT");
	license_files.push_back("license");
	license_files.push_back("License");
	license_files.push_back("LICENSE");

	vector<string> cardsets_directory;
	cardsets_directory.push_back((*this)(PRIVATE_DATA_DIRECTORY) + "/"
				     + (*this)(CARDSETS_DIRECTORY));
	cardsets_directory.push_back((*this)(PUBLIC_DATA_DIRECTORY) + "/"
				     + (*this)(CARDSETS_DIRECTORY));
	cardsets_directory.push_back("./"
				     + (*this)(CARDSETS_DIRECTORY));
	cardsets_directory.push_back(::setting_default(PUBLIC_DATA_DIRECTORY) + "/"
				     + (*this)(CARDSETS_DIRECTORY));
	cardsets_directory.push_back(::setting_default(PUBLIC_DATA_DIRECTORY) + "/"
				     + ::setting_default(CARDSETS_DIRECTORY));

	string directory = this->value(CARDSET);

#ifdef POSTPHONED
	// The g++-2.95 does not understand this
	cardset_license.clear();
#else
	cardset_license = string();
#endif

	do { // while (directory != ".")
	  for (vector<string>::const_iterator cardsets_dir
	       = cardsets_directory.begin();
	       ((cardsets_dir != cardsets_directory.end())
		&& cardset_license.empty());
	       cardsets_dir++) {
	    for (vector<string>::const_iterator license
		 = license_files.begin();
		 ((license != license_files.end())
		  && cardset_license.empty());
		 license++) {
	      if (DK::Utils::File::isfile(*cardsets_dir + "/"
					  + directory + "/"
					  + *license)) {
		cardset_license = DK::Utils::String::getfile(*cardsets_dir + "/"
							     + directory + "/"
							     + *license);
	      } // if (license found)
	    } // for (license \in license_files)
	  } // for (cardsets_dir \in cardsets_directory)

	  if (cardset_license.empty()
	      && (directory == "."))
	    // no license found
	    cardset_license = "license not found :-(";

	  directory = DK::Utils::File::dirname(directory);

	} while (directory != ".");
      } // read the license

      { // update the cards back (if necessary)
	if (!DK::Utils::File::isfile((*this)(Setting::PRIVATE_DATA_DIRECTORY)
				     + (*this)(Setting::CARDSET)
				     + (*this)(Setting::CARDS_BACK)
				     + "."
				     + (*this)(Setting::GRAPHIC_EXTENSION))
	    && !::DK::Utils::File::isfile((*this)(Setting::PUBLIC_DATA_DIRECTORY)
					  + (*this)(Setting::CARDSET)
					  + (*this)(Setting::CARDS_BACK)
					  + "."
					  + (*this)(Setting::GRAPHIC_EXTENSION))
	   ) {
	  // search a back in the directory
	  DIR *dir = opendir(((*this)(Setting::PRIVATE_DATA_DIRECTORY)
			      + "/"
			      + (*this)(Setting::CARDS_BACK_DIRECTORY)
			     ).c_str());
	  string directory = ((*this)(Setting::PRIVATE_DATA_DIRECTORY)
			      + "/"
			      + (*this)(Setting::CARDS_BACK_DIRECTORY));

	  if (dir == NULL) {
	    dir = opendir(((*this)(Setting::PUBLIC_DATA_DIRECTORY)
			   + "/"
			   + (*this)(Setting::CARDS_BACK_DIRECTORY)
			  ).c_str());
	    directory = ((*this)(Setting::PUBLIC_DATA_DIRECTORY)
			 + "/"
			 + (*this)(Setting::CARDS_BACK_DIRECTORY));

	  } // if (dir == NULL)

	  if (dir != NULL) {
	    struct dirent *entry;

	    // search all entries in the directory
	    while ((entry = readdir(dir)) != NULL) {
	      if ((strcmp(entry->d_name, ".") == 0)
		  || (strcmp(entry->d_name, "..") == 0))
		continue;
	      if (DK::Utils::File::isfile(directory + "/" + entry->d_name)) {
		string const basename = DK::Utils::File::basename(entry->d_name);
		if ((basename.size()
		     > 1 + (*this)(Setting::GRAPHIC_EXTENSION).size())
		    && (string(basename,
			       basename.size()
			       - 1
			       - (*this)(Setting::GRAPHIC_EXTENSION).size(),
			       1 + (*this)(Setting::GRAPHIC_EXTENSION).size())
			== "." + (*this)(Setting::GRAPHIC_EXTENSION))
		   ) {
		  this->set(Setting::CARDS_BACK,
			    string(basename,
				   0,
				   basename.size()
				   - 1 - (*this)(Setting::GRAPHIC_EXTENSION).size()));
		  break;
		} // if (extension is right)
	      } // if (DK::Utils::File::isfile(entry->d_name))
	    } // while (entry != NULL) ;
	    closedir(dir);
	  } // if (dir != NULL)
	} // if (file of the back of the cards exists)
      } // update the cards back (if necessary)
      break;
    default:
      break;
    } // switch(type)

    if (ui != NULL)
      ui->setting_update(type, &old_value);
  } // if (this == &::setting)

  return this->value(type);
} // string Setting::set(const TypeString type, string const& value)

/**
 ** sets the 'type' to 'value'
 **
 ** @param	type	setting type (Type CardsOrder)
 ** @param	value	new value
 **
 ** @return	new value
 ** 
 ** @author	Diether Knof
 **
 ** @version	0.7.0
 **/
CardsOrder const&
Setting::set(const TypeCardsOrder type, CardsOrder const& value)
{
  if (this->value(type) == value) {
    return this->value(type);
  }

  CardsOrder const old_value = this->cards_order_p;

  // the following code keeps the sorting order when the cards are mixed,
  if (!value.sorted()) {
    this->cards_order_p.sorted_set(value.sorted());
  } else { // if !(!value.sorted())
    this->cards_order_p = value;

    if (this == &::setting) {
      if (game_status & GAMESTATUS::GAME)
	::party.game().players_hands_sort();

      if (ui != NULL)
	ui->setting_update(type, &old_value);
    } // if (this == &::setting)
  } // if !(!value.sorted())

  return this->value(type);
} // CardsOrder const& Setting::set(const TypeCardsOrder type, CardsOrder const& value)

/**
 ** sets the 'type' to 'value'
 **
 ** @param	type	setting type (Type CardsOrder)
 ** @param	value	new value (as string)
 **
 ** @return	new value
 ** 
 ** @author	Diether Knof
 **
 ** @version	0.7.0
 **/
CardsOrder const&
Setting::set(const TypeCardsOrder type, string const& value)
{
  return this->set(type, CardsOrder(value));
} // CardsOrder Setting::set(const TypeCardsOrder type, string const& value)

/**
 ** sets the 'type' to 'value'
 ** the parameters are strings
 **
 ** @param	type	name of the setting type
 ** @param	value	new value
 **
 ** @return	whether the type is found
 ** 
 ** @author	Diether Knof
 **
 ** @version	0.7.0
 **/
bool
Setting::set(string const& type, string const& value)
{
  for (int i = Setting::BOOL_FIRST; i <= Setting::BOOL_LAST; i++) {
    if ((type == ::name(Setting::TypeBool(i)))
	|| (type == ::translation(Setting::TypeBool(i)))) {
      this->set(Setting::TypeBool(i), value);
      return true;
    }
  }
  for (int i = Setting::UNSIGNED_FIRST; i <= Setting::UNSIGNED_LAST; i++) {
    if ((type == ::name(Setting::TypeUnsigned(i)))
	|| (type == ::translation(Setting::TypeUnsigned(i)))) {
      this->set(Setting::TypeUnsigned(i), value);
      return true;
    }
  }
  for (int i = Setting::STRING_FIRST; i <= Setting::STRING_LAST; i++) {
    if ((type == ::name(Setting::TypeString(i)))
	|| (type == ::translation(Setting::TypeString(i)))) {
      this->set(Setting::TypeString(i), value);
      return true;
    }
  }

  if ((type == ::name(Setting::CARDS_ORDER))
      || (type == ::translation(Setting::CARDS_ORDER))) {
    this->set(CARDS_ORDER, value);
    return true;
  }

  return false;
} // bool Setting::set(string const& type, string const& value)

/**
 ** load the settings from the default file
 **
 ** @param	-
 **
 ** @return	-
 **
 ** @author	Diether Knof
 **
 ** @version	0.7.0
 **/
void
Setting::load()
{
  this->load((*this)(PUBLIC_DATA_DIRECTORY) + "/" + this->value(SETTINGS_FILE),
	     false);
  this->load((*this)(SETTINGS_FILE), false);

  return ;
} // void Setting::load()

/**
 ** load the settings from the given file
 **
 ** @param	filename	file to load the settings from
 ** @param	filename_not_exists_output	whether to show an information
 **						if the file could not be opened
 **
 ** @return	-
 **
 ** @author	Diether Knof
 **
 ** @version	0.7.0
 **/
void
Setting::load(string const& filename, bool filename_not_exists_output)
{
  ifstream istr(filename.c_str());

  if (istr.fail()) {
    if (filename_not_exists_output)
      cerr << "Setting::load(" << filename << "):\n"
						  << "  Error while opening the file"
						    << endl;
    return ;
  }

  // load the settings
  while (istr.good()) {
    Config config;
    istr >> config;

    // finished with the config file
    if ((config.name == "") && (config.value == ""))
      break;

    if (config.separator) {
      // a setting
      if (!set(config.name, config.value)) {
	cerr << "setting file:	"
	  << "ignoring unknown setting '" << config.name << "'."
	  << endl;
      }
    } else { // if (config.separator)
      // a setting
      // if the value is in parentencies, remove both
      if (config.name == "!input") {
	// include the given file
	this->load((DK::Utils::File::dirname(filename) + "/"
		    + config.value));
      } else if (config.name == "!end") {
	// ignore the rest of the file
	break;
      } else if (config.name == "!stdout") {
	// output of the data to 'stdout'
	cout << config.value << endl;
      } else if (config.name == "!stderr") {
	// output of the data to 'stderr'
	cerr << config.value << endl;
      } else if (config.name == "") {
	cerr << "Setting file \'" << filename << "\':	"
	  << "Ignoring line \'" << config.value << "\'.\n";
      } else {
	cerr << "Setting file \'" << filename << "\':	"
	  << "Setting '" << config.name << "' unknown.\n"
	  << "Ignoring it.\n";
      } // if (config.name == .)
    } // config.separator

  } // while (istr.good())

  return ;
} // void Setting::load(string const& filename, bool filename_not_exists_output)

/**
 ** save the settings in the default file
 **
 ** @param	-
 **
 ** @return	whether the saving was successful
 **
 ** @author	Diether Knof
 **
 ** @version	0.7.0
 **/
bool
Setting::save() const
{
  bool const success = this->save((*this)(SETTINGS_FILE));

  if (!success)
    cerr << "Could not save the settings in '"
      << (*this)(SETTINGS_FILE)
      << "'" << endl;

  return success;
} // bool Setting::save() const

/**
 ** save the settings in the given file
 **
 ** @param	filename	file into which to save the settings
 **
 ** @return	whether the saving was successful
 **
 ** @author	Diether Knof
 **
 ** @version	0.7.0
 **/
bool
Setting::save(string const& filename) const
{
  ofstream ostr(filename.c_str());

  if (ostr.fail())
    return true;

  ostr << "#!FreeDoko -s\n"
    << "# FreeDoko settings file (version " << ::version << ")\n"
    << '\n';

  this->write(ostr);

  return !ostr.fail();
} // bool Setting::save(string const& filename)

/**
 ** updates all settings in the ui
 **
 ** @param	-
 **
 ** @return	-
 **
 ** @author	Diether Knof
 **
 ** @version	0.7.0
 **/
void
Setting::update_all()
{
  if (this == &::setting) {
    ::translator.load();

    int i;

    for (i = BOOL_FIRST; i <= BOOL_LAST; i++)
      ::ui->setting_update(i, &(this->value(TypeBool(i))));
    for (i = UNSIGNED_FIRST; i <= UNSIGNED_LAST; i++)
      ::ui->setting_update(i, &(this->value(TypeUnsigned(i))));
    for (i = STRING_FIRST; i <= STRING_LAST; i++)
      ::ui->setting_update(i, &(this->value(TypeString(i))));
    ::ui->setting_update(CARDS_ORDER, &(this->value(TypeCardsOrder(i))));
  } // if (this == &::setting)

  return ;
} // void Setting::update_all()

/**
 ** prints the settings in the output stream
 **
 ** @param	ostr	ouput stream
 **
 ** @return	output stream
 **
 ** @author	Diether Knof
 **
 ** @version	0.7.0
 **/
ostream&
Setting::write(ostream& ostr) const
{
    ostr << ::name(NAME) << " = "
    << this->value(NAME) << "\n"

    << ::name(LANGUAGE) << " = "
    << this->value(LANGUAGE) << "\n"

    << ::name(SOUND) << " = "
    << this->value(SOUND) << "\n"

    << ::name(BROWSER) << " = "
    << this->value(BROWSER) << "\n"

    << ::name(SHOW_BUG_REPORT_BUTTON_IN_GAME_FINISHED_WINDOW) << " = "
    << this->value(SHOW_BUG_REPORT_BUTTON_IN_GAME_FINISHED_WINDOW) << "\n"

    << ::name(SAVE_BUG_REPORTS_ON_DESKTOP) << " = "
    << this->value(SAVE_BUG_REPORTS_ON_DESKTOP) << "\n"

    << "\n"
    << "# information and delay\n"

    << ::name(CARD_PLAY_DELAY) << " = "
    << ((this->value(CARD_PLAY_DELAY) == UINT_MAX)
	? "-1"
	: DK::Utils::String::to_string(this->value(CARD_PLAY_DELAY)).c_str())
    << "\n"

    << ::name(AUTOMATIC_CARD_SUGGESTION) << " = "
    << this->value(AUTOMATIC_CARD_SUGGESTION) << "\n"

    << ::name(ANNOUNCE_SWINES_AUTOMATICALLY) << " = "
    << this->value(ANNOUNCE_SWINES_AUTOMATICALLY) << "\n"

    << ::name(SHOW_IF_VALID) << " = "
    << this->value(SHOW_IF_VALID) << "\n"

    << ::name(EMPHASIZE_VALID_CARDS) << " = "
    << this->value(EMPHASIZE_VALID_CARDS) << "\n"

    << ::name(ANNOUNCE_IN_TABLE) << " = "
    << this->value(ANNOUNCE_IN_TABLE) << "\n"

    << ::name(SHOW_FULL_TRICK_WINDOW) << " = "
    << this->value(SHOW_FULL_TRICK_WINDOW) << "\n"

    << ::name(SHOW_FULL_TRICK_WINDOW_IF_SPECIAL_POINTS) << " = "
    << this->value(SHOW_FULL_TRICK_WINDOW_IF_SPECIAL_POINTS) << "\n"

    << ::name(CLOSE_FULL_TRICK_AUTOMATICALLY) << " = "
    << this->value(CLOSE_FULL_TRICK_AUTOMATICALLY) << "\n"

    << ::name(FULL_TRICK_CLOSE_DELAY) << " = "
    << this->value(FULL_TRICK_CLOSE_DELAY) << "\n"


    << ::name(SHOW_GAMETYPE_WINDOW) << " = "
    << this->value(SHOW_GAMETYPE_WINDOW) << "\n"

    << ::name(CLOSE_GAMETYPE_WINDOW_AUTOMATICALLY) << " = "
    << this->value(CLOSE_GAMETYPE_WINDOW_AUTOMATICALLY) << "\n"

    << ::name(GAMETYPE_WINDOW_CLOSE_DELAY) << " = "
    << this->value(GAMETYPE_WINDOW_CLOSE_DELAY) << "\n"


    << ::name(SHOW_MARRIAGE_WINDOW) << " = "
    << this->value(SHOW_MARRIAGE_WINDOW) << "\n"

    << ::name(CLOSE_MARRIAGE_WINDOW_AUTOMATICALLY) << " = "
    << this->value(CLOSE_MARRIAGE_WINDOW_AUTOMATICALLY) << "\n"

    << ::name(MARRIAGE_WINDOW_CLOSE_DELAY) << " = "
    << this->value(MARRIAGE_WINDOW_CLOSE_DELAY) << "\n"


    << ::name(SHOW_GENSCHER_WINDOW) << " = "
    << this->value(SHOW_GENSCHER_WINDOW) << "\n"

    << ::name(CLOSE_GENSCHER_WINDOW_AUTOMATICALLY) << " = "
    << this->value(CLOSE_GENSCHER_WINDOW_AUTOMATICALLY) << "\n"

    << ::name(GENSCHER_WINDOW_CLOSE_DELAY) << " = "
    << this->value(GENSCHER_WINDOW_CLOSE_DELAY) << "\n"


    << ::name(SHOW_ANNOUNCEMENT_WINDOW) << " = "
    << this->value(SHOW_ANNOUNCEMENT_WINDOW) << "\n"

    << ::name(CLOSE_ANNOUNCEMENT_WINDOW_AUTOMATICALLY) << " = "
    << this->value(CLOSE_ANNOUNCEMENT_WINDOW_AUTOMATICALLY) << "\n"

    << ::name(ANNOUNCEMENT_WINDOW_CLOSE_DELAY) << " = "
    << this->value(ANNOUNCEMENT_WINDOW_CLOSE_DELAY) << "\n"


    << ::name(SHOW_SWINES_WINDOW) << " = "
    << this->value(SHOW_SWINES_WINDOW) << "\n"

    << ::name(CLOSE_SWINES_WINDOW_AUTOMATICALLY) << " = "
    << this->value(CLOSE_SWINES_WINDOW_AUTOMATICALLY) << "\n"

    << ::name(SWINES_WINDOW_CLOSE_DELAY) << " = "
    << this->value(SWINES_WINDOW_CLOSE_DELAY) << "\n"



    << ::name(SHOW_TRICKPILES_POINTS) << " = "
    << this->value(SHOW_TRICKPILES_POINTS) << "\n"

    << ::name(SHOW_KNOWN_TEAMS_IN_GAME) << " = "
    << this->value(SHOW_KNOWN_TEAMS_IN_GAME) << "\n"

    << ::name(SHOW_SOLOPLAYER_IN_GAME) << " = "
    << this->value(SHOW_SOLOPLAYER_IN_GAME) << "\n"

    << ::name(SHOW_ALL_HANDS) << " = "
    << this->value(SHOW_ALL_HANDS) << "\n"

    << ::name(SHOW_AI_INFORMATION_HANDS) << " = "
    << this->value(SHOW_AI_INFORMATION_HANDS) << "\n"

    << ::name(SHOW_AI_INFORMATION_TEAMS) << " = "
    << this->value(SHOW_AI_INFORMATION_TEAMS) << "\n"

    << "\n";

    // so the sorting is saved, even if the mixed modus is aktivated

    if (!this->value(CARDS_ORDER).sorted()) {
      CardsOrder cards_order_tmp(this->value(CARDS_ORDER));

      cards_order_tmp.sorted_set(true);

      ostr << ::name(CARDS_ORDER) << " = "
	<< cards_order_tmp << "\n";
    } // if (this->value(CARDS_ORDER).mixed())

    ostr << ::name(CARDS_ORDER) << " = "
      << this->value(CARDS_ORDER) << "\n";

    ostr << "# appearance\n"

      << "#   table\n"

      << ::name(OWN_HAND_ON_TABLE_BOTTOM) << " = "
      << this->value(OWN_HAND_ON_TABLE_BOTTOM) << "\n"

      << ::name(TABLE_ROTATION) << " = "
      << this->value(TABLE_ROTATION) << "\n"

      << ::name(ROTATE_TRICK_CARDS) << " = "
      << this->value(ROTATE_TRICK_CARDS) << "\n"

      << "#   cards\n"

      << ::name(ORIGINAL_CARDS_SIZE) << " = "
      << this->value(ORIGINAL_CARDS_SIZE) << "\n"

      << ::name(CARDS_HEIGHT) << " = "
      << this->value(CARDS_HEIGHT) << "\n"

      << "#   theme\n"

      << ::name(CARDSET) << " = "
      << this->value(CARDSET) << "\n"

      << ::name(CARDS_BACK) << " = "
      << this->value(CARDS_BACK) << "\n"

      << ::name(BACKGROUND) << " = "
      << this->value(BACKGROUND) << "\n"

      << "#   fonts and colors\n"

      << ::name(NAME_FONT) << " = "
      << this->value(NAME_FONT) << "\n"

      << ::name(NAME_FONT_COLOR) << " = "
      << this->value(NAME_FONT_COLOR) << "\n"

      << ::name(NAME_ACTIVE_FONT_COLOR) << " = "
      << this->value(NAME_ACTIVE_FONT_COLOR) << "\n"

      << ::name(TRICKPILE_POINTS_FONT) << " = "
      << this->value(TRICKPILE_POINTS_FONT) << "\n"

      << ::name(TRICKPILE_POINTS_FONT_COLOR) << " = "
      << this->value(TRICKPILE_POINTS_FONT_COLOR) << "\n"

      << ::name(POVERTY_SHIFT_ARROW_COLOR) << " = "
      << this->value(POVERTY_SHIFT_ARROW_COLOR) << "\n"

      << "#   splash screen\n"

      << ::name(SHOW_SPLASH_SCREEN) << " = "
      << this->value(SHOW_SPLASH_SCREEN) << "\n"

      << ::name(SPLASH_SCREEN_TRANSPARENT) << " = "
      << this->value(SPLASH_SCREEN_TRANSPARENT) << "\n";

    ostr << "\n";

    return ostr;
} // ostream& Setting::write(ostream& ostr) const

/**
 ** -> result
 **
 ** @return	type	the type (bool)
 **
 ** @return	name of the type
 **
 ** @author	Diether Knof
 **
 ** @version	0.7.0
 **/
string
name(Setting::TypeBool const& type)
{
  switch(type) {
  case Setting::SAVE_PARTY_CHANGES:
    return "save party changes";
  case Setting::SHOW_SPLASH_SCREEN:
    return "show splash screen";
  case Setting::SPLASH_SCREEN_TRANSPARENT:
    return "splash screen transparent";
  case Setting::SHOW_BUG_REPORT_BUTTON_IN_GAME_FINISHED_WINDOW:
    return "show bug report button in game finished window";
  case Setting::SAVE_BUG_REPORTS_ON_DESKTOP:
    return "save bug reports on desktop";
  case Setting::SOUND:
    return "sound";
  case Setting::AUTOMATIC_CARD_SUGGESTION:
    return "automatic card suggestion";
  case Setting::ANNOUNCE_SWINES_AUTOMATICALLY:
    return "announce swines automatically";
  case Setting::SHOW_IF_VALID:
    return "show if valid";
  case Setting::EMPHASIZE_VALID_CARDS:
    return "emphasize valid cards";
  case Setting::ANNOUNCE_IN_TABLE:
    return "announce in table";
  case Setting::SHOW_ALL_HANDS:
    return "show all hands";
  case Setting::SHOW_AI_INFORMATION_HANDS:
    return "show ai information hands";
  case Setting::SHOW_AI_INFORMATION_TEAMS:
    return "show ai information teams";
  case Setting::SHOW_TRICKPILES_POINTS:
    return "show trickpiles points";
  case Setting::SHOW_KNOWN_TEAMS_IN_GAME:
    return "show known teams in game";
  case Setting::SHOW_SOLOPLAYER_IN_GAME:
    return "show soloplayer in game";
  case Setting::SHOW_FULL_TRICK_WINDOW:
    return "show full trick window";
  case Setting::SHOW_FULL_TRICK_WINDOW_IF_SPECIAL_POINTS:
    return "show full trick window if special points";
  case Setting::CLOSE_FULL_TRICK_AUTOMATICALLY:
    return "close full trick automatically";
  case Setting::SHOW_GAMETYPE_WINDOW:
    return "show gametype window";
  case Setting::CLOSE_GAMETYPE_WINDOW_AUTOMATICALLY:
    return "close gametype window automatically";
  case Setting::SHOW_MARRIAGE_WINDOW:
    return "show marriage window";
  case Setting::CLOSE_MARRIAGE_WINDOW_AUTOMATICALLY:
    return "close marriage window automatically";
  case Setting::SHOW_GENSCHER_WINDOW:
    return "show genscher window";
  case Setting::CLOSE_GENSCHER_WINDOW_AUTOMATICALLY:
    return "close genscher window automatically";
  case Setting::SHOW_ANNOUNCEMENT_WINDOW:
    return "show announcement window";
  case Setting::CLOSE_ANNOUNCEMENT_WINDOW_AUTOMATICALLY:
    return "close announcement window automatically";
  case Setting::SHOW_SWINES_WINDOW:
    return "show swines window";
  case Setting::CLOSE_SWINES_WINDOW_AUTOMATICALLY:
    return "close swines window automatically";
  case Setting::ROTATE_TRICK_CARDS:
    return "rotate trick cards";
  case Setting::OWN_HAND_ON_TABLE_BOTTOM:
    return "own hand on table bottom";
  case Setting::ORIGINAL_CARDS_SIZE:
    return "original cards size";
  } // switch(type)

  return "";
} // string name(Setting::TypeBool const& type)

/**
 ** -> result
 **
 ** @return	type	the type (unsigned)
 **
 ** @return	name of the type
 **
 ** @author	Diether Knof
 **
 ** @version	0.7.0
 **/
string
name(Setting::TypeUnsigned const& type)
{
  switch(type) {
  case Setting::CARD_PLAY_DELAY:
    return "card play delay";
  case Setting::FULL_TRICK_CLOSE_DELAY:
    return "full trick close delay";
  case Setting::GAMETYPE_WINDOW_CLOSE_DELAY:
    return "gametype window close delay";
  case Setting::MARRIAGE_WINDOW_CLOSE_DELAY:
    return "marriage window close delay";
  case Setting::GENSCHER_WINDOW_CLOSE_DELAY:
    return "genscher window close delay";
  case Setting::ANNOUNCEMENT_WINDOW_CLOSE_DELAY:
    return "announcement window close delay";
  case Setting::SWINES_WINDOW_CLOSE_DELAY:
    return "swines window close delay";
  case Setting::TABLE_ROTATION:
    return "table rotation";
  case Setting::CARDS_HEIGHT:
    return "cards height";
  } // switch(type)

  return "";
} // string name(Setting::TypeUnsigned const& type)

/**
 ** -> result
 **
 ** @return	type	the type (string)
 **
 ** @return	name of the type
 **
 ** @author	Diether Knof
 **
 ** @version	0.7.0
 **/
string
name(Setting::TypeString const& type)
{
  switch(type) {
  case Setting::NAME:
    return "name";
  case Setting::LANGUAGE:
    return "language";
  case Setting::CARDSET:
    return "cardset";
  case Setting::CARDS_BACK:
    return "cards back";
  case Setting::BACKGROUND:
    return "background";
  case Setting::NAME_FONT:
    return "name font";
  case Setting::NAME_FONT_COLOR:
    return "name font color";
  case Setting::NAME_ACTIVE_FONT_COLOR:
    return "name active font color";
  case Setting::TRICKPILE_POINTS_FONT:
    return "trickpile points font";
  case Setting::TRICKPILE_POINTS_FONT_COLOR:
    return "trickpile points font color";
  case Setting::POVERTY_SHIFT_ARROW_COLOR:
    return "poverty shift arrow color";
  case Setting::BROWSER:
    return "browser";
  } // switch(type)

  return "";
} // string name(Setting::TypeString const& type)

/**
 ** -> result
 **
 ** @return	type	the type (string const)
 **
 ** @return	name of the type
 **
 ** @author	Diether Knof
 **
 ** @version	0.7.0
 **/
string
name(Setting::TypeStringConst const& type)
{
  switch(type) {
  case Setting::PUBLIC_DATA_DIRECTORY:
    return "public data directory";
  case Setting::PRIVATE_DATA_DIRECTORY:
    return "private data directory";
  case Setting::SETTINGS_FILE:
    return "settings file";
  case Setting::LANGUAGES_DIRECTORY:
    return "languages directory";
  case Setting::LANGUAGE_FILE:
    return "language file";
  case Setting::GRAPHIC_EXTENSION:
    return "graphic extension";
  case Setting::CARDSETS_DIRECTORY:
    return "cardsets directory";
  case Setting::CARDS_DIRECTORY:
    return "cards directory";
  case Setting::CARDS_BACK_DIRECTORY:
    return "cards back directory";
  case Setting::ICONS_DIRECTORY:
    return "icons directory";
  case Setting::BACKGROUNDS_DIRECTORY:
    return "backgrounds directory";
  case Setting::SOUND_DIRECTORY:
    return "sound directory";
  case Setting::AI_DIRECTORY:
    return "ai directory";
  case Setting::PARTIES_DIRECTORY:
    return "parties directory";
  case Setting::RULES_DIRECTORY:
    return "rules directory";
  case Setting::SETTINGS_DIRECTORY:
    return "settings directory";
  case Setting::HELP_DIRECTORY:
    return "help directory";
  } // switch(type)

  return "";
} // string name(Setting::TypeStringConst const& type)

/**
 ** -> result
 **
 ** @return	type	the type (cards order)
 **
 ** @return	name of the type
 **
 ** @author	Diether Knof
 **
 ** @version	0.7.0
 **/
string
name(Setting::TypeCardsOrder const& type)
{
  switch(type) {
  case Setting::CARDS_ORDER:
    return "cards order";
  } // switch(type)

  return "";
} // string name(Setting::TypeCardsOrder const& type)

#if 0
/**********************************************************************
 *
 ** operator<<(ostream& ostr, Setting::TypeBool const& type)
 *
 ** Parameters:	ostr - ouput stream
 *		type - the type
 *
 ** Result:	output stream
 *
 ** Version:	0.4.1
 *
 ** Description:	prints the name of the type in the ouput stream
 *
 **********************************************************************/
ostream&
operator<<(ostream& ostr, Setting::TypeBool const& type)
{
  DEBUG_CALLING(INFO_SETTING && INFO_IO,
		"operator<<(ostream, Setting::TypeBool)");

  ostr << name(type);

  DEBUG_RETURNING(ostr,
		  INFO_SETTING && INFO_IO,
		  "operator<<(ostream, Setting::TypeBool)");
} // ostream& operator<<(ostream& ostr, Setting::TypeBool const& type)

/**********************************************************************
 *
 ** operator<<(ostream& ostr, Setting::TypeUnsigned const& type)
 *
 ** Parameters:	ostr - ouput stream
 *		type - the type
 *
 ** Result:	output stream
 *
 ** Version:	0.4.1
 *
 ** Description:	prints the name of the type in the ouput stream
 *
 **********************************************************************/
ostream&
operator<<(ostream& ostr, Setting::TypeUnsigned const& type)
{
  DEBUG_CALLING(INFO_SETTING && INFO_IO,
		"operator<<(ostream, Setting::TypeUnsigned)");

  ostr << name(type);

  DEBUG_RETURNING(ostr,
		  INFO_SETTING && INFO_IO,
		  "operator<<(ostream, Setting::TypeUnsigned)");
} // ostream& operator<<(ostream& ostr, Setting::TypeUnsigned const& type)

/**********************************************************************
 *
 ** operator<<(ostream& ostr, Setting::TypeString const& type)
 *
 ** Parameters:	ostr - ouput stream
 *		type - the type
 *
 ** Result:	output stream
 *
 ** Version:	0.4.1
 *
 ** Description:	prints the name of the type in the ouput stream
 *
 **********************************************************************/
ostream&
operator<<(ostream& ostr, Setting::TypeString const& type)
{
  DEBUG_CALLING(INFO_SETTING && INFO_IO,
		"operator<<(ostream, Setting::TypeString)");

  ostr << name(type);

  DEBUG_RETURNING(ostr,
		  INFO_SETTING && INFO_IO,
		  "operator<<(ostream, Setting::TypeString)");
} // ostream& operator<<(ostream& ostr, Setting::TypeString const& type)

/**********************************************************************
 *
 ** operator<<(ostream& ostr, Setting::TypeStringConst const& type)
 *
 ** Parameters:	ostr - ouput stream
 *		type - the type
 *
 ** Result:	output stream
 *
 ** Version:	0.4.3
 *
 ** Description:	prints the name of the type in the ouput stream
 *
 **********************************************************************/
ostream&
operator<<(ostream& ostr, Setting::TypeStringConst const& type)
{
  DEBUG_CALLING(INFO_SETTING && INFO_IO,
		"operator<<(ostream, Setting::TypeStringConst)");

  ostr << name(type);

  DEBUG_RETURNING(ostr,
		  INFO_SETTING && INFO_IO,
		  "operator<<(ostream, Setting::TypeStringConst)");
} // ostream& operator<<(ostream& ostr, Setting::TypeStringConst const& type)

/**********************************************************************
 *
 ** operator<<(ostream& ostr, Setting::TypeCardsOrder const& type)
 *
 ** Parameters:	ostr - ouput stream
 *		type - the type
 *
 ** Result:	output stream
 *
 ** Version:	0.4.1
 *
 ** Description:	prints the name of the type in the ouput stream
 *
 **********************************************************************/
ostream&
operator<<(ostream& ostr, Setting::TypeCardsOrder const& type)
{
  DEBUG_CALLING(INFO_SETTING && INFO_IO,
		"operator<<(ostream, Setting::TypeCardsOrder)");

  ostr << name(type);

  DEBUG_RETURNING(ostr,
		  INFO_SETTING && INFO_IO,
		  "operator<<(ostream, Setting::TypeCardsOrder)");
} // ostream& operator<<(ostream& ostr, Setting::TypeCardsOrder const& type)
#endif

/**
 ** write the setting in the output stream
 **
 ** @param	ostr	output stream
 ** @param	setting	setting to write
 **
 ** @return	output stream
 **
 ** @author	Diether Knof
 **
 ** @version	0.7.0
 **/
ostream&
operator<<(ostream& ostr, Setting const& setting)
{
  setting.write(ostr);

  return ostr;
} // ostream& operator<<(ostream& ostr, Setting const& setting)

/**
 ** -> result
 **
 ** @param	setting1	first setting that is compared
 ** @param	setting2	second setting that is compared
 **
 ** @return	whether the two settings are equal (according to value)
 **
 ** @author	Diether Knof
 **
 ** @version	0.6.6
 **/
bool
operator==(Setting const& setting1, Setting const& setting2)
{
  for (int i = Setting::BOOL_FIRST; i <= Setting::BOOL_LAST; ++i)
    if (setting1.value(static_cast<Setting::TypeBool>(i))
	!= setting2.value(static_cast<Setting::TypeBool>(i)))
      return false;

  for (int i = Setting::UNSIGNED_FIRST; i <= Setting::UNSIGNED_LAST; ++i)
    if (setting1.value(static_cast<Setting::TypeUnsigned>(i))
	!= setting2.value(static_cast<Setting::TypeUnsigned>(i)))
      return false;

  for (int i = Setting::STRING_FIRST; i <= Setting::STRING_LAST; ++i)
    if (setting1.value(static_cast<Setting::TypeString>(i))
	!= setting2.value(static_cast<Setting::TypeString>(i)))
      return false;

  if (setting1.value(Setting::CARDS_ORDER)
      != setting2.value(Setting::CARDS_ORDER))
    return false;

  return true;
} // bool operator==(Setting const& setting1, Setting const& setting2)

/**
 ** -> result
 **
 ** @param	setting1	first setting that is compared
 ** @param	setting2	second setting that is compared
 **
 ** @return	whether the two settings are different (according to value)
 **
 ** @author	Diether Knof
 **
 ** @version	0.6.6
 **/
bool
operator!=(Setting const& setting1, Setting const& setting2)
{
  return !(setting1 == setting2);
} // bool operator!=(Setting const& setting1, Setting const& setting2)
