/***************************************************************************
                          kbconfig.cpp  -  description
                             -------------------
    begin                : Sun Jul 8 2001
    copyright            : (C) 2001 by Leonid Zeitlin
    email                : lz@europe.com
 ***************************************************************************/

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

#include <unistd.h>

#include <config.h> 
#include <tdeversion.h>
#include <tdelocale.h>
#include <tdeglobal.h>
#include <kstandarddirs.h>
#include <tdeapplication.h>
#include <tdeglobalsettings.h>
#include <kdebug.h>
#include <kglobalaccel.h>

#include <tqnamespace.h>
#include <tqpainter.h>
#include <tqimage.h>

#include "kbconfig.h"
#include "xkeyboard.h"

#ifdef HAVE_X11_EXTENSIONS_XKBRULES_H
  #include <X11/extensions/XKBrules.h>
#endif

#define TOGGLE_MODE_ENTRY "toggle_mode"
#define DEFAULT_GROUP_ENTRY "default_group"
//#define PERWINDOW_GROUP_ENTRY "perwindow_group"
#define ICON_TYPE_ENTRY "icon_type"
#define AUTOSTART_ENTRY "autostart"
#define USE_SHORTCUTS_ENTRY "use_shorcuts"
#define GROUP_SCOPE_ENTRY "group_scope"

KBConfig::KBConfig()
{
  m_toggle_mode = false;
  m_groups.setAutoDelete(true);
  m_default_groupno = 0;
  //m_perwindow_group = false;
  m_group_scope = SCOPE_GLOBAL;
  m_autostart = true;
  m_icon_style = ICON_CODE_AND_FLAG;
  //m_keys = new TDEGlobalAccel(NULL);
  m_keys = NULL;
}

KBConfig::~KBConfig()
{
	delete m_keys;
}

/** load the KBSwitch configration from the application TDEConfig object */
void KBConfig::load(TDEConfig *config){
  config->setGroup(OPTIONS_SECTION);
  m_toggle_mode = config->readBoolEntry(TOGGLE_MODE_ENTRY);
  m_default_groupno = config->readNumEntry(DEFAULT_GROUP_ENTRY);
  //m_perwindow_group = config->readBoolEntry(PERWINDOW_GROUP_ENTRY);
  m_group_scope = GroupScope(config->readNumEntry(GROUP_SCOPE_ENTRY, SCOPE_GLOBAL));
  m_autostart = config->readBoolEntry(AUTOSTART_ENTRY, true);
  m_icon_style = IconStyle(config->readNumEntry(ICON_TYPE_ENTRY, ICON_FLAG));
  m_use_shortcuts = config->readBoolEntry(USE_SHORTCUTS_ENTRY, false);
	
  XKeyboard *xkb = XKeyboard::self();
  TQStringList list;
  xkb->getGroupNames(list);
  unsigned int i = 0;
  m_groups.clear();
  m_groups.resize(xkb->getNumKbdGroups());
  TQString name;
  for (TQStringList::Iterator iter = list.begin(); iter != list.end(); iter++, i++) {
    name = *iter;
    if (name == TQString::null) name = i18n("<Unnamed>");
    m_groups.insert(i, new KBGroup(name));
  }

  TQValueVector<TQPixmap> pixlist;
  TQStringList iconpaths;
  drawIcons(m_icon_style, &pixlist, &iconpaths);
  for (i = 0; i < m_groups.count(); i++) {
		m_groups[i]->setPixmap(pixlist[i]);
		m_groups[i]->setIconPath(iconpaths[i]);
	}

	if (m_keys) delete m_keys;
  m_keys = new TDEGlobalAccel(NULL);
  for (int i = 0; i < groupCount(); i++) {
    m_keys->insert(TQString::fromLatin1("SetGroup %1").arg(i),
      i18n("Activate %1 keyboard layout").arg(m_groups[i]->getName()),
      TQString::null, TQt::ALT+TQt::CTRL+TQt::Key_1 + i, KKey::QtWIN+TQt::CTRL+TQt::Key_1 + i,
      kapp, TQ_SLOT(slotGroupSelected(int)));
  }
  m_keys->insert("NextGroup", i18n("Cycle keyboard layouts"),
                 i18n("Activates the next keyboard layout or, if the current layout is the last one, "
                      "activates the first layout."),
                 TQt::SHIFT+TQt::CTRL+TQt::Key_Plus, TQt::SHIFT+TQt::CTRL+TQt::Key_Plus,
                 kapp, TQ_SLOT(slotSelectNextGroup()));
  m_keys->insert("PrevGroup", i18n("Cycle keyboard layouts (reverse)"),
                 i18n("Activates the previous keyboard layout or, if the current layout is the first one, "
                      "activates the last layout."),
                 TQt::SHIFT+TQt::CTRL+TQt::Key_Minus, TQt::SHIFT+TQt::CTRL+TQt::Key_Minus,
                 kapp, TQ_SLOT(slotSelectPrevGroup()));
  m_keys->readSettings(config);
  checkKeysEnabled();
}

