/*
 * locale.cpp
 *
 * Copyright (c) 1998 Matthias Hoelzer (hoelzer@physik.uni-wuerzburg.de)
 * Copyright (c) 1999 Preston Brown <pbrown@kde.org>
 * Copyright (c) 1999-2003 Hans Petter Bieker <bieker@kde.org>
 *
 * Requires the Qt widget libraries, available at no cost at
 * http://www.troll.no/
 *
 *  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 should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */

#include <tqhbox.h>
#include <tqlabel.h>
#include <tqlayout.h>
#include <tqlistbox.h>
#include <tqpushbutton.h>
#include <tqtooltip.h>
#include <tqwhatsthis.h>

#include <kdebug.h>
#include <kdialog.h>
#include <kprocess.h>
#include <kiconloader.h>
#include <klanguagebutton.h>
#include <ksimpleconfig.h>
#include <kstandarddirs.h>

#include "kcmlocale.h"
#include "kcmlocale.moc"
#include "toplevel.h"

TDELocaleConfig::TDELocaleConfig(TDELocale *locale,
                             TQWidget *parent, const char *name)
  : TQWidget (parent, name),
    m_locale(locale)
{
  TQGridLayout *lay = new TQGridLayout(this, 4, 3,
                                     KDialog::marginHint(),
                                     KDialog::spacingHint());

  m_labCountry = new TQLabel(this, I18N_NOOP("Country or region:"));
  m_comboCountry = new KLanguageButton( this );
  m_labCountry->setBuddy(m_comboCountry);
  connect( m_comboCountry, TQT_SIGNAL(activated(const TQString &)),
           this, TQT_SLOT(changedCountry(const TQString &)) );

  m_labLang = new TQLabel(this, I18N_NOOP("Languages:"));
  m_labLang->setAlignment( AlignTop );

  m_languages = new TQListBox(this);
  connect(m_languages, TQT_SIGNAL(selectionChanged()),
          TQT_SLOT(slotCheckButtons()));

  TQWidget * vb = new TQWidget(this);
  TQVBoxLayout * boxlay = new TQVBoxLayout(vb, 0, KDialog::spacingHint());
  m_addLanguage = new KLanguageButton(TQString::null, vb, I18N_NOOP("Add Language"));
  boxlay->add(m_addLanguage);
  connect(m_addLanguage, TQT_SIGNAL(activated(const TQString &)),
          TQT_SLOT(slotAddLanguage(const TQString &)));
  m_removeLanguage = new TQPushButton(vb, I18N_NOOP("Remove Language"));
  m_upButton = new TQPushButton(vb, I18N_NOOP("Move Up"));
  m_downButton = new TQPushButton(vb, I18N_NOOP("Move Down"));
  boxlay->add(m_removeLanguage);
  boxlay->add(m_upButton);
  boxlay->add(m_downButton);
  connect(m_removeLanguage, TQT_SIGNAL(clicked()),
          TQT_SLOT(slotRemoveLanguage()));
  connect(m_upButton, TQT_SIGNAL(clicked()),
          TQT_SLOT(slotLanguageUp()));
  connect(m_downButton, TQT_SIGNAL(clicked()),
          TQT_SLOT(slotLanguageDown()));
  boxlay->insertStretch(-1);

  // #### HPB: This should be implemented for KDE 3
  //  new TQLabel(this, I18N_NOOP("Encoding:"));
  //TQComboBox * cb = new TQComboBox( this );
  //cb->insertStringList( TDEGlobal::charsets()->descriptiveEncodingNames() );

  lay->addMultiCellWidget(m_labCountry, 0, 0, 0, 1);
  lay->addWidget(m_comboCountry, 0, 2);
  lay->addWidget(m_labLang, 1, 0);
  lay->addWidget(m_languages, 1, 1);
  lay->addWidget(vb, 1, 2);

  lay->setRowStretch(2, 5);

  lay->setColStretch(1, 1);
  lay->setColStretch(2, 1);

#if 0
  // Added jriddell 2007-01-08, for Kubuntu Language Selector spec
  TQHBoxLayout* languageSelectorLayout = new TQHBoxLayout();
  installLanguage = new TQPushButton(i18n("Install New Language"), this);
  languageSelectorLayout->addWidget(installLanguage);
  uninstallLanguage = new TQPushButton(i18n("Uninstall Language"), this);
  languageSelectorLayout->addWidget(uninstallLanguage);
  selectLanguage = new TQPushButton(i18n("Select System Language"), this);
  languageSelectorLayout->addWidget(selectLanguage);
  languageSelectorLayout->addStretch();
  lay->addMultiCellLayout(languageSelectorLayout, 3, 3, 0, 2);

  connect( installLanguage, TQT_SIGNAL(clicked()), this, TQT_SLOT(slotInstallLanguage()) );
  connect( uninstallLanguage, TQT_SIGNAL(clicked()), this, TQT_SLOT(slotUninstallLanguage()) );
  connect( selectLanguage, TQT_SIGNAL(clicked()), this, TQT_SLOT(slotSelectLanguage()) );
#endif

}

