/* This file is part of the KDE libraries
    Copyright (C) 1997 Stephan Kulow (coolo@kde.org)

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library 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
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to
    the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.
*/

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

// Overloading of all standard locale functions makes no sense
// Let application use them
#ifdef HAVE_LOCALE_H 
#include <locale.h>
#endif

#include <stdlib.h>

#include <qdir.h>
/**
  * Stephan: I don't want to put this in an extra header file, since
  * this would let people think, they can use it within C files, but
  * this is not the case.
  **/

/* Look up MSGID in the DOMAINNAME message catalog for the current CATEGORY
   locale.  */
char *k_dcgettext (const char *__domainname, const char *__msgid,
		   const char *_language);

/* Set the current default message catalog to DOMAINNAME.
   If DOMAINNAME is null, return the current default.
   If DOMAINNAME is "", reset to the default of "messages".  */
char *k_textdomain (const char *__domainname);

/* Specify that the DOMAINNAME message catalog will be found
   in DIRNAME rather than in the system locale data base.  */
char *k_bindtextdomain (const char *__domainname,
			const char *__dirname);  


#include "klocale.h"
#include <kapp.h>
#include <kconfig.h>
#include <kcharsets.h>

#if !HAVE_LC_MESSAGES
/* This value determines the behaviour of the gettext() and dgettext()
   function.  But some system does not have this defined.  Define it
   to a default value.  */
# define LC_MESSAGES (-1)
#endif
 
#define SYSTEM_MESSAGES "kde"

static char *_categories[]={"LC_MESSAGES","LC_CTYPE","LC_COLLATE",
                            "LC_TIME","LC_NUMERIC","LC_MONETARY",0};

const QString KLocale::mergeLocale(const QString& lang,const QString& country,
				   const QString &charset)
{
    if (lang.isEmpty()) 
	return "C";
    QString ret = lang;
    if (!country.isEmpty()) 
	ret += "_" + country;
    if (!charset.isEmpty()) 
	ret+= "." +charset;
    return ret;
}

void KLocale::splitLocale(const QString& aStr,
			  QString& lang,
			  QString& country,
			  QString &chset){
   
    QString str = aStr.copy();

    // just in case, there is another language appended
    int f = str.find(':');
    if (f >= 0) {
	str = str.left(f);
    }

    country="";
    chset="";
    lang="";
    
    f = str.find('.');
    if (f >= 0) {
	chset = str.right(str.length() - f - 1);
	str = str.left(f);
    }
    
    f = str.find('_');
    if (f >= 0) { 
	country = str.right(str.length() - f - 1);
	str = str.left(f);
    }
    
    lang = str;
    
    if (chset.isEmpty() && kapp != 0){
	QString directory = KApplication::kde_localedir();
	QString dir=directory+"/"+lang+"_"+country;
	QDir d(dir);
	if (!d.exists("charset")){
	    dir=directory+"/"+lang;
	    d=QDir(dir);
	}  
	if (d.exists("charset")){
	    QFile f(dir+"/charset");   
	    if (f.exists() && f.open(IO_ReadOnly)){
		char *buf=new char[256];
		int l=f.readLine(buf,256);
		if (l>0){
		    if (buf[l-1]=='\n') buf[l-1]=0;
		    if (KCharset(buf).ok()) chset=buf;
		}
		delete [] buf;
		f.close();
	    }
	}    
    }  
}

#ifdef ENABLE_NLS