void KBConfig::save(TDEConfig *config)
{
  config->setGroup(OPTIONS_SECTION);
  config->writeEntry(TOGGLE_MODE_ENTRY, m_toggle_mode);
  config->writeEntry(DEFAULT_GROUP_ENTRY, m_default_groupno);
  //config->writeEntry(PERWINDOW_GROUP_ENTRY, m_perwindow_group);
  config->writeEntry(GROUP_SCOPE_ENTRY, m_group_scope);
  config->writeEntry(ICON_TYPE_ENTRY, m_icon_style);
  config->writeEntry(AUTOSTART_ENTRY, m_autostart);
  config->writeEntry(USE_SHORTCUTS_ENTRY, m_use_shortcuts);
  m_keys->writeSettings(config);
}

void KBConfig::drawIcons(IconStyle icon_style, TQValueVector<TQPixmap> *icons,
  TQStringList *iconpaths)
{
  TQString path, countryCode, langCode;
  TQStringList layouts;
  
  TDEGlobal::dirs()->addResourceDir("appdata", ".");
  TDEConfig map("group_names", true, true, "appdata");
  TDEConfig *config = kapp->config();
  config->setGroup(ICONS_SECTION);
  getXkbLayouts(layouts);

  icons->clear();
  icons->resize(m_groups.count());
  iconpaths->clear();
  for (unsigned int i = 0; i < m_groups.count(); i++) {
    map.setGroup("Mapping");
    countryCode = map.readEntry(m_groups[i]->getName());
    // if the country code can't be guessed from group name, try XKB layout name
    if (countryCode.isEmpty() && i < layouts.count()) countryCode = layouts[i];
    map.setGroup("Languages");
    langCode = map.readEntry(m_groups[i]->getName());
    if (langCode.isEmpty()) langCode = countryCode;
    TQPixmap &pix = (*icons)[i];
    pix.resize(0, 0);
    path = TQString::null;
    if (icon_style == ICON_FLAG /*&& !countryCode.isEmpty()*/)
      drawFlagPixmap(pix, path, countryCode, i, config);
    else if (icon_style == ICON_CODE_AND_FLAG /*&& !countryCode.isEmpty()*/)
      drawCodeAndFlagPixmap(pix, path, countryCode, langCode, i, config);
    if (pix.isNull() && !langCode.isEmpty())
    drawCodePixmap(pix, langCode);
    if (pix.isNull()) drawDefaultPixmap(pix, i);
    iconpaths->append(path);
  }
}

/** No descriptions */
/*void KBConfig::guessGroupPixmaps(){
  TDEGlobal::dirs()->addResourceDir("appdata", ".");
  TDEConfig map("group_names", true, true, "appdata");
  TQString path, countryCode, langCode;
  TQPixmap pix;

  for (unsigned int i = 0; i < m_groups.count(); i++) {
    if (m_groups[i]->getPixmap().isNull()) {
  	  map.setGroup("Mapping");
      countryCode = map.readEntry(m_groups[i]->getName());
  	  map.setGroup("Languages");
      langCode = map.readEntry(m_groups[i]->getName());
      if (langCode.isEmpty()) langCode = countryCode;
  		pix.resize(0, 0);
	  	if (m_icon_type == ICON_FLAG && !countryCode.isEmpty())
	      drawFlagPixmap(pix, countryCode);
		  else if (m_icon_type == ICON_CODE_AND_FLAG && !countryCode.isEmpty())
		    drawCodeAndFlagPixmap(pix, countryCode, langCode);
  		if (pix.isNull() && !langCode.isEmpty())
        drawCodePixmap(pix, langCode);
      if (!pix.isNull()) m_groups[i]->setPixmap(pix);
    }
  }
}*/

bool KBConfig::getGroupImage(TQImage &img, TQString &path, const TQString &code,
  int group, TDEConfig *config)
{
  bool ret = true;
  bool need_to_scale = false;
	
  path = config->readEntry(m_groups[group]->getName()/*entryForGroup(group)*/);
  if (path.isEmpty() || !img.load(path)) {
    if (code.isEmpty()) ret = false;
    else {
      path = locate("locale", TQString("l10n/%1/flag.png").arg(code));
      if (!path.isEmpty()) ret = img.load(path);
      else {
        // I am told in Red Hat 9 standard KDE flag pixmaps are missing.
        // Workaround: we have to simulate them by rescaling GKB's pixmaps
        path = TQString("/usr/share/pixmaps/gkb/%1.png").arg(code);
        ret = img.load(path) && !img.isNull();
        need_to_scale = true;
      }
    } 
  }
  if (ret) {
     // if need_to_scale is not already set, set it if image is too wide
     if (!need_to_scale) need_to_scale = img.width() > 24;
     if (need_to_scale) img = img.smoothScale(FLAG_ICON_WIDTH, FLAG_ICON_HEIGHT);
  }
  return ret;
}

void KBConfig::drawFlagPixmap(TQPixmap &pix, TQString &path, const TQString &code,
  int group, TDEConfig *config)
{
  TQImage img;
  if (getGroupImage(img, path, code, group, config)) 
    pix.convertFromImage(img);
}

void KBConfig::drawCodePixmap(TQPixmap &pix, const TQString &code)
{
  pix.resize(19, 16);
	
  TQPainter painter(&pix);
  TQFont font("helvetica", 9, TQFont::Bold);
  font.setPixelSize(10);
  painter.setFont(font);
	painter.setPen(TDEGlobalSettings::highlightedTextColor());
	
	pix.fill(TDEGlobalSettings::highlightColor());
  painter.drawText(1, 0, pix.width(), pix.height(),
    TQt::AlignHCenter | TQt::AlignVCenter, code.upper());

  /*TQSize size = painter.fontMetrics().size(0, code.upper());
  kdDebug() << size.width() << " x " << size.height() << endl;*/
}

void KBConfig::drawCodeAndFlagPixmap(TQPixmap &pix, TQString &path,
  const TQString &countryCode, const TQString &langCode, int group, TDEConfig *config)
{
	TQImage img;
	if (!getGroupImage(img, path, countryCode, group, config)) return; // could not find flag
	if (img.depth() <= 8) img = img.convertDepth(32);

	// the following code is taken from tdebase/kxkb/pixmap.cpp
  for (int y = 0; y < img.height(); y++)
    for(int x = 0; x < img.width(); x++) {
      TQRgb rgb = img.pixel(x, y);
      img.setPixel(x, y, tqRgb(tqRed(rgb)*3/4, tqGreen(rgb)*3/4, tqBlue(rgb)*3/4));
    }
  pix.convertFromImage(img);

  TQPainter painter(&pix);
  painter.setPen(TQt::black);
  painter.setFont(TQFont("helvetica", 10, TQFont::Bold));
  painter.drawText(1, 1, pix.width(), pix.height()-2, TQt::AlignCenter, langCode);
  painter.setPen(TQt::white);
  painter.drawText(0, 0, pix.width(), pix.height()-2, TQt::AlignCenter, langCode);
}

void KBConfig::drawDefaultPixmap(TQPixmap &pix, int group)
{
  pix.resize(FLAG_ICON_WIDTH, FLAG_ICON_HEIGHT);
  TQPainter painter(&pix);
  pix.fill();
  painter.drawText(0, 0, pix.width(), pix.height(),
    TQt::AlignHCenter | TQt::AlignVCenter, TQString::number(group+1));
}	

void KBConfig::checkKeysEnabled()
{
  m_keys->setEnabled(m_use_shortcuts);
  m_keys->updateConnections();
}


/** No descriptions */
/*void KBConfig::drawDefaultPixmaps(){
  TQPixmap pix(16, 16);
  TQPainter painter(&pix);

  for (unsigned int i = 0; i < m_groups.count(); i++) {
    if (m_groups[i]->getPixmap().isNull()) {
      pix.fill();
      painter.drawText(0, 0, pix.width(), pix.height(),
        TQt::AlignHCenter | TQt::AlignVCenter, TQString::number(i+1));
      m_groups[i]->setPixmap(pix);
    }
  }
}*/

/** No descriptions */
/*void KBConfig::loadConfiguredPixmaps(TDEConfig *config){
  TQString path;
  TQPixmap pix;
  config->setGroup(ICONS_SECTION);
  for (unsigned int i = 0; i < m_groups.count(); i++) {
    path = config->readEntry(entryForGroup(i));
    if (!path.isEmpty() && pix.load(path))
      m_groups[i]->setPixmap(pix);
  }
}*/

/** No descriptions */
/*void KBConfig::notifyChanged(){
  emit changed();
}*/


/*!
    \fn KBConfig::getXkbLayouts(const TQStringList &layouts)
 */
void KBConfig::getXkbLayouts(TQStringList &layouts)
{
#if HAVE_X11_EXTENSIONS_XKBRULES_H && HAVE_LIBXKBFILE
  XkbRF_VarDefsRec vardefs;
  int i;

  usleep(10000);
  if (XkbRF_GetNamesProp(tqt_xdisplay(), NULL, &vardefs)) {
    layouts = TQStringList::split(',', vardefs.layout, true);
    for (TQStringList::Iterator it = layouts.begin(); it != layouts.end(); ++it) {
      i = 0;
      while ((*it)[i] >= 'a' && (*it)[i] <= 'z') i++;
      *it = (*it).left(i);
    }
    if (vardefs.layout) XFree(vardefs.layout);
    if (vardefs.model) XFree(vardefs.model);
    if (vardefs.variant) XFree(vardefs.variant);
    if (vardefs.options) XFree(vardefs.options);
  }
#endif
}
