/**********************************************************************
 *
 *   FreeDoko a Doppelkopf-Game
 * 
 *   Copyright (C) 2001-2010  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 "setting.h"
#include "setting.cardsorder.h"
#include "setting.theme.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 "../game/game.h"
#include "../player/human/human.h"

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

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

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


// the date of the exipration of the Altenburg cardset
DK::Utils::Date const Setting::ALTENBURG_EXPIRATION_DATE(2011, 12, 31);
// the date of the exipration of the InnoCard cardset
DK::Utils::Date const Setting::INNOCARD_EXPIRATION_DATE(2009, 12, 31);
// the date of the exipration of the Elite cardset
DK::Utils::Date const Setting::ELITE_EXPIRATION_DATE(2009, 12, 31);


// 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);

/**
 ** constructor
 ** 
 ** @param     -
 **
 ** @return    -
 **
 ** @author    Diether Knof
 **
 ** @version   0.7.4
 **/
Setting::Setting() :
  bool_(BOOL_NUMBER),
  unsigned_(UNSIGNED_NUMBER),
  string_(STRING_NUMBER, ""),
  cardset_license_(""),
  cards_order_(new CardsOrder),
  data_directories_(),
  string_path_(STRING_NUMBER, ""),
  themes_()
{
  this->set_data_directories();
  this->set_to_hardcoded();
  this->create_themes_list();

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

  return ;
} // Setting::Setting()

/**
 ** copy constructor
 ** 
 ** @param     setting   setting to copy
 **
 ** @return    -
 **
 ** @author    Diether Knof
 **
 ** @version   0.7.4
 **/
Setting::Setting(Setting const& setting):
  bool_(setting.bool_),
  unsigned_(setting.unsigned_),
  string_(setting.string_),
  cardset_license_(setting.cardset_license_),
  cards_order_(new CardsOrder(*setting.cards_order_)),
  data_directories_(setting.data_directories_),
  string_path_(setting.string_path_),
  themes_()
{
  for (list<Theme*>::const_iterator t = setting.themes().begin();
       t != setting.themes().end();
       ++t)
    this->themes_.push_back(new Theme(**t));

  this->update_all();

  return ;
} // Setting::Setting(Setting setting)

/**
 ** copy operator
 ** 
 ** @param     setting   setting to copy
 **
 ** @return    this
 **
 ** @author    Diether Knof
 **
 ** @version   0.7.4
 **/
Setting&
Setting::operator=(Setting const& setting)
{
  this->bool_ = setting.bool_;
  this->unsigned_ = setting.unsigned_;
  this->string_ = setting.string_;
  this->cardset_license_ = setting.cardset_license_;
  *this->cards_order_ = *setting.cards_order_;
  this->data_directories_ = setting.data_directories_;
  this->string_path_ = setting.string_path_;
  this->clear_themes_list();
  for (list<Theme*>::const_iterator t = setting.themes().begin();
       t != setting.themes().end();
       ++t)
    this->themes_.push_back(new Theme(**t));

  return *this;
} // bool Setting::operator=(Setting setting) const

/**
 ** destructor
 ** 
 ** @param     -
 **
 ** @return    -
 **
 ** @author    Diether Knof
 **
 ** @version   0.7.4
 **/
Setting::~Setting()
{
  delete this->cards_order_;
  this->clear_themes_list();
  return ;
} // Setting::Setting()

/**
 ** set the values to the hardcoded
 ** 
 ** @param     -
 **
 ** @return    -
 **
 ** @author    Diether Knof
 **
 ** @version   0.7.4
 **/