void TDELocaleConfig::slotInstallLanguage()
{
  TDEProcess *proc = new TDEProcess;

  *proc << "tdesu";
  *proc << "qt-language-selector --mode install";
  TQApplication::connect(proc, TQT_SIGNAL(processExited(TDEProcess *)),
			this, TQT_SLOT(slotLanguageSelectorExited(TDEProcess *)));
  setEnabled(false);
  proc->start();
}

void TDELocaleConfig::slotUninstallLanguage()
{
  TDEProcess *proc = new TDEProcess;

  *proc << "tdesu";
  *proc << "qt-language-selector --mode uninstall";
  TQApplication::connect(proc, TQT_SIGNAL(processExited(TDEProcess *)),
			this, TQT_SLOT(slotLanguageSelectorExited(TDEProcess *)));
  setEnabled(false);
  proc->start();
}

void TDELocaleConfig::slotSelectLanguage()
{
  TDEProcess *proc = new TDEProcess;

  *proc << "tdesu";
  *proc << "qt-language-selector --mode select";
  TQApplication::connect(proc, TQT_SIGNAL(processExited(TDEProcess *)),
			this, TQT_SLOT(slotLanguageSelectorExited(TDEProcess *)));
  setEnabled(false);
  proc->start();
}

void TDELocaleConfig::slotLanguageSelectorExited(TDEProcess *)
{
  //reload here
  loadLanguageList();
  setEnabled(true);
}

void TDELocaleConfig::slotAddLanguage(const TQString & code)
{
  TQStringList languageList = m_locale->languageList();

  int pos = m_languages->currentItem();
  if ( pos < 0 )
    pos = 0;

  // If it's already in list, just move it (delete the old, then insert a new)
  int oldPos = languageList.findIndex( code );
  if ( oldPos != -1 )
    languageList.remove( languageList.at(oldPos) );

  if ( oldPos != -1 && oldPos < pos )
    --pos;

  TQStringList::Iterator it = languageList.at( pos );

  languageList.insert( it, code );

  m_locale->setLanguage( languageList );

  emit localeChanged();
  if ( pos == 0 )
    emit languageChanged();
}

void TDELocaleConfig::slotRemoveLanguage()
{
  TQStringList languageList = m_locale->languageList();
  int pos = m_languages->currentItem();

  TQStringList::Iterator it = languageList.at( pos );

  if ( it != languageList.end() )
    {
      languageList.remove( it );

      m_locale->setLanguage( languageList );

      emit localeChanged();
      if ( pos == 0 )
        emit languageChanged();
    }
}

void TDELocaleConfig::slotLanguageUp()
{
  TQStringList languageList = m_locale->languageList();
  int pos = m_languages->currentItem();

  TQStringList::Iterator it1 = languageList.at( pos - 1 );
  TQStringList::Iterator it2 = languageList.at( pos );

  if ( it1 != languageList.end() && it2 != languageList.end()  )
  {
    TQString str = *it1;
    *it1 = *it2;
    *it2 = str;

    m_locale->setLanguage( languageList );

    emit localeChanged();
    if ( pos == 1 ) // at the lang before the top
      emit languageChanged();
  }
}

void TDELocaleConfig::slotLanguageDown()
{
  TQStringList languageList = m_locale->languageList();
  int pos = m_languages->currentItem();

  TQStringList::Iterator it1 = languageList.at( pos );
  TQStringList::Iterator it2 = languageList.at( pos + 1 );

  if ( it1 != languageList.end() && it2 != languageList.end()  )
    {
      TQString str = *it1;
      *it1 = *it2;
      *it2 = str;

      m_locale->setLanguage( languageList );

      emit localeChanged();
      if ( pos == 0 ) // at the top
        emit languageChanged();
    }
}