KLocale::KLocale( const char *catalogue )
{
#ifdef HAVE_SETLOCALE
    /* Set locale via LC_ALL according to environment variables  */
    setlocale (LC_ALL, "");
#endif
    chset="us-ascii";
    if ( ! catalogue )
	catalogue = kapp->appName().data();
    
    catalogues = new QStrList(true);
    catalogues->append(catalogue);
    
    QString languages;
    const char *g_lang = getenv("KDE_LANG");
    languages = g_lang;
    
    bool set_locale_vars=false;

    if (kapp) {
	QString setting;
	KConfig* config = kapp->getConfig();
	config->setGroup("Locale");
	if (!g_lang) 
	    languages = config->readEntry("Language", "default");
#ifdef HAVE_SETLOCALE
	setting = config->readEntry("Collate", "default");
	if (setting!="default") 
	    setlocale (LC_COLLATE, setting);
	setting = config->readEntry("Time", "default");
	if (setting!="default") 
	    setlocale (LC_TIME, setting);
	setting = config->readEntry("Monetary", "default");
	if (setting!="default") 
	    setlocale (LC_MONETARY, setting);
	setting = config->readEntry("CType", "default");
	if (setting!="default") 
	    setlocale (LC_CTYPE, setting);
	setting = config->readEntry("Numeric", "default");
	if (setting!="default") 
	    setlocale (LC_NUMERIC, setting);
#endif
	set_locale_vars  = config->readBoolEntry("SetLocaleVariables"
						 , false);
    }
    else 
	if (!g_lang) languages = "default";
    
#ifdef HAVE_SETLOCALE
    // setlocale reads variables LC_* and LANG, and it may use aliases,
    // so we don't have to do it
    g_lang = setlocale(LC_MESSAGES,0);
#else   
    g_lang = getenv("LANG");
#endif
    
    if (languages.isEmpty() || (languages == "default")) {
	if (g_lang && g_lang[0]!=0) // LANG value is set and is not ""
	    languages = g_lang;
	else
	    languages = "C";
    } else 
	languages = languages + ":C";

    QString directory = KApplication::kde_localedir();
    QString ln,ct,chrset;
   
    // save languages list requested by user
    langs=languages;    
    while (1) {
      int f = languages.find(':');
	if (f > 0) {
	    lang = languages.left(f);
	    languages = languages.right(languages.length() - 
					lang.length() - 1);
	} else {
	    lang = languages;
	    languages = "";
	}
	
	if (lang.isEmpty() || lang == "C")
	    break;

        splitLocale(lang,ln,ct,chrset);	

	QString lng[3];
	lng[0]=ln+"_"+ct+"."+chrset;
	lng[1]=ln+"_"+ct;
	lng[2]=ln;
	int i;
	for(i=0; i<3; i++) {
	  QDir d(directory + "/" + lng[i] + "/LC_MESSAGES");
	  if (d.exists(QString(catalogue) + ".mo") &&
	      d.exists(QString(SYSTEM_MESSAGES) + ".mo")) 
	      {
		  lang = lng[i];
		  break;
	      }
        }
	
	if (i != 3)
	    break;
    }
    
    chset=chrset;
#ifdef HAVE_SETLOCALE
    lc_numeric=setlocale(LC_NUMERIC,0);
    setlocale(LC_NUMERIC,"C");          // by default disable LC_NUMERIC
    setlocale(LC_MESSAGES,lang);       
    if (set_locale_vars){
        // set environment variables for all categories
	// maybe we should treat LC_NUMERIC differently (netscape problem)
	QString stmp;
        for(int i=0;_categories[i]!=0;i++) {
	  stmp = QString(_categories[i])+ "=" + getLocale(_categories[i]);
 	  putenv( stmp.data() );
	}
    }
    // we should use LC_CTYPE, not LC_MESSAGES for charset
    // however in most cases it should be the same for messages
    // to be readable (there is no i18n messages charset conversion yet)
    // So when LC_CTYPE is not set (is set to "C") better stay
    // with LC_MESSAGES
    QString lc_ctype=getLocale("LC_CTYPE");
    if ( !lc_ctype.isEmpty() && lc_ctype!="C"){
      splitLocale(getLocale("LC_CTYPE"),ln,ct,chrset);
      if (!chrset.isEmpty()) chset=chrset;
    }  
#else
    lc_numeric="C";
#endif
    numeric_enabled=false;

    insertCatalogue( catalogue );
    insertCatalogue( SYSTEM_MESSAGES );
    if (chset.isEmpty() || !KCharset(chset).ok()) chset="us-ascii";
}

void KLocale::insertCatalogue( const char *catalogue )
{
    k_bindtextdomain ( catalogue , KApplication::kde_localedir() );
    catalogues->append(catalogue);
}

KLocale::~KLocale()
{
    delete catalogues;
}

const char *KLocale::translate(const char *msgid)
{
    const char *text = msgid;
    for (const char *catalogue = catalogues->first(); catalogue; 
	 catalogue = catalogues->next()) 
    {
	text = k_dcgettext( catalogue, msgid, lang);
	if ( text != msgid) // we found it
	    break;
    }

    return text;
}

QString KLocale::directory() 
{
    return KApplication::kde_localedir() +  "/" + lang;
}

void KLocale::aliasLocale( const char* text, long int index)
{
    aliases.insert(index, translate(text));
}

// Using strings seems to be more portable (for systems without locale.h
const char *KLocale::getLocale(QString cat){

    cat.upper();
    if (cat=="LC_NUMERIC") return lc_numeric;
#ifdef HAVE_SETLOCALE        
    else if (cat=="LC_MESSAGES") return setlocale(LC_MESSAGES,0);
    else if (cat=="LC_COLLATE") return setlocale(LC_COLLATE,0);
    else if (cat=="LC_TIME") return setlocale(LC_TIME,0);
    else if (cat=="LC_CTYPE") return setlocale(LC_CTYPE,0);
    else if (cat=="LC_MONETARY") return setlocale(LC_MONETARY,0);
#endif	
    else return "C";
}

void KLocale::enableNumericLocale(bool on){
#ifdef HAVE_SETLOCALE
    if (on) 
	setlocale(LC_NUMERIC,lc_numeric);
    else 
	setlocale(LC_NUMERIC,"C");  
    numeric_enabled=on;
#else  
    numeric_enabled=false;
#endif
}

bool KLocale::numericLocaleEnabled()const{
    return numeric_enabled;
}
 
QStrList KLocale::languageList()const{

// a list to be returned
    QStrList list;
// temporary copy of language list
    QString str=langs;
    str.detach();
    
    while(!str.isEmpty()){
      int f = str.find(':');
      if (f >= 0) {
  	list.append(str.left(f));
        str=str.right(str.length()-f-1);
      }
      else{
        list.append(str);
        str="";
      }
    }   
    return list;
}

#else /* ENABLE_NLS */

KLocale::KLocale( const char *) 
{
}

KLocale::~KLocale() 
{
}

const char *KLocale::translate(const char *msgid)
{
    return msgid;
}

QString KLocale::directory() 
{
    return KApplication::kde_localedir();
}

void KLocale::aliasLocale(const char* text, long int index)
{
    aliases.insert(index, text);
}

const char *KLocale::getLocale(QString ){
    return "C";
}

void  KLocale::enableNumericLocale(bool){
}

bool  KLocale::numericLocaleEnabled()const{
    return false;
}
 
QStrList KLocale::languageList()const{
    return QStrList();
}
#endif /* ENABLE_NLS */


const char *KLocale::getAlias(long key) const
{
    return aliases[key];
}