void
Setting::set_to_hardcoded()
{
#if 0
  this->set(PUBLIC_DATA_DIRECTORY,	"");
  this->set(PRIVATE_DATA_DIRECTORY,	"");
  this->set(SETTINGS_FILE,		"FreeDokorc");
  this->set(LOGO_FILE,                  "logo.png");
  this->set(ICON_FILE,                  "icon.png");
  this->set(LANGUAGES_DIRECTORY,	"translations");
  this->set(LANGUAGE_FILE,		"text");
  this->set(GRAPHIC_EXTENSION,		"png");
  this->set(SOUND_EXTENSION,		"wav");
  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(SOUNDS_DIRECTORY,		"sound");
  this->set(AI_DIRECTORY,		"ai");
  this->set(PARTIES_DIRECTORY,		"rules");
  this->set(RULES_DIRECTORY,		"rules");
  this->set(SETTINGS_DIRECTORY,		"settings");
  this->set(MANUAL_DIRECTORY,		"/usr/share/doc/manual");
#endif

  this->set(AUTOMATIC_SAVINGS,          true);
  this->set(SAVE_PARTY_CHANGES,		true);


  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(NETWORK_CONNECTIONS_URGENCY_HINT,		true);
  this->set(NETWORK_CHAT_URGENCY_HINT,			true);

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


#ifdef USE_THREADS
  this->set(THREADS_MAX,	       		1);
#endif
  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");
  { // set the cardset
    list<string> cardsets;
    if ((*this)(LANGUAGE) == "de") {
      if (DK::Utils::Date() <= Setting::ALTENBURG_EXPIRATION_DATE)
        cardsets.push_back("Altenburg/french");
      cardsets.push_back("xskat/french");
      if (DK::Utils::Date() <= Setting::ALTENBURG_EXPIRATION_DATE)
        cardsets.push_back("Altenburg/german");
      cardsets.push_back("xskat/german");
    } else if ((*this)(LANGUAGE) == "de-alt") {
      if (DK::Utils::Date() <= Setting::ALTENBURG_EXPIRATION_DATE)
        cardsets.push_back("Altenburg/german");
      cardsets.push_back("xskat/german");
    } else { // english and so
      if (DK::Utils::Date() <= Setting::ALTENBURG_EXPIRATION_DATE)
        cardsets.push_back("Altenburg/english");
      if (DK::Utils::Date() <= Setting::INNOCARD_EXPIRATION_DATE)
        cardsets.push_back("InnoCard");
      if (DK::Utils::Date() <= Setting::ELITE_EXPIRATION_DATE)
        cardsets.push_back("Elite");
      cardsets.push_back("dondorf");
    } // if (language == )
    if (DK::Utils::Date() <= Setting::ALTENBURG_EXPIRATION_DATE)
      cardsets.push_back("Altenburg/french");
    cardsets.push_back("xskat/french");
    if (DK::Utils::Date() <= Setting::INNOCARD_EXPIRATION_DATE)
      cardsets.push_back("InnoCard");
    if (DK::Utils::Date() <= Setting::ELITE_EXPIRATION_DATE)
      cardsets.push_back("Elite");
    cardsets.push_back("dondorf");
    cardsets.push_back("kdecarddecks/spaced");
    cardsets.push_back("pysol/gpl");
    cardsets.push_back("pysol/a-m/gpl");
    cardsets.push_back("openclipart");

    list<string>::const_iterator cardset;
    for (cardset = cardsets.begin();
         cardset != cardsets.end();
         ++cardset) {
      this->set(CARDSET, *cardset);
      if (!this->path(CARDSET).empty())
        break;
    } // for (cardset \in cardsets)

    if (cardset == cardsets.end()) {
      this->set(CARDSET, "");
      if (::ui)
        ::ui->error(::translation("Error::loading default cardset %scardset%",
                                  cardsets.front()
                                 ).translation());
    } else {
      this->set(CARDSET, *cardset);
    }
  } // set the cardset
  { // set the cards back
    list<string> backs;

    backs.push_back("penguin");
    backs.push_back("back");

    list<string>::const_iterator back;
    for (back = backs.begin();
         back != backs.end();
         ++back) {
      this->set(CARDS_BACK, *back);
      if (!this->path(CARDS_BACK).empty())
        break;
    } // for (back \in backs)

    if (back == backs.end()) {
      this->set(CARDS_BACK, "");
      if (::ui)
        ::ui->error(::translation("Error::loading default cards back %sback% (%scardset%)",
                                  backs.front(),
                                  this->value(CARDSET)
                                 ).translation());
    } else {
      this->set(CARDS_BACK, *back);
    }
  } // set the cards back
  { // set the background
    list<string> backgrounds;

    backgrounds.push_back("table");

    list<string>::const_iterator background;
    for (background = backgrounds.begin();
         background != backgrounds.end();
         ++background) {
      this->set(BACKGROUND, *background);
      if (!this->path(BACKGROUND).empty())
        break;
    } // for (background \in backgrounds)

    if (background == backgrounds.end()) {
      this->set(BACKGROUND, "");
      if (::ui)
        ::ui->error(::translation("Error::loading default background %sbackground%",
                                  backgrounds.front()
                                 ).translation());
    } else {
      this->set(BACKGROUND, *background);
    }
  } // set the background


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

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

#ifdef USE_SOUND_COMMAND
  this->set(PLAY_SOUND_COMMAND,		"");
#endif
  this->set(BROWSER_COMMAND,		"");

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

/**
 ** -> result
 **
 ** @param	-
 **
 ** @return	a vector with all data directories
 **
 ** @author	Diether Knof
 **
 ** @version	0.6.3
 **/
void
Setting::set_data_directories()
{
  // search the directory
  this->data_directories_.clear();
  if (getenv("FREEDOKO_DATA_DIRECTORY"))
    this->data_directories_.push_back(getenv("FREEDOKO_DATA_DIRECTORY"));
  if (getenv("FREEDOKO_MORE_DATA_DIRECTORY"))
    this->data_directories_.push_back(getenv("FREEDOKO_MORE_DATA_DIRECTORY"));
  this->data_directories_.push_back(this->value(PRIVATE_DATA_DIRECTORY));


#ifdef PUBLIC_DATA_DIRECTORY_VALUE
  this->data_directories_.push_back(PUBLIC_DATA_DIRECTORY_VALUE);
#else // !#ifdef PUBLIC_DATA_DIRECTORY_VALUE

#ifdef RELEASE

#ifdef WINDOWS
  this->data_directories_.push_back(DK::Utils::Windows::Reg_read(HKEY_CURRENT_USER,
                                                                 "Software\\FreeDoko",
                                                                 "Directory"));
  if (this->data_directories_.back().empty())
    this->data_directories_.pop_back();
  this->data_directories_.push_back(DK::Utils::Windows::Reg_read(HKEY_LOCAL_MACHINE,
                                                                 "Software\\FreeDoko",
                                                                 "Directory"));
  if (this->data_directories_.back().empty())
    this->data_directories_.pop_back();
#endif // #ifdef WINDOWS

#else // !#ifdef RELEASE
  this->data_directories_.push_back("../data");
#endif // !#ifdef RELEASE

#endif // !#ifdef PUBLIC_DATA_DIRECTORY_VALUE

  this->data_directories_.push_back(".");


  // make each name unique
  for (list<string>::iterator d = this->data_directories_.begin();
       d != this->data_directories_.end();
      )
    if (std::find(this->data_directories_.begin(), d, *d) != d)
      d = this->data_directories_.erase(d);
    else
      ++d;


  return ;
} // Setting::set_data_directories()

/**
 ** -> result
 **
 ** @param	type	setting type
 **
 ** @return	the setting 'type'
 **
 ** @author	Diether Knof
 **
 ** @version	0.7.4
 **/
bool
Setting::operator()(TypeBool const type) const
{
  if ((FAST_PLAY & FAST_NS::SHOW_ALL_HANDS)
      && (type == Setting::SHOW_ALL_HANDS))
    return true;

  return (this->dependencies(type)
          && this->value(type));
} // bool Setting::operator()(TypeBool type) const

/**
 ** -> result
 **
 ** @param	type	setting type
 **
 ** @return	the setting 'type'
 **
 ** @author	Diether Knof
 **
 ** @version	0.7.4
 **/
unsigned
Setting::operator()(TypeUnsigned const type) const
{
  return this->value(type);
} // unsigned Setting::operator()(TypeUnsigned type) const

/**
 ** -> result
 **
 ** @param	type	setting type
 **
 ** @return	the setting 'type'
 **
 ** @author	Diether Knof
 **
 ** @version	0.6.3
 **/
string
Setting::operator()(TypeString const type) const
{
  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
      {
    	  TCHAR  infoBuf[1001];
    	  infoBuf[1000] = 0;
     	  DWORD  bufCharCount =1000;
     	  if( !GetUserName( infoBuf, &bufCharCount ))
        	  value = "Player";
     	  else
       	    value = infoBuf;
      }
#ifdef OUTDATED
      // 2010-01-24
      // *** 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");
#endif
#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_CURRENT_USER,
                                           "Software\\FreeDoko",
                                           "Language");
      if (value.empty())
        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/french";
      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 NAME_RESERVATION_FONT_COLOR:
      value = "blue";
      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;
#ifdef USE_SOUND_COMMAND
    case PLAY_SOUND_COMMAND:
#ifdef WINDOWS
#ifdef USE_REGISTRY
      { // Look in the registry for the default program for wav files
        string class_str
          = DK::Utils::Windows::Reg_read(HKEY_CURRENT_USER,
                                         "Software\\CLASSES\\.wav",
                                         "");
        if (class_str.empty())
          class_str = DK::Utils::Windows::Reg_read(HKEY_LOCAL_MACHINE,
                                                   "Software\\CLASSES\\.wav",
                                                   "");
        if (!class_str.empty()) {
          value = DK::Utils::Windows::Reg_read(HKEY_CURRENT_USER,
                                               "Software\\CLASSES\\" + class_str
                                               + "\\shell\\open\\command",
                                               "");
          if (value.empty())
            value = DK::Utils::Windows::Reg_read(HKEY_LOCAL_MACHINE,
                                                 "Software\\CLASSES\\" + class_str
                                                 + "\\shell\\open\\command",
                                                 "");
          if (   (value.size() >= 5)  
              && string(value, value.size() - 4, std::string::npos) == "\"\%1\"")
            value = string(value, 0, value.size() - 4);
        } // if (!class_str.empty())
      } // Look in the registry for the default program for wav files
#else
#endif
      if (value.empty())
        value = "explorer";
#else // #ifdef WINDOWS
      value = "aplay";
#endif // #ifdef WINDOWS
      break;
#endif // #ifdef USE_SOUND_COMMAND

    case BROWSER_COMMAND:
#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
        list<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 (list<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
#ifdef USE_REGISTRY
      { // Look in the registry for the default browser for html
        string class_str
          = DK::Utils::Windows::Reg_read(HKEY_CURRENT_USER,
                                         "Software\\CLASSES\\.html",
                                         "");
        if (class_str.empty())
          class_str = DK::Utils::Windows::Reg_read(HKEY_LOCAL_MACHINE,
                                                   "Software\\CLASSES\\.html",
                                                   "");
        if (!class_str.empty()) {
          value = DK::Utils::Windows::Reg_read(HKEY_CURRENT_USER,
                                               "Software\\CLASSES\\" + class_str
                                               + "\\shell\\open\\command",
                                               "");
          if (value.empty())
            value = DK::Utils::Windows::Reg_read(HKEY_LOCAL_MACHINE,
                                                 "Software\\CLASSES\\" + class_str
                                                 + "\\shell\\open\\command",
                                                 "");
          if (   (value.size() >= 5)  
              && string(value, value.size() - 4, std::string::npos) == "\"\%1\"")
            value = string(value, 0, value.size() - 4);
        } // if (!class_str.empty())
      } // Look in the registry for the default browser for html
#else
#endif
      if (value.empty())
        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 NAME_RESERVATION_FONT_COLOR:
  case TRICKPILE_POINTS_FONT:
  case TRICKPILE_POINTS_FONT_COLOR:
  case POVERTY_SHIFT_ARROW_COLOR:
#ifdef USE_SOUND_COMMAND
  case PLAY_SOUND_COMMAND:
#endif
  case BROWSER_COMMAND:
    break;
  } // switch(type)

  return value;
} // string Setting::operator()(TypeString type) const