void TDELocaleConfig::loadLanguageList()
{
  // temperary use of our locale as the global locale
  TDELocale *lsave = TDEGlobal::_locale;
  TDEGlobal::_locale = m_locale;

  // clear the list
  m_addLanguage->clear();

  TQStringList first = languageList();

  TQStringList prilang;
  // add the primary languages for the country to the list
  for ( TQStringList::ConstIterator it = first.begin();
        it != first.end();
        ++it )
  {
    TQString str = locate("locale", TQString::fromLatin1("%1/entry.desktop")
                         .arg(*it));
    if (!str.isNull())
      prilang << str;
  }

  // add all languages to the list
  TQStringList alllang = TDEGlobal::dirs()->findAllResources("locale",
                               TQString::fromLatin1("*/entry.desktop"), 
                               false, true);
  TQStringList langlist = prilang;
  if (langlist.count() > 0)
    langlist << TQString::null; // separator
  langlist += alllang;

  int menu_index = -2;
  TQString submenu; // we are working on this menu
  for ( TQStringList::ConstIterator it = langlist.begin();
        it != langlist.end(); ++it )
  {
    if ((*it).isNull())
    {
      m_addLanguage->insertSeparator();
      submenu = TQString::fromLatin1("other");
      m_addLanguage->insertSubmenu(m_locale->translate("Other"),
                                   submenu, TQString::null, -1);
      menu_index = -2; // first entries should _not_ be sorted
      continue;
    }
    KSimpleConfig entry(*it);
    entry.setGroup("KCM Locale");
    TQString name = entry.readEntry("Name",
                                   m_locale->translate("without name"));

    TQString tag = *it;
    int index = tag.findRev('/');
    tag = tag.left(index);
    index = tag.findRev('/');
    tag = tag.mid(index + 1);
    m_addLanguage->insertItem(name, tag, submenu, menu_index);
  }

  // restore the old global locale
  TDEGlobal::_locale = lsave;
}

void TDELocaleConfig::loadCountryList()
{
  // temperary use of our locale as the global locale
  TDELocale *lsave = TDEGlobal::_locale;
  TDEGlobal::_locale = m_locale;

  TQString sub = TQString::fromLatin1("l10n/");

  // clear the list
  m_comboCountry->clear();

  TQStringList regionlist = TDEGlobal::dirs()->findAllResources("locale",
                                 sub + TQString::fromLatin1("*.desktop"), 
                                 false, true );

  for ( TQStringList::ConstIterator it = regionlist.begin();
    it != regionlist.end();
    ++it )
  {
    TQString tag = *it;
    int index;

    index = tag.findRev('/');
    if (index != -1)
      tag = tag.mid(index + 1);

    index = tag.findRev('.');
    if (index != -1)
      tag.truncate(index);

    KSimpleConfig entry(*it);
    entry.setGroup("KCM Locale");
    TQString name = entry.readEntry("Name",
                                   m_locale->translate("without name"));

    TQString map( locate( "locale",
                          TQString::fromLatin1( "l10n/%1.png" )
                          .arg(tag) ) );
    TQIconSet icon;
    if ( !map.isNull() )
      icon = TDEGlobal::iconLoader()->loadIconSet(map, TDEIcon::Small);
    m_comboCountry->insertSubmenu( icon, name, tag, sub, -2 );
  }

  // add all languages to the list
  TQStringList countrylist = TDEGlobal::dirs()->findAllResources
    ("locale", sub + TQString::fromLatin1("*/entry.desktop"), false, true);

  for ( TQStringList::ConstIterator it = countrylist.begin();
        it != countrylist.end(); ++it )
  {
    KSimpleConfig entry(*it);
    entry.setGroup("KCM Locale");
    TQString name = entry.readEntry("Name",
                                   m_locale->translate("without name"));
    TQString submenu = entry.readEntry("Region");

    TQString tag = *it;
    int index = tag.findRev('/');
    tag.truncate(index);
    index = tag.findRev('/');
    tag = tag.mid(index + 1);
    int menu_index = submenu.isEmpty() ? -1 : -2;

    TQString flag( locate( "locale",
                          TQString::fromLatin1( "l10n/%1/flag.png" )
                          .arg(tag) ) );
    TQIconSet icon( TDEGlobal::iconLoader()->loadIconSet(flag, TDEIcon::Small) );
    m_comboCountry->insertItem( icon, name, tag, submenu, menu_index );
  }

  // restore the old global locale
  TDEGlobal::_locale = lsave;
}

