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

#include <stdarg.h>

#include "constants.h"

#include "language.h"

#ifndef USE_TRANSLATOR
#include "setting.h"

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

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

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

// ignores unknown words
// (if not defined, each unknown word leads to an error message)
//#define LANGUAGE_IGNORE_UNKNOWN_WORDS
#ifdef RELEASE
#define LANGUAGE_IGNORE_UNKNOWN_WORDS
#endif
#ifndef DKNOF
#define LANGUAGE_IGNORE_UNKNOWN_WORDS
#endif



vector<string> Language::directories;
vector<string> Language::names;

/**********************************************************************
 *
 ** void Language::dir_scan()
 *
 ** Parameters:	-
 *
 ** Result:	-
 *
 ** Version:	0.4.2
 *
 ** Description:	scans the directories for the translations
 **   
 **********************************************************************/
void
Language::dir_scan()
{
  DEBUG_CALLING(INFO_LANGUAGE && INFO_INIT,
		"Language::dir_scan()");

  // clear the old data
  Language::directories.clear();
  Language::names.clear();

  Language::dir_scan(::setting(Setting::PRIVATE_DATA_DIRECTORY)
		     + "/" + ::setting(Setting::LANGUAGES_DIRECTORY));
  Language::dir_scan(::setting(Setting::PUBLIC_DATA_DIRECTORY)
		     + "/" + ::setting(Setting::LANGUAGES_DIRECTORY));
  Language::dir_scan(::setting(Setting::PRIVATE_DATA_DIRECTORY)
		     + "/" + ::setting(Setting::LANGUAGES_DIRECTORY));
  Language::dir_scan("./" + ::setting(Setting::LANGUAGES_DIRECTORY));

  DEBUG_RETURNING(VOID,
		  INFO_LANGUAGE && INFO_INIT,
		  "Language::dir_scan()");
} // void Language::dir_scan()

/**********************************************************************
 *
 ** void Language::dir_scan(string const& dirname)
 *
 ** Parameters:	dirname - directory to scan
 *
 ** Result:	-
 *
 ** Version:	0.4.2
 *
 ** Description:	scans the directory for the translations
 **   
 **********************************************************************/
void
Language::dir_scan(string const& dirname)
{
  DEBUG_CALLING(INFO_LANGUAGE && INFO_INIT,
		"Language::dir_scan(dirname)");

  DIR *language_dir = opendir(dirname.c_str());
  if (language_dir == NULL) {
    DEBUG_RETURNING(VOID,
		    INFO_LANGUAGE && INFO_INIT,
		    "Language::dir_scan(dirname) = failure");
  }

  struct dirent *entry;

  Language::directories.clear();
  Language::names.clear();

  // search all entries in the directory
  while ((entry = readdir(language_dir)) != NULL) {
    if ((strcmp(entry->d_name, ".") == 0) ||
	(strcmp(entry->d_name, "..") == 0))
      continue;
#ifdef LINUX
    if (entry->d_type == DT_DIR)
      // the entry is a directory
#else
      ;
    if (DK::Utils::File::isdirectory(dirname + "/" + entry->d_name))
#endif
    {
      if (DK::Utils::File::isfile(dirname + "/" + entry->d_name + "/"
				  + ::setting.value(Setting::LANGUAGE_FILE))) { 
	// add the language to the list
	Language language;
	language.load(dirname + "/" + entry->d_name + "/"
		      + ::setting.value(Setting::LANGUAGE_FILE));

	// only add the language, when it is not in the list
	if ((std::find(Language::directories.begin(),
		       Language::directories.end(),
		       entry->d_name) == Language::directories.end())
	    || (std::find(Language::names.begin(), Language::names.end(),
			  language.name()) == Language::names.end())) {

	  Language::directories.push_back(entry->d_name);
	  Language::names.push_back(language.name());

	} // if (language not in the list
      } // if (islanguagedirectory)
    } // if (entry->d_type == DT_DIR)
  } // while ((entry = readdir(language_dir)) != NULL)

  closedir(language_dir);

  DEBUG_RETURNING(VOID,
		  INFO_LANGUAGE && INFO_INIT,
		  "Language::dir_scan(dirname)");
} // void Language::dir_scan(string const& dirname)


/**********************************************************************
 *
 ** Language::Language()
 *
 ** Parameters:	-
 *
 ** Result:	-
 *
 ** Version:	0.3.7
 *
 ** Description: Constructor
 *
 **********************************************************************/
Language::Language() :
name_p(),
  word_p(),
translation_p()
{
  DEBUG_CALLING(INFO_LANGUAGE && INFO_INIT,
		"Language::Language()");

  DEBUG_RETURNING(VOID,
		  INFO_LANGUAGE && INFO_INIT,
		  "Language::Language()");
} // Language::Language()

/**********************************************************************
 *
 ** Language::Language(Language const& language)
 *
 ** Parameters:	language - language
 *
 ** Result:	-
 *
 ** Version:	0.4.2
 *
 ** Description: Constructor
 *
 **********************************************************************/
Language::Language(Language const& language) :
name_p(language.name_p),
  word_p(language.word_p),
translation_p(language.translation_p)
{
  DEBUG_CALLING(INFO_LANGUAGE && INFO_INIT,
		"Language::Language(Language)");

  DEBUG_RETURNING(VOID,
		  INFO_LANGUAGE && INFO_INIT,
		  "Language::Language(Language)");
} // Language::Language(Language const& language)

/**********************************************************************
 *
 ** Language& Language::operator=(Language const& language)
 *
 ** Parameters:	language - language
 *
 ** Result:	-
 *
 ** Version:	0.4.2
 *
 ** Description: setting equal
 *
 **********************************************************************/
Language&
Language::operator=(Language const& language)
{
  DEBUG_CALLING(INFO_LANGUAGE && INFO_INIT,
		"Language::operator=(Language)");

  this->name_p = language.name_p;
  this->word_p = language.word_p;
  this->translation_p = language.translation_p;

  DEBUG_RETURNING(*this,
		  INFO_LANGUAGE && INFO_INIT,
		  "Language::operator=(Language)");
} // Language& Language::operator=(Language const& language)


/**********************************************************************
 *
 ** Language::~Language()
 *
 ** Parameters:	-
 *
 ** Result:	-
 *
 ** Version:	0.3.7
 *
 ** Description: Destructor (nothing to do)
 **   
 *
 **********************************************************************/

Language::~Language()
{
  DEBUG_CALLING(INFO_LANGUAGE && INFO_INIT,
		"Language::~Language()");

  DEBUG_RETURNING(VOID,
		  INFO_LANGUAGE && INFO_INIT,
		  "Language::~Language()");
} // Language::~Language()

/**
 **
 ** -> result
 **
 ** @param	-
 **
 ** @return	the name of the current language
 **
 ** @version	0.5.3
 **
 ** @author	Diether Knof
 **
 **/
string const&
Language::name() const
{
  DEBUG_CALLING(INFO_LANGUAGE && INFO_VALUE,
		"Language::name()");

  DEBUG_RETURNING(this->name_p,
		  INFO_LANGUAGE && INFO_VALUE,
		  "Language::name()");
} // string const& Language::name()

/**
 **
 ** -> result
 **
 ** @param	-
 **
 ** @return	the token of the language (also the directory)
 **
 ** @version	0.5.3
 **
 ** @author	Diether Knof
 **
 **/
string const&
Language::token() const
{
  DEBUG_CALLING(INFO_LANGUAGE && INFO_VALUE,
		"Language::token()");

  for (unsigned i = 0; i < Language::names.size(); i++)
    if (Language::names[i] == this->name())
      DEBUG_RETURNING(Language::directories[i],
		      INFO_LANGUAGE && INFO_VALUE,
		      "Language::token()");


  DEBUG_ASSERTION(false,
		  "Language::token():\n"
		  "  token for " << this->name() << " not found.");

  // token not found
  DEBUG_RETURNING(Language::directories[0],
		  INFO_LANGUAGE && INFO_VALUE,
		  "Language::token()");
} // string const& Language::token()

/**
 **
 ** translates 'text'
 **
 ** @param	text	string, that is to be translated
 **
 ** @return	the translation
 ** 
 ** @author	Diether Knof
 **
 ** @version	0.5.1
 **
 **/
string
Language::operator()(string const& text) const
{
  DEBUG_CALLING(INFO_LANGUAGE && INFO_VALUE,
		"Language::operator()(string)");

  DEBUG_RETURNING((*this)(text.c_str()),
		  INFO_LANGUAGE && INFO_VALUE,
		  "Language::operator()(string)");
} // string Language::operator()(string const& text) const

/**********************************************************************
 *
 ** string Language::operator()(char const* const text, ...) const
 *
 ** Parameters:	text - string, that is to be translated
 *
 ** Result:	translated string
 *
 ** Version:	0.4.2
 *
 ** Description: -> result
 **   
 **********************************************************************/
string
Language::operator()(char const* const text_a, ...) const
{
  DEBUG_CALLING(INFO_LANGUAGE && INFO_VALUE,
		"Language::operator()(string, ...)");

  string text = text_a;
  string s = text; // keeps the string

  if (text == "_GPL_")
    DEBUG_RETURNING(GPL_string,
		    INFO_LANGUAGE && INFO_VALUE,
		    "Language::operator()(string, ...)");

  vector<string>::const_iterator word
    = std::find(this->word_p.begin(), this->word_p.end(), s);
  //  string const* word = find(word_p.begin(), word_p.end(), s);
  if (word == this->word_p.end()) {
    // word not found
    // -- if the first character is uppercase, search for lowercase
    if (isupper(s[0])) {
      s[0] = (char) tolower(s[0]);
      word = std::find(this->word_p.begin(), this->word_p.end(), s);
    }
  }

  if (word == this->word_p.end()) {
    // word not found (= word not translated)
#ifndef LANGUAGE_IGNORE_UNKNOWN_WORDS
    if (!this->word_p.empty()) {
      cerr << "Translation: \"" << text << "\" not found"
	<< endl;
    }
#endif
  } else { // if !(word == this->word_p.end())
    s = this->translation_p[word - this->word_p.begin()];
  } // if !(word == this->word_p.end())

  if (isupper(text[0]) && islower(s[0]))
    // the first character is uppercase
    s[0] = (char) toupper(s[0]);

  { // replace the %x...% entries in the text with the parameters
    va_list ap;
    va_start(ap, text_a);

    // start of a '%'-substring
    string::iterator pos = text.begin();
    // end of the '%'-substring
    string::iterator pos_end = text.begin() - 1;
    string replacement; // the replacement for the '%'-substring
    while (pos != text.end()) {
      pos = find(pos_end + 1, text.end(), '%');
      if (pos == text.end())
	// no more '%' in s
	break;

      pos_end = find(pos + 1, text.end(), '%');
      DEBUG_ASSERTION((pos_end != text.end()),
		      "Language::operator()(string, ...):\n"
		      "  uncorrect number of \%");
      if (pos_end == pos + 1)
	// "%%" -- ignore
	continue;

      // look, what of type the argument is
      switch(*(pos + 1)) {
      case 's': // string
#ifdef WORKAROUND
	// 'Language' cannot handle a translation, so take it as a string
      case 't': // translation
#endif
	replacement = DK::Utils::String::to_string(va_arg(ap,
							  char const* const));
	break;
      case 'c': // character
	replacement = DK::Utils::String::to_string(char(va_arg(ap, int)));
	break;
      case 'd':
      case 'i': // integer
	replacement = DK::Utils::String::to_string(va_arg(ap, int));
	break;
      case 'u': // unsigned
	replacement = DK::Utils::String::to_string(va_arg(ap, unsigned));
	break;
      case 'f':
      case 'g': // double
	replacement = DK::Utils::String::to_string(va_arg(ap, double));
	break;
      default:
	DEBUG_ASSERTION(false,
			"Language::operator()(string, ...):\n"
			"  unknown replacement type '" << *(pos + 1) << "'.");
	break;
      } // switch (*(pos + 1))

      DK::Utils::String::replace_all(s, string(pos, pos_end + 1), replacement);
    } // while (pos != s.end())

    // replace "%%" with "%"
    DK::Utils::String::replace_all(s, "%%", "%");

    va_end(ap);
  } // replace the %x...% entries in the text with the parameters

  DEBUG_RETURNING(s,
		  INFO_LANGUAGE && INFO_VALUE,
		  "Language::operator()(char*, ...)");
} // string Language::operator()(char const* const text, ...) const


/**********************************************************************
 *
 ** string Language::operator()(Card::Value const& c) const
 *
 ** Parameters:	value - Card::Value to translate
 *
 ** Result:	translated Card::Value
 *
 ** Version:	0.4.1
 *
 ** Description: -> result
 *
 **********************************************************************/
string
Language::operator()(Card::Value const& value) const
{
  DEBUG_CALLING(INFO_LANGUAGE && INFO_VALUE,
		"Language::operator()(Card::Value)");

  DEBUG_RETURNING((*this)(::name(value)),
		  INFO_LANGUAGE && INFO_VALUE,
		  "Language::operator()(Card::Value)");
} // string Language::operator()(Card::Value const& value) const

/**********************************************************************
 *
 ** string Language::operator()(Card::TColor const& tcolor) const
 *
 ** Parameters:	tcolor - Card::TColor to translate
 *
 ** Result:	translated Card::TColor
 *
 ** Version:	0.4.1
 *
 ** Description: -> result
 *
 **********************************************************************/
string
Language::operator()(Card::TColor const& tcolor) const
{
  DEBUG_CALLING(INFO_LANGUAGE && INFO_VALUE,
		"Language::operator()(Card::TColor)");

  DEBUG_RETURNING((*this)(::name(tcolor)),
		  INFO_LANGUAGE && INFO_VALUE,
		  "Language::operator()(Card::TColor)");
} // string Language::operator()(Card::TColor const& tcolor) const

/**********************************************************************
 *
 ** string Language::operator()(Card const& card) const
 *
 ** Parameters:	card - card to translate
 *
 ** Result:	translated card
 *
 ** Version:	0.4.1
 *
 ** Description: -> result
 **   
 *
 **********************************************************************/
string
Language::operator()(Card const& card) const
{
  DEBUG_CALLING(INFO_LANGUAGE && INFO_VALUE,
		"Language::operator()(Card)");

  DEBUG_RETURNING((*this)(::name(card)),
		  INFO_LANGUAGE && INFO_VALUE,
		  "Language::operator()(Card)");
} // string Language::operator()(Card const& card) const

/**********************************************************************
 *
 ** string Language::operator()(const Rule::TypeBool type) const
 *
 ** Parameters:	type - type to translate
 *
 ** Result:	translated type
 *
 ** Version:	0.4.1
 *
 ** Description: -> result
 **   
 *
 **********************************************************************/
string
Language::operator()(Rule::TypeBool const& type) const
{
  DEBUG_CALLING(INFO_LANGUAGE && INFO_VALUE,
		"Language::operator()(Rule::TypeBool)");

  DEBUG_RETURNING((*this)(::name(type)),
		  INFO_LANGUAGE && INFO_VALUE,
		  "Language::operator()(Rule::TypeBool)");
} // string Language::operator()(Rule::TypeBool const& type) const

/**********************************************************************
 *
 ** string Language::operator()(const Rule::TypeUnsigned type) const
 *
 ** Parameters:	type - type to translate
 *
 ** Result:	translated type
 *
 ** Version:	0.4.1
 *
 ** Description: -> result
 **   
 *
 **********************************************************************/
string
Language::operator()(Rule::TypeUnsigned const& type) const
{
  DEBUG_CALLING(INFO_LANGUAGE && INFO_VALUE,
		"Language::operator()(Rule::TypeUnsigned)");

  DEBUG_RETURNING((*this)(::name(type)),
		  INFO_LANGUAGE && INFO_VALUE,
		  "Language::operator()(Rule::TypeUnsigned)");
} // string Language::operator()(Rule::TypeUnsigned const& type) const

/**********************************************************************
 *
 ** string Language::operator()(Team const& team) const
 *
 ** Parameters:	team - team to translate
 *
 ** Result:	translated team
 *
 ** Version:	0.4.1
 *
 ** Description: -> result
 *
 **********************************************************************/
string
Language::operator()(Team const& team) const
{
  DEBUG_CALLING(INFO_LANGUAGE && INFO_VALUE,
		"Language::operator()(Team)");

  DEBUG_RETURNING((*this)(::name(team)),
		  INFO_LANGUAGE && INFO_VALUE,
		  "Language::operator()(Team)");
} // string Language::operator()(Team const& team) const

/**********************************************************************
 *
 ** string Language::operator()(GameType const& game_type) const
 *
 ** Parameters:	game_type - gametype to translate
 *
 ** Result:	translated gametype
 *
 ** Version:	0.4.1
 *
 ** Description: -> result
 **   
 **********************************************************************/
string
Language::operator()(GameType const& game_type) const
{
  DEBUG_CALLING(INFO_LANGUAGE && INFO_VALUE,
		"Language::operator()(GameType)");

  DEBUG_RETURNING((*this)(::name(game_type)),
		  INFO_LANGUAGE && INFO_VALUE,
		  "Language::operator()(GameType)");
} // string Language::operator()(GameType const& type) const

/**********************************************************************
 *
 ** string Language::operator()(Announcement const& announcement) const
 *
 ** Parameters:	announcement - announcement to translate
 *
 ** Result:	translated announcement
 *
 ** Version:	0.4.1
 *
 ** Description: -> result
 *
 **********************************************************************/
string
Language::operator()(Announcement const& announcement) const
{
  DEBUG_CALLING(INFO_LANGUAGE && INFO_VALUE,
		"Language::operator()(Announcement)");

  DEBUG_RETURNING((*this)(::name(announcement)),
		  INFO_LANGUAGE && INFO_VALUE,
		  "Language::operator()(Announcement)");
} // string Language::operator()(Announcement const& announcement) const

/**********************************************************************
 *
 ** string Language::operator()(MarriageSelector const& marriage_selector) const
 *
 ** Parameters:	marriage_selector - marriageselector to translate
 *
 ** Result:	translated marriageselector
 *
 ** Version:	0.4.1
 *
 ** Description: -> result
 *
 **********************************************************************/
string
Language::operator()(MarriageSelector const& marriage_selector) const
{
  DEBUG_CALLING(INFO_LANGUAGE && INFO_VALUE,
		"Language::operator()(MarriageSelector)");

  DEBUG_RETURNING((*this)(::name(marriage_selector)),
		  INFO_LANGUAGE && INFO_VALUE,
		  "Language::operator()(MarriageSelector)");
} // string Language::operator()(MarriageSelector const& marriage_selector) const

/**********************************************************************
 *
 ** string Language::operator()(Specialpoint const& special_point) const
 *
 ** Parameters:	special_point - Specialpoint to translate
 *
 ** Result:	translated specialpoint
 *
 ** Version:	0.4.1
 *
 ** Description: -> result
 *
 **********************************************************************/
string
Language::operator()(Specialpoint const& special_point) const
{
  DEBUG_CALLING(INFO_LANGUAGE && INFO_VALUE,
		"Language::operator()(Specialpoint)");

  DEBUG_RETURNING((*this)(::name(special_point)),
		  INFO_LANGUAGE && INFO_VALUE,
		  "Language::operator()(Specialpoint)");
} // string Language::operator()(Specialpoint const& special_point) const

/**********************************************************************
 *
 ** string Language::operator()(Player::Type const& type) const
 *
 ** Parameters:	type - player type to translate
 *
 ** Result:	translated type
 *
 ** Version:	0.4.1
 *
 ** Description: -> result
 **   
 **********************************************************************/
string
Language::operator()(Player::Type const& type) const
{
  DEBUG_CALLING(INFO_LANGUAGE && INFO_VALUE,
		"Language::operator()(Player::Type)");

  DEBUG_RETURNING((*this)(::name(type)),
		  INFO_LANGUAGE && INFO_VALUE,
		  "Language::operator()(Player::Type)");
} // string Language::operator()(Player::Type const& type) const

/**********************************************************************
 *
 ** string Language::operator()(AiType const& aitype) const
 *
 ** Parameters:	aitype - aitype to translate
 *
 ** Result:	translated aitype
 *
 ** Version:	0.4.1
 *
 ** Description: -> result
 **   
 **********************************************************************/
string
Language::operator()(AiType const& aitype) const
{
  DEBUG_CALLING(INFO_LANGUAGE && INFO_VALUE,
		"Language::operator()(AiType)");

  DEBUG_RETURNING((*this)(::name(aitype)),
		  INFO_LANGUAGE && INFO_VALUE,
		  "Language::operator()(AiType)");
} // string Language::operator()(AiType const& aitype) const

/**
 **
 ** loads the language given by the settings
 **
 ** @param	-
 **
 ** @return	Language
 **
 ** @version	0.4.2
 **
 ** @author	Diether Knof
 **
 **/
Language&
Language::load()
{
  DEBUG_CALLING(INFO_LANGUAGE && INFO_INIT,
		"Language::load()");

  // clear the treanslation
  this->word_p.clear();
  this->translation_p.clear();

  this->load("./"
	     + ::setting(Setting::LANGUAGE_FILE));
  this->load(::setting(Setting::PRIVATE_DATA_DIRECTORY) + "/"
	     + ::setting(Setting::LANGUAGE_FILE));
  this->load(::setting(Setting::PUBLIC_DATA_DIRECTORY) + "/"
	     + ::setting(Setting::LANGUAGE_FILE));

  DEBUG_RETURNING(*this,
		  INFO_LANGUAGE && INFO_INIT,
		  "Language::load()");
} // Language& Language::load()

/**********************************************************************
 *
 ** Language& Language::load(string filename)
 *
 ** Parameters:	filename - the file to load  
 *
 ** Result:	Language
 *
 ** Version:	0.4.2
 *
 ** Description:	loads a (new) language and updates it
 *
 **********************************************************************/
Language&
Language::load(string filename)
{
  DEBUG_CALLING(INFO_LANGUAGE && INFO_INIT,
		"Language::load(filename)");

  ifstream* istr = new ifstream(filename.c_str());

  if (istr->fail()) {
    if (std::find(Language::names.begin(),
		  Language::names.end(),
		  ::setting.value(Setting::LANGUAGE))
	!= Language::names.end()) {
      filename = (DK::Utils::File::dirname(filename, 2)
		  + "/"
		  + Language::directories[std::find(Language::names.begin(),
						    Language::names.end(),
						    setting.value(Setting::LANGUAGE))
		  - Language::names.begin()]
		  + "/text");

      delete istr;
      istr = new ifstream(filename.c_str());  
    }

    if (istr->fail()) {
      delete istr;
      DEBUG_RETURNING(*this,
		      INFO_LANGUAGE && INFO_INIT,
		      "Language::load(filename)");
    }
  } // if (istr->fail());

  if (DK::Utils::File::basename(DK::Utils::File::dirname(filename)).empty())
    // the filename is not in a subdirectory
    DEBUG_RETURNING(*this,
		    INFO_LANGUAGE && INFO_INIT,
		    "Language::load(filename)");

  this->name_p = DK::Utils::File::basename(DK::Utils::File::dirname(filename));

  while (istr->good()) {
    Config config;
    *istr >> config;

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

    if (config.separator) {
      // a language entry
      this->word_p.push_back(config.name);
      this->translation_p.push_back(config.value);
    } else { // if (config.separator)
      // a setting
      // if the value is in parentencies, remove both
      if ((config.value[0] == '\"')
	  && (config.value[config.value.length() - 1] == '\"'))
	config.value = string(config.value, 1, config.value.length() - 2);
      if (config.name == "!name") {
	// set the name of the lanaguage
	this->name_p = config.value;
      } else if (config.name == "!include") {
	// include the given language
	Language language_new;
	language_new.load(::setting(Setting::PUBLIC_DATA_DIRECTORY) + "/"
			  + ::setting(Setting::LANGUAGES_DIRECTORY) + "/"
			  + config.value + "/"
			  + ::setting.value(Setting::LANGUAGE_FILE));
	this->word_p.insert(word_p.end(),
			    language_new.word_p.begin(),
			    language_new.word_p.end());
	this->translation_p.insert(translation_p.end(),
				   language_new.translation_p.begin(),
				   language_new.translation_p.end());
	language_new.word_p.clear();
	language_new.translation_p.clear();
	language_new.load(::setting(Setting::PRIVATE_DATA_DIRECTORY) + "/"
			  + ::setting(Setting::LANGUAGES_DIRECTORY) + "/"
			  + config.value + "/"
			  + ::setting.value(Setting::LANGUAGE_FILE));
	this->word_p.insert(word_p.end(),
			    language_new.word_p.begin(),
			    language_new.word_p.end());
	this->translation_p.insert(translation_p.end(),
				   language_new.translation_p.begin(),
				   language_new.translation_p.end());
      } else if(config.name == "!end") {
	// ignore the rest of the file
	break;
      } else if (config.name == "!input") {
	// include the given file
	Language language_new;
	language_new.load((DK::Utils::File::dirname(filename) + "/"
			   + config.value));
	this->word_p.insert(word_p.end(),
			    language_new.word_p.begin(),
			    language_new.word_p.end());
	this->translation_p.insert(translation_p.end(),
				   language_new.translation_p.begin(),
				   language_new.translation_p.end());
      } else if(config.name == "") {
	cerr << "Language file \'" << filename << "\': "
	  << "Ignoring line \'" << config.value << "\'.\n";
      } else {
	cerr << "Language file \'" << filename << "\': "
	  << "Setting " << config.name << " unknown.\n"
	  << "Ignoring it.\n";
      } // if (config.name == .)
    } // config.separator

  } // while (istr->good())

  delete istr;

  this->update();

  DEBUG_RETURNING(*this,
		  INFO_LANGUAGE && INFO_INIT,
		  "Language::load(filename)");
} // Language& Language::load(string filename)


/**********************************************************************
 *
 ** int Language::update()
 *
 ** Parameters:	-
 *
 ** Result:	-
 *
 ** Version:	0.3.7
 *
 ** Description: updates all text fields in the program
 *
 **********************************************************************/

void
Language::update()
{
  DEBUG_CALLING(INFO_LANGUAGE && INFO_INIT,
		"Language::update()");

  if ((this == &::language)
      && (ui != NULL))
    ui->language_update();

  DEBUG_RETURNING(VOID,
		  INFO_LANGUAGE && INFO_INIT,
		  "Language::update()");
} // void Language::update()

/**********************************************************************
 *
 ** ostream& Language::output(ostream& ostr)
 *
 ** Parameters:	ostr - output stream
 *
 ** Result:	output stream
 *
 ** Version:	0.3.7
 *
 ** Description: writes all translations into to output stream
 *
 **********************************************************************/
ostream&
Language::output(ostream& ostr) const
{
  DEBUG_CALLING(INFO_LANGUAGE && INFO_IO,
		"Language::output(ostream)");

  unsigned const wordnumber = word_p.size();

  ostr << "Translation: Language " << name_p
    << " (" << wordnumber << " translations) \n";

  for (unsigned i = 0; i < wordnumber; i++) {
    ostr << "  " << setw(32) << word_p[i]
      << "= " << translation_p[i]
      << "\n";
  }

  DEBUG_RETURNING(ostr,
		  INFO_LANGUAGE && INFO_IO,
		  "Language::output(ostream)");
} // ostream& Language::output(ostream& ostr) const

/**********************************************************************
 *
 ** ostream& operator<<(ostream& ostr, Language const& language)
 *
 ** Parameters:	ostr - output stream
 *		language - Language to be printed
 *
 ** Result:	printed language
 *
 ** Version:	0.3.7
 *
 ** Description: ouput of the language
 *
 **********************************************************************/

ostream&
operator<<(ostream& ostr, Language const& language)
{
  DEBUG_CALLING(INFO_LANGUAGE && INFO_IO,
		"operator<<(ostream, Language)");

  language.output(ostr);

  DEBUG_RETURNING(ostr,
		  INFO_LANGUAGE && INFO_IO,
		  "operator<<(ostream, Language)");
} // ostream& operator<<(ostream& ostr, Language const& language)
#endif // #ifndef USE_TRANSLATOR