/**
 ** -> result
 **
 ** @param     type   setting type
 **
 ** @return    value of setting 'type'
 **
 ** @author    Diether Knof
 **
 ** @version   0.7.4
 **/
string
Setting::operator()(TypeStringConst const type) const
{
  switch(type) {
  case CARDSET_LICENSE:
    return this->value(CARDSET_LICENSE);
  case PUBLIC_DATA_DIRECTORY:
    return DK::Utils::File::filename_expand(this->value(PUBLIC_DATA_DIRECTORY));
  case PRIVATE_DATA_DIRECTORY:
    return DK::Utils::File::filename_expand(this->value(PRIVATE_DATA_DIRECTORY));
  case SETTINGS_FILE:
    return ((*this)(PRIVATE_DATA_DIRECTORY)
            + "/" + this->value(type));
  case LOGO_FILE:
    return ((*this)(PUBLIC_DATA_DIRECTORY)
            + this->value(type));
  case ICON_FILE:
    return ((*this)(PUBLIC_DATA_DIRECTORY)
            + this->value(type));
  case LANGUAGES_DIRECTORY:
    return this->value(type);
  case LANGUAGE_FILE:
    return ((*this)(LANGUAGES_DIRECTORY) + "/"
            + (*this)(LANGUAGE) + "/"
            + this->value(type));
  case GRAPHIC_EXTENSION:
    return this->value(type);
  case SOUND_EXTENSION:
    return this->value(type);
  case CARDSETS_DIRECTORY:
    return this->value(type);
  case CARDS_DIRECTORY:
    return ((*this)(CARDSET) + "/"
            + this->value(type));
  case CARDS_BACK_DIRECTORY:
    return ((*this)(CARDSET) + "/"
            + this->value(type));
  case ICONS_DIRECTORY:
    return ((*this)(CARDSET) + "/"
            + this->value(type));
  case BACKGROUNDS_DIRECTORY:
    return this->value(type);
  case SOUNDS_DIRECTORY:
    return (this->value(type) + "/" + ::translator.token());
  case AI_DIRECTORY:
    return this->value(type);
  case PARTIES_DIRECTORY:
    return this->value(type);
  case RULES_DIRECTORY:
    return this->value(type);
  case SETTINGS_DIRECTORY:
    return this->value(type);
  case MANUAL_DIRECTORY:
    return this->value(type);
  } // switch(type)

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

/**
 ** -> result
 **
 ** @param     type   cards order
 **
 ** @return    the cards order
 **
 ** @author    Diether Knof
 **
 ** @version   0.7.4
 **/
Setting::CardsOrder const&
Setting::operator()(TypeCardsOrder type) const
{
  return this->value(type);
} // CardsOrder Setting::operator()(TypeCardsOrder type) const

/**
 ** -> result
 **
 ** @param     type   cards order
 **
 ** @return    the cards order
 **
 ** @author    Diether Knof
 **
 ** @version   0.7.4
 **/
Setting::CardsOrder&
Setting::operator()(TypeCardsOrder const type)
{
  return this->value(type);
} // CardsOrder& Setting::operator()(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
{
  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	type   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 AUTOMATIC_SAVINGS:
    return true;
  case SAVE_PARTY_CHANGES:
    return (*this)(AUTOMATIC_SAVINGS);
  case SHOW_SPLASH_SCREEN:
    return true;
  case SPLASH_SCREEN_TRANSPARENT:
    return (*this)(SHOW_SPLASH_SCREEN);
  case SHOW_BUG_REPORT_BUTTON_IN_GAME_FINISHED_WINDOW:
  case SAVE_BUG_REPORTS_ON_DESKTOP:
  case SOUND:
  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);
  case SHOW_FULL_TRICK_WINDOW:
  case CLOSE_FULL_TRICK_AUTOMATICALLY:
  case SHOW_GAMETYPE_WINDOW:
  case SHOW_MARRIAGE_WINDOW:
  case SHOW_GENSCHER_WINDOW:
  case SHOW_ANNOUNCEMENT_WINDOW:
  case SHOW_SWINES_WINDOW:
  case NETWORK_CONNECTIONS_URGENCY_HINT:
  case NETWORK_CHAT_URGENCY_HINT:
  case ROTATE_TRICK_CARDS:
  case OWN_HAND_ON_TABLE_BOTTOM:
  case ORIGINAL_CARDS_SIZE:
    return true;
  } // switch(type)

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