void TDELocaleConfig::readLocale(const TQString &path, TQString &name,
                               const TQString &sub) const
{
  // temperary use of our locale as the global locale
  TDELocale *lsave = TDEGlobal::_locale;
  TDEGlobal::_locale = m_locale;

  // read the name
  TQString filepath = TQString::fromLatin1("%1%2/entry.desktop")
    .arg(sub)
    .arg(path);

  KSimpleConfig entry(locate("locale", filepath));
  entry.setGroup("KCM Locale");
  name = entry.readEntry("Name");

  // restore the old global locale
  TDEGlobal::_locale = lsave;
}

void TDELocaleConfig::save()
{
  TDEConfigBase *config = TDEGlobal::config();

  config->setGroup("Locale");

  config->writeEntry("Country", m_locale->country(), true, true);
  if ( m_locale->languageList().isEmpty() )
    config->writeEntry("Language", TQString::fromLatin1(""), true, true);
  else
    config->writeEntry("Language",
                       m_locale->languageList(), ':', true, true);

  config->sync();
}

void TDELocaleConfig::slotCheckButtons()
{
  m_removeLanguage->setEnabled( m_languages->currentItem() != -1 );
  m_upButton->setEnabled( m_languages->currentItem() > 0 );
  m_downButton->setEnabled( m_languages->currentItem() != -1 &&
                            m_languages->currentItem() < (signed)(m_languages->count() - 1) );
}

void TDELocaleConfig::slotLocaleChanged()
{
  loadLanguageList();
  loadCountryList();

  // update language widget
  m_languages->clear();
  TQStringList languageList = m_locale->languageList();
  for ( TQStringList::Iterator it = languageList.begin();
        it != languageList.end();
        ++it )
  {
    TQString name;
    readLocale(*it, name, TQString::null);

    m_languages->insertItem(name);
  }
  slotCheckButtons();

  m_comboCountry->setCurrentItem( m_locale->country() );
}

void TDELocaleConfig::slotTranslate()
{
  kdDebug() << "slotTranslate()" << endl;

  TQToolTip::add(m_comboCountry, m_locale->translate
        ( "This is where you live. TDE will use the defaults for "
          "this country or region.") );
  TQToolTip::add(m_addLanguage, m_locale->translate
        ( "This will add a language to the list. If the language is already "
          "in the list, the old one will be moved instead." ) );

  TQToolTip::add(m_removeLanguage, m_locale->translate
        ( "This will remove the highlighted language from the list." ) );

  TQToolTip::add(m_languages, m_locale->translate
        ( "TDE programs will be displayed in the first available language in "
          "this list.\nIf none of the languages are available, US English "
          "will be used.") );

  TQString str;

  str = m_locale->translate
    ( "Here you can choose your country or region. The settings "
      "for languages, numbers etc. will automatically switch to the "
      "corresponding values." );
  TQWhatsThis::add( m_labCountry, str );
  TQWhatsThis::add( m_comboCountry, str );

  str = m_locale->translate
    ( "Here you can choose the languages that will be used by TDE. If the "
      "first language in the list is not available, the second will be used, "
      "etc. If only US English is available, no translations "
      "have been installed. You can get translation packages for many "
      "languages from the place you got TDE from.<p>"
      "Note that some applications may not be translated to your languages; "
      "in this case, they will automatically fall back to US English." );
  TQWhatsThis::add( m_labLang, str );
  TQWhatsThis::add( m_languages, str );
  TQWhatsThis::add( m_addLanguage, str );
  TQWhatsThis::add( m_removeLanguage, str );
}

TQStringList TDELocaleConfig::languageList() const
{
  TQString fileName = locate("locale",
                            TQString::fromLatin1("l10n/%1/entry.desktop")
                            .arg(m_locale->country()));

  KSimpleConfig entry(fileName);
  entry.setGroup("KCM Locale");

  return entry.readListEntry("Languages");
}

void TDELocaleConfig::changedCountry(const TQString & code)
{
  m_locale->setCountry(code);

  // change to the preferred languages in that country, installed only
  TQStringList languages = languageList();
  TQStringList newLanguageList;
  for ( TQStringList::Iterator it = languages.begin();
        it != languages.end();
        ++it )
  {
    TQString name;
    readLocale(*it, name, TQString::null);

    if (!name.isEmpty())
      newLanguageList += *it;
  }
  m_locale->setLanguage( newLanguageList );

  emit localeChanged();
  emit languageChanged();
}