/***************************************************************************
                          emoticonmanager.cpp - handles emoticon themes for current account
                             -------------------
    begin                : Tue April 10 2007
    copyright            : (C) 2007 by Valerio Pilo
    email                : valerio@kmess.org
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   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 "emoticonmanager.h"

#include "emoticon.h"
#include "emoticontheme.h"
#include "currentaccount.h"
#include "kmessdebug.h"

#include <QColor>
#include <QStringList>


#ifdef KMESSDEBUG_EMOTICONS
  #define KMESSDEBUG_EMOTICONS_GENERAL
#endif



// Initialize the singleton instance to zero
EmoticonManager* EmoticonManager::instance_(0);



/**
 * Constructor
 */
EmoticonManager::EmoticonManager()
  : QObject(0)
  , customTheme_(new EmoticonTheme())
  , shouldSaveTheme_(false)
  , standardTheme_(new EmoticonTheme())
{
  setObjectName("EmoticonManager");

  // Create the default KMess standard theme, to always have a fallback theme
  if( ! standardTheme_->loadTheme( "KMess-new", false ) )
  {
    kWarning() << "Cannot create standard emoticon theme!";
  }
  else
  {
    // Change theme and connect its update signal
    connect( standardTheme_, SIGNAL( updated() ), this, SIGNAL( updated() ) );
  }

  // Connect the theme update signal to detect its changes
  connect( customTheme_, SIGNAL( updated() ), this, SIGNAL( updated() ) );
}



/**
 * Destructor
 */
EmoticonManager::~EmoticonManager()
{
  customTheme_->saveTheme();

  delete customTheme_;
  delete standardTheme_;
}



/**
 * Load an account's emoticon themes
 *
 * To load the custom emoticon theme we use the account's handle as the theme name, so every account
 * will get its very own emoticons.
 * Giving this method an account handle is only useful if we're loading the Account Settings for an account
 * different than the currently connected one.
 *
 * @param handle  Optional account email, if given will load the specified account's theme instead of the current one's
 */
void EmoticonManager::connected( QString handle )
{
  QString themeName;

  // The account will be needed in the disconnected() method, to decide whether to save the theme or not
  Account *account = CurrentAccount::instance();
  shouldSaveTheme_ = ! account->isGuestAccount();

  if( handle.isEmpty() )
  {
    // Update the standard emoticons with the user's preferred theme
    slotChangedEmoticonSettings();

    themeName = account->getHandle();
  }
  else
  {
    // Not updating the standard emoticons when loading an account's settings

    themeName = handle;
  }

#ifdef KMESSDEBUG_EMOTICONS_GENERAL
  kDebug() << "Loading custom emoticon theme of: " << themeName;
#endif

  // When this call fails, it'll give feedback about the cause. No need to do it here too.
  customTheme_->loadTheme( themeName, true );

  emit updated();
}



/**
 * Delete the instance of the emoticon manager
 */
void EmoticonManager::destroy()
{
  delete instance_;
  instance_ = 0;
}



/**
 * Unload the custom emoticon theme of the current account
 */
void EmoticonManager::disconnected()
{
#ifdef KMESSDEBUG_EMOTICONS_GENERAL
  kDebug() << "Destroying custom emoticon theme.";
#endif

  // Only save the theme when the account is not temporary
  if( shouldSaveTheme_ )
  {
    customTheme_->saveTheme();
  }
#ifdef KMESSDEBUG_EMOTICONS_GENERAL
  else
  {
    // NOTE If a guest user adds emoticons, there will be its folder with the relative images.
    // I don't delete nor move them, since it may be a registered account which, for once, has
    // been made not to remember changes.
    kDebug() << "Guest account - do not save the theme.";
  }
#endif
}



/**
 * Return the picture file names of all emoticons
 */
const QHash<QString,QString>& EmoticonManager::getFileNames( bool getCustomTheme )
{
  return getTheme( getCustomTheme )->getFileNames();
}



// Return a QHash to map shortcut to data hash
const QHash<QString,QString>& EmoticonManager::getHashes()
{
  return customTheme_->getHashes();
}



/**
 * Return the search pattern to find emoticons in an HTML document
 */
const QRegExp& EmoticonManager::getHtmlPattern( bool getCustomTheme )
{
  return getTheme( getCustomTheme )->getHtmlPattern();
}



/**
 * Return the HTML replacement codes for all emoticons in a theme
 */
const QHash<QString,QString>& EmoticonManager::getHtmlReplacements( bool small, bool getCustomTheme )
{
  return getTheme( getCustomTheme )->getHtmlReplacements( small );
}



/**
 * Return a QStringList of emoticons
 */
const QStringList& EmoticonManager::getList( bool getCustomTheme )
{
  return getTheme( getCustomTheme )->getList();
}



/**
 * Return the search pattern to find emoticons in a text
 */
const QRegExp& EmoticonManager::getPattern( bool getCustomTheme )
{
  return getTheme( getCustomTheme )->getPattern();
}



/**
 * Return one replacement code for the given emoticon
 */
QString EmoticonManager::getReplacement( const QString &code, bool small, bool getCustomTheme )
{
  return getTheme( getCustomTheme )->getReplacement( code, small );
}



/**
 * Return the replacement codes for all emoticons in a theme
 */
const QHash<QString,QString>& EmoticonManager::getReplacements( bool small, bool getCustomTheme )
{
  return getTheme( getCustomTheme )->getReplacements( small );
}



/**
 * Return a pointer to an emoticons theme
 */
EmoticonTheme *EmoticonManager::getTheme( bool getCustomTheme )
{
  if( getCustomTheme )
  {
    return customTheme_;
  }
  else
  {
    return standardTheme_;
  }
}



/**
 * Return the path where the theme's emoticons are located
 */
const QString& EmoticonManager::getThemePath( bool getCustomTheme )
{
  return getTheme( getCustomTheme )->getThemePath();
}



// Returns true if a custom emoticon has already been added
bool EmoticonManager::emoticonIsAdded( QString dataHash )
{
  return customTheme_->emoticonIsAdded( dataHash );
}



/**
 * Return a singleton instance of the emoticon manager
 */
EmoticonManager* EmoticonManager::instance()
{
  // If the instance is null, create a new emoticon manager and return that.
  if ( instance_ == 0 )
  {
    instance_ = new EmoticonManager();
  }
  return instance_;
}



/**
 * Replace the custom emoticon theme with a new one
 */
void EmoticonManager::replaceCustomTheme( EmoticonTheme *newTheme )
{
#ifdef KMESSDEBUG_EMOTICONS_GENERAL
  kDebug() << "Replacing custom emoticon theme with a new one.";
#endif

  delete customTheme_;
  customTheme_ = new EmoticonTheme( *newTheme );

  // Connect the update signal
  connect( customTheme_, SIGNAL( updated() ), this, SIGNAL( updated() ) );

  emit updated();
}



/**
 * The emoticon theme has changed, update our settings
 *
 * The theme won't be replaced with the emoticon definitions from the theme file,
 * since KMess is an MSN-only client and other clients don't support these special emoticons.
 * Instead, the current emoticon theme is kept, and the code tries to detect which
 * filenames the theme uses for certain emoticon codes.
 */
void EmoticonManager::slotChangedEmoticonSettings()
{
#ifdef KMESSDEBUG_EMOTICONS_GENERAL
  kDebug() << "Emoticon theme changed, updating emoticons.";
#endif

  // Find out which theme is used now.
  const QString &currentStyle = CurrentAccount::instance()->getEmoticonStyle();

  // And load it
  bool isLoaded = standardTheme_->loadTheme( currentStyle, false );

  // Warn if something has gone wrong
  if( ! isLoaded )
  {
    kWarning() << "Cannot set standard emoticon theme '" << currentStyle << "'.";
    return;
  }

  emit updated();
}



#include "emoticonmanager.moc"