/**
 ** -> result
 **
 ** @param	type   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	type   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 POSTPONED
  // *** DK
  // else there is a compiler warning: returning reference to temporary
  static bool value = false;
  value = this->bool_[type - BOOL_FIRST];
  return value;
#else // #ifndef POSTPONED
  return this->bool_[type - BOOL_FIRST];
#endif // #ifndef POSTPONED
} // 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_[type - UNSIGNED_FIRST];
} // unsigned const& Setting::value(const TypeUnsigned 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(TypeString const type) const
{
  return this->string_[type - STRING_FIRST];
} // string const& Setting::value(TypeString type)

/**
 ** searches the file for 'type' in the directories
 **
 ** @param     type	setting type
 **
 ** @return    the file/directory with 'type'
 **            empty string if not found
 ** 
 ** @author    Diether Knof
 **
 ** @version   0.7.5
 **/
string const&
Setting::path(TypeString const type) const
{
  return this->string_path_[type - STRING_FIRST];
} // string Setting::path(TypeString type) const

/**
 ** searches the file for 'type' in the directories
 **
 ** @param     type	setting type
 **
 ** @return    the file/directory with 'type'
 **            empty string if not found
 ** 
 ** @author    Diether Knof
 **
 ** @version   0.7.4
 **/
string const
Setting::path(TypeStringConst const type) const
{
  switch (type) {
  case CARDSET_LICENSE:
    return "";

  case PUBLIC_DATA_DIRECTORY:
  case PRIVATE_DATA_DIRECTORY:
    return this->value(type);

  case SETTINGS_FILE:
    return (this->value(PRIVATE_DATA_DIRECTORY) + "/"
            + this->value(type));

  case LOGO_FILE:
  case ICON_FILE: {
    // search the directory

    list<string> const datadir = this->data_directories();

    for (list<string>::const_iterator dd = datadir.begin();
         dd != datadir.end();
         dd++) {
      string const file = (*dd + "/" + this->value(type));
      // check for the file
      ifstream istr(file.c_str());
      if (istr.good()) {
        return file;
      }
    } // for (dd \in datadir)

    return "";
  } // case LOGO_FILE, ICON_FILE

    // the following directories are subdirectories of the
    // public/private data directory
  case LANGUAGE_FILE:
  case LANGUAGES_DIRECTORY:
  case CARDSETS_DIRECTORY:
  case CARDS_DIRECTORY:
  case CARDS_BACK_DIRECTORY:
  case ICONS_DIRECTORY:
  case BACKGROUNDS_DIRECTORY:
  case SOUNDS_DIRECTORY:
  case AI_DIRECTORY:
  case PARTIES_DIRECTORY:
  case RULES_DIRECTORY:
  case SETTINGS_DIRECTORY:
  case MANUAL_DIRECTORY:
    return "";

  case GRAPHIC_EXTENSION:
  case SOUND_EXTENSION:
    return "";
  } // switch(type)

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

/**
 ** search a cards back
 **
 ** @param     -
 **
 ** @return    -
 **
 ** @author    Diether Knof
 **
 ** @version   0.7.4
 **/
void
Setting::search_cards_back()
{
  if (!this->path(CARDS_BACK).empty())
    return ;

  string new_back;

  { // search the file from the settings
    string const file = (this->path(CARDSET) + "/"
                         + this->value(CARDS_BACK_DIRECTORY) + "/"
                         + this->value(CARDS_BACK)
                         + "." + (*this)(GRAPHIC_EXTENSION));
    // check for the file
    ifstream istr(file.c_str());
    if (istr.good()) {
      new_back = file;
    }

    if (new_back.empty()) {

      list<string> const datadir = this->data_directories();

      for (list<string>::const_iterator dd = datadir.begin();
           dd != datadir.end();
           dd++) {
        string const file = (*dd + "/" + (*this)(CARDSET) + "/"
                             + this->value(CARDS_BACK_DIRECTORY) + "/"
                             + this->value(CARDS_BACK)
                             + "." + (*this)(GRAPHIC_EXTENSION));
        // check for the file
        ifstream istr(file.c_str());
        if (istr.good()) {
          new_back = file;
          break;
        }
      } // for (dd \in datadir)
    } // if (new_back.empty())

  } // search the file from the settings


  list<string> const datadir = this->data_directories();

  // search any back
  for (list<string>::const_iterator dd = datadir.begin();
       dd != datadir.end();
       ++dd) {
    string const directory = (*dd + "/" + (*this)(CARDS_BACK_DIRECTORY));

    DIR *dir = opendir(directory.c_str());

    if (dir == NULL)
      continue;

    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))
             ) {
            new_back = string(basename,
                              0,
                              basename.size()
                              - 1 - (*this)(GRAPHIC_EXTENSION).size());
            break;
          } // if (extension is right)
        } // if (DK::Utils::File::isfile(entry->d_name))
      } // while (entry != NULL) ;
      closedir(dir);
    } // if (dir != NULL)
  } // for (dd \in datadir)

  if (new_back.empty()) {
    if (::ui)
      ::ui->error(::translation("Error::could not find any back for cardset %scardset%", this->value(CARDSET)).translation());
  } else {
    this->set(Setting::CARDS_BACK, new_back);
  }

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

/**
 ** search a background
 **
 ** @param     -
 **
 ** @return    -
 **
 ** @author    Diether Knof
 **
 ** @version   0.7.4
 **/
void
Setting::search_background()
{
  if (!this->path(BACKGROUND).empty())
    return ;

  string new_background;

  list<string> const datadir = this->data_directories();

  // search any background
  for (list<string>::const_iterator dd = datadir.begin();
       dd != datadir.end();
       ++dd) {
    string const directory = (*dd + "/" + (*this)(BACKGROUNDS_DIRECTORY));

    DIR *dir = opendir(directory.c_str());

    if (dir == NULL)
      continue;

    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))
             ) {
            new_background = string(basename,
                                    0,
                                    basename.size()
                                    - 1 - (*this)(GRAPHIC_EXTENSION).size());
            break;
          } // if (extension is right)
        } // if (DK::Utils::File::isfile(entry->d_name))
      } // while (entry != NULL) ;
      closedir(dir);
    } // if (dir != NULL)
  } // for (dd \in datadir)

  if (new_background.empty()) {
    if (::ui)
      ::ui->error(::translation("Error::could not find any background"
                               ).translation());
  } else {
    this->set(Setting::BACKGROUND, new_background);
  }

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

/**
 ** -> 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 CARDSET_LICENSE:
    return this->cardset_license_;
  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 LOGO_FILE:
    return "logo.png";
  case ICON_FILE:
    return "icon.png";
  case LANGUAGES_DIRECTORY:
    return "translations";
  case LANGUAGE_FILE:
    return "text";
  case GRAPHIC_EXTENSION:
    return "png";
#ifdef POSTPONED
    // When the program is started (and 'Setting::default_to_hardcoded()' is
    // called) the ui type is not yet known.
    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 POSTPONED
        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)
#endif // #ifdef POSTPONED
    return "";
  case SOUND_EXTENSION:
#ifdef DKNOF
    //return "ogg";
#endif
    return "wav";
  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 SOUNDS_DIRECTORY:
    return "sounds";
  case AI_DIRECTORY:
    return "ai";
  case PARTIES_DIRECTORY:
    return "parties";
  case RULES_DIRECTORY:
    return "rules";
  case SETTINGS_DIRECTORY:
    return "settings";
  case MANUAL_DIRECTORY:
#ifdef MANUAL_DIRECTORY_VALUE
    return MANUAL_DIRECTORY_VALUE;
#endif // !#ifdef MANUAL_DIRECTORY_VALUE
#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
 **/
Setting::CardsOrder const&
Setting::value(TypeCardsOrder const type) const
{
  return *this->cards_order_;
} // Setting::CardsOrder Setting::value(TypeCardsOrder type) const

/**
 ** -> result
 **
 ** @param	type	setting type (only 'CARDS_ORDER')
 **
 ** @return	the value of the cards order
 ** 
 ** @author	Diether Knof
 **
 ** @version	0.7.0
 **/
Setting::CardsOrder&
Setting::value(TypeCardsOrder const type)
{
  return *this->cards_order_;
} // Setting::CardsOrder& Setting::value(TypeCardsOrder 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) {
#ifdef USE_THREADS
  case THREADS_MAX:
    return 1;
#endif
  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) {
#ifdef USE_THREADS
  case THREADS_MAX:
    return 12;
#endif
  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


/**
 ** -> result
 **
 ** @param     -
 **
 ** @return    the themes list
 **
 ** @author    Diether Knof
 **
 ** @version   0.7.4
 **/
list<Setting::Theme*> const&
Setting::themes() const
{
  return this->themes_;
} // list<Setting::Theme*> const& Setting::themes() const

/**
 ** -> result
 **
 ** @param     name   name of the theme
 **
 ** @return    the theme with the name 'name'
 **            'NULL' if none is found
 **
 ** @author    Diether Knof
 **
 ** @version   0.7.4
 **/
Setting::Theme const*
Setting::theme(string const& name) const
{
  for (list<Theme*>::const_iterator t = this->themes().begin();
       t != this->themes().end();
       ++t)
    if ((*t)->name() == name)
      return *t;

  return NULL;
} // Setting::Theme const* Setting::theme(string const& name) const

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

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

  if (   ui
      && (this == &::setting))
    ::ui->setting_changed(type, &old_value);

  return ;
} // void Setting::set(TypeBool type, bool value)

/**
 ** sets the 'type' to 'value'
 **
 ** @param	type	setting type (Type Bool)
 ** @param	value	new value (as string)
 **
 ** @return	-
 ** 
 ** @author	Diether Knof
 **
 ** @version	0.7.0
 **/
void
Setting::set(TypeBool const 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;
  }

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

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

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

  if (   ui
      && (this == &::setting))
    ::ui->setting_changed(type, &old_value);

  return ;
} // void Setting::set(TypeUnsigned type, unsigned value)

/**
 ** sets the 'type' to 'value'
 **
 ** @param	type	setting type (Type Unsigned)
 ** @param	value	new value (as string)
 **
 ** @return	-
 ** 
 ** @author	Diether Knof
 **
 ** @version	0.7.0
 **/
void
Setting::set(TypeUnsigned const 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;
  }

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

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

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

  // First test, whether this is the default value.
  // If it is, then leave the value empty.
#ifdef POSTPONED
  this->string_[type - STRING_FIRST] = "";
#endif // #ifdef POSTPONED 

  this->string_[type - STRING_FIRST] = value;

  this->update_path(type);

  { // check for path values
    switch(type) {
    case BACKGROUND:
    case CARDS_BACK:
    case CARDSET:
    case LANGUAGE:
      if (this->path(type).empty()) {
        this->string_[type - STRING_FIRST] = old_value;
        return ;
      }
      break;
    default:
      break;
    } // switch (type)
  } // check for path values

  if (this == &::setting) {
    switch(type) {
    case NAME:
      break;
    case PUBLIC_DATA_DIRECTORY:
    case PRIVATE_DATA_DIRECTORY:

      Translator::dir_scan();
      ::translator.load();
      break;
    case LANGUAGE:
      ::translator.load();
      break;
    case CARDSET:
      { // read the license
        list<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");

        string directory = this->path(CARDSET);

        this->cardset_license_.clear();

        for (list<string>::const_iterator license
             = license_files.begin();
             ((license != license_files.end())
              && this->cardset_license_.empty());
             license++) {
          if (DK::Utils::File::isfile(directory + "/"
                                      + *license)) {
            this->cardset_license_ = DK::Utils::String::getfile(directory + "/"
                                                                + *license);
          } // if (license found)
        } // for (license \in license_files)

        if (this->cardset_license_.empty())
          // no license found
          this->cardset_license_ = "license not found :-(";

      } // read the license

      this->search_cards_back();
      break;

    default:
      break;
    } // switch(type)

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

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

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

  CardsOrder const old_value = *this->cards_order_;

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

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

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

  return ;
} // void Setting::set(TypeCardsOrder type, CardsOrder value)

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

/**
 ** sets the 'type' to 'value'
 ** the parameters are strings
 **
 ** @param	type	name of the setting type
 ** @param	value	new value
 **
 ** @return	whether the setting was successful
 ** 
 ** @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)

/**
 ** set the values from the theme
 **
 ** @param     theme   theme to set
 **
 ** @return    -
 **
 ** @author    Diether Knof
 **
 ** @version   0.7.4
 **/
void
Setting::set(Theme const& theme)
{
  for (map<TypeBool, bool>::const_iterator t = theme.bool_.begin();
       t != theme.bool_.end();
       ++t)
    this->set(t->first, t->second);
  for (map<TypeUnsigned, unsigned>::const_iterator t = theme.unsigned_.begin();
       t != theme.unsigned_.end();
       ++t)
    this->set(t->first, t->second);
  for (map<TypeString, string>::const_iterator t = theme.string_.begin();
       t != theme.string_.end();
       ++t)
    this->set(t->first, t->second);

  return ;
} // void Setting::set(Theme theme)

/**
 ** set the values from the theme 'name'
 **
 ** @param     name   name of the theme
 **
 ** @return    whether the theme was found
 **
 ** @author    Diether Knof
 **
 ** @version   0.7.4
 **/
bool
Setting::set_theme(string const& name)
{
  Theme const* theme = this->theme(name);
  if (!theme)
    return false;

  this->set(*theme);
  return true;
} // bool Setting::set_theme(string const& name)

/**
 ** -> result
 **
 ** @param     player   the player
 **
 ** @return    the position of 'player'
 **
 ** @author    Diether Knof
 **
 ** @version   0.7.5
 **/
Position
Setting::position(Player const& player) const
{
  int const rotation
    = ( (   ::setting(Setting::OWN_HAND_ON_TABLE_BOTTOM)
         && (::party.humanno() == 1) )
       ? ::party.human_player()->no()
       : ::setting(Setting::TABLE_ROTATION) );

  switch ( (player.no() + 4 - rotation) % 4) {
  case 0:
    return SOUTH;
  case 1:
    return WEST;
  case 2:
    return NORTH;
  case 3:
    return EAST;
  default:
    DEBUG_ASSERTION(false,
                    "Table::position(player):\n"
                    "  player number " << player.no()
                    << " invalid.");
    break;
  } // switch(player.no())

  return NORTH;
} // Position Table::position(Player player) const

/**
 ** 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.6
 **/
bool
Setting::save() const
{
  return this->save((*this)(SETTINGS_FILE));
} // 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.6
 **/
bool
Setting::save(string const& filename) const
{
  string filename_tmp = filename + ".tmp";
  ofstream ostr(filename_tmp.c_str());
  if (!ostr.good()) {
    ::ui->information(::translation("Error::Setting::save: Error opening temporary file %stmpfile%. Aborting saving.", filename_tmp), INFORMATION::PROBLEM);
    return false;
  }

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

  if (!ostr.good()) {
    ::ui->information(::translation("Error::Setting::save: Error saving in temporary file %stmpfile%. Keeping temporary file (for bug tracking).", filename_tmp), INFORMATION::PROBLEM);
    return false;
  }
  ostr.close();

#ifdef WINDOWS
  unlink(filename.c_str());
#endif
  if (rename(filename_tmp.c_str(), filename.c_str())) {
    ::ui->information(::translation("Error::Setting::save: Could not rename temporary file %stmpfile% to requested file %sfile%. Keeping temporary file.", filename_tmp, filename), INFORMATION::PROBLEM);
    return false;
  }

  return true;
} // 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();

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

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

/**
 ** create the themes list
 **
 ** @param     -
 **
 ** @return    -
 **
 ** @author    Diether Knof
 **
 ** @version   0.7.4
 **/
void
Setting::create_themes_list()
{
  this->clear_themes_list();

  Theme* theme;
  { // Altenburg french
    theme = new Theme("französisch (Altenburg)");
    theme->set(CARDSET, "Altenburg/french");
    theme->set(CARDS_BACK, "penguin");
    theme->set(LANGUAGE, "de");
    this->themes_.push_back(theme);
  } // Altenburg french
  { // Altenburg german
    theme = new Theme("deutsch (Altenburg)");
    theme->set(CARDSET, "Altenburg/german");
    theme->set(CARDS_BACK, "penguin");
    theme->set(LANGUAGE, "de-alt");
    this->themes_.push_back(theme);
  } // Altenburg german
  { // Altenburg english
    theme = new Theme("english (Altenburg)");
    theme->set(CARDSET, "Altenburg/english");
    theme->set(CARDS_BACK, "penguin");
    theme->set(LANGUAGE, "en");
    this->themes_.push_back(theme);
  } // Altenburg german
  { // dondorf english
    theme = new Theme("english (dondorf)");
    theme->set(CARDSET, "dondorf");
    theme->set(CARDS_BACK, "penguin");
    theme->set(LANGUAGE, "en");
    this->themes_.push_back(theme);
  } // dondorf english
  { // autumn
    theme = new Theme(::translation("Setting::Theme::autumn"));
    theme->set(CARDS_BACK, "leaves");
    theme->set(BACKGROUND, "grass-with-leaves");
    this->themes_.push_back(theme);
  } // autumn
  { // christmas
    theme = new Theme(::translation("Setting::Theme::christmas"));
    theme->set(CARDS_BACK, "christmas/candle");
    theme->set(BACKGROUND, "additional/christmas/sky");
    this->themes_.push_back(theme);
  } // christmas

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

/**
 ** clear the themes list
 **
 ** @param     -
 **
 ** @return    -
 **
 ** @author    Diether Knof
 **
 ** @version   0.7.4
 **/
void
Setting::clear_themes_list()
{
  for (list<Theme*>::iterator t = this->themes_.begin();
       t != this->themes_.end();
       ++t)
    delete *t;
  this->themes_.clear();

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

/**
 ** update the path of the string setting 'type'
 **
 ** @param     type	setting type
 **
 ** @return    -
 ** 
 ** @author    Diether Knof
 **
 ** @version   0.7.5
 **/
void
Setting::update_path(TypeString const type)
{
  string const path_bak = this->string_path_[type - STRING_FIRST];

  switch(type) {
  case NAME:
  case NAME_FONT:
  case NAME_FONT_COLOR:
  case NAME_ACTIVE_FONT_COLOR:
  case NAME_RESERVATION_FONT_COLOR:
  case TRICKPILE_POINTS_FONT:
  case TRICKPILE_POINTS_FONT_COLOR:
  case POVERTY_SHIFT_ARROW_COLOR:
    break;
  case LANGUAGE: {
    // @todo   all (use the vectors in 'Translator')
    this->string_path_[type - STRING_FIRST] = (*this)(LANGUAGE_FILE);
    break;
  } // case LANGUAGE:

  case CARDSET: {
    // search the directory
    list<string> subdir;
    subdir.push_back((*this)(CARDSET));
    list<string> const datadir = this->data_directories();

    for (list<string>::const_iterator sd = subdir.begin();
         sd != subdir.end();
         sd++) {
#ifdef WORKAROUND
      // check for Altenburg cardset
      if (   (ALTENBURG_EXPIRATION_DATE < DK::Utils::Date() )
          && (sd->find("Altenburg") != string::npos) ) {
        ::ui->information(::translation("License: Altenburg expired"),
                          INFORMATION::WARNING);
        continue;
      } // if (Altenburg license expired)
      // check for InnoCard cardset
      if (   (INNOCARD_EXPIRATION_DATE < DK::Utils::Date() )
          && (sd->find("InnoCard") != string::npos) ) {
        ::ui->information(::translation("License: InnoCard expired"),
                          INFORMATION::WARNING);
        continue;
      } // if (InnoCard license expired)
      // check for Elite cardset
      if (   (ELITE_EXPIRATION_DATE < DK::Utils::Date() )
          && (sd->find("Elite") != string::npos) ) {
        ::ui->information(::translation("License: Elite expired"),
                          INFORMATION::WARNING);
        continue;
      } // if (Elite license expired)
#endif
      for (list<string>::const_iterator dd = datadir.begin();
           dd != datadir.end();
           dd++) {
        string const directory = *dd + "/" + *sd;
        // check for the file
        ifstream istr((directory + "/"
                       + this->value(CARDS_DIRECTORY) + "/"
                       + ::name(Card::CLUB) + "/"
                       + ::name(Card::ACE)
                       + "." + (*this)(GRAPHIC_EXTENSION)
                      ).c_str());
        if (istr.good()) {
          this->string_path_[type - STRING_FIRST] = directory;
          break;
        }
      } // for (dd \in datadir)
      if (!this->string_path_[type - STRING_FIRST].empty())
        break;
    } // for (sd \in subdir)

    this->update_path(CARDS_BACK);
    break;
  } // case CARDSET: 

  case CARDS_BACK: {

    string const file = (this->path(CARDSET) + "/"
                         + this->value(CARDS_BACK_DIRECTORY) + "/"
                         + this->value(CARDS_BACK)
                         + "." + (*this)(GRAPHIC_EXTENSION));
    // check for the file
    // check for the file
    ifstream istr(file.c_str());
    if (istr.good()) {
      this->string_path_[type - STRING_FIRST] = file;
      break;
    }


    list<string> const datadir = this->data_directories();

    for (list<string>::const_iterator dd = datadir.begin();
         dd != datadir.end();
         dd++) {
      string const file = (*dd + "/" + (*this)(CARDSET) + "/"
                           + this->value(CARDS_BACK_DIRECTORY) + "/"
                           + this->value(CARDS_BACK)
                           + "." + (*this)(GRAPHIC_EXTENSION));
      // check for the file
      ifstream istr(file.c_str());
      if (istr.good()) {
        this->string_path_[type - STRING_FIRST] = file;
        break;
      }
    } // for (dd \in datadir)

    break;
  } // case CARDS_BACK:

  case BACKGROUND: {
    // search the directory

    list<string> const datadir = this->data_directories();

    for (list<string>::const_iterator dd = datadir.begin();
         dd != datadir.end();
         dd++) {
      string const file = (*dd + "/" + (*this)(BACKGROUNDS_DIRECTORY) + "/"
                           + this->value(BACKGROUND)
                           + "." + (*this)(GRAPHIC_EXTENSION)
                          );
      // check for the file
      ifstream istr(file.c_str());
      if (istr.good()) {
        this->string_path_[type - STRING_FIRST] = file;
        break;
      }
    } // for (dd \in datadir)

    break;
  } // case BACKGROUND:

#ifdef USE_SOUND_COMMAND
  case USE_SOUND_COMMAND:
    this->string_path_[type - STRING_FIRST] = (*this)(type);
    break ;
#endif
  case BROWSER_COMMAND:
    this->string_path_[type - STRING_FIRST] = (*this)(type);
    break ;
  } // switch(type)

  if (this->string_path_[type - STRING_FIRST].empty())
    this->string_path_[type - STRING_FIRST] = path_bak;

  return ;
} // void Setting::update_path(TypeString type)

/**
 ** 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
{
  ios_base::fmtflags const flags = ostr.flags();
  ostr << boolalpha;

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

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

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

#ifdef USE_SOUND_COMMAND
    << ::name(USE_SOUND_COMMAND) << " = "
    << this->value(USE_SOUND_COMMAND) << "\n"
#endif

    << ::name(BROWSER_COMMAND) << " = "
    << this->value(BROWSER_COMMAND) << "\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"

#ifdef USE_THREADS
    << ::name(THREADS_MAX) << " = "
    << this->value(THREADS_MAX) << "\n"
#endif

    << "\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(NETWORK_CONNECTIONS_URGENCY_HINT) << " = "
    << this->value(NETWORK_CONNECTIONS_URGENCY_HINT) << "\n"

    << ::name(NETWORK_CHAT_URGENCY_HINT) << " = "
    << this->value(NETWORK_CHAT_URGENCY_HINT) << "\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(NAME_RESERVATION_FONT_COLOR) << " = "
    << this->value(NAME_RESERVATION_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";

  ostr.flags(flags);
  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::AUTOMATIC_SAVINGS:
    return "automatic savings";
  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::NETWORK_CONNECTIONS_URGENCY_HINT:
    return "network connections urgency hint";
  case Setting::NETWORK_CHAT_URGENCY_HINT:
    return "network chat urgency hint";
  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) {
#ifdef USE_THREADS
  case Setting::THREADS_MAX:
    return "max threads";
#endif
  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::NAME_RESERVATION_FONT_COLOR:
    return "name reservation 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";
#ifdef USE_SOUND_COMMAND
  case Setting::PLAY_SOUND_COMMAND:
    return "play sound command";
#endif
  case Setting::BROWSER_COMMAND:
    return "browser command";
  } // 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::CARDSET_LICENSE:
    return "cardset license";
  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::LOGO_FILE:
    return "logo file";
  case Setting::ICON_FILE:
    return "icon file";
  case Setting::LANGUAGES_DIRECTORY:
    return "languages directory";
  case Setting::LANGUAGE_FILE:
    return "language file";
  case Setting::GRAPHIC_EXTENSION:
    return "graphic extension";
  case Setting::SOUND_EXTENSION:
    return "sound 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::SOUNDS_DIRECTORY:
    return "sounds 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::MANUAL_DIRECTORY:
    return "manual 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)

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