/***************************************************************************
 *   Copyright (C) 2007 by Anistratov Oleg                                 *
 *   ower@users.sourceforge.net                                            *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License version 2        *
 *   as published by the Free Software Foundation;                         *
 *                                                                         *
 *   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.                          *
 *                                                                         *
 ***************************************************************************/

#include "qchatsettings.h"
#include "globals.h"

#include <QObject>
#include <QApplication>

#include "userlisticonformat.h"
#include "messagefilter.h"
#include "option.h"

QChatSettings*      QChatSettings::m_currentSettings(0);
QChatSettings*      QChatSettings::m_defaultSettings(0);
QString             QChatSettings::m_profileName    ("");
QString             QChatSettings::m_settingsDir    ("");
QString             QChatSettings::m_loggingDir     ("");
QChatSettings::Mode QChatSettings::m_mode           (Serverless);
QHostAddress        QChatSettings::m_servBroadcast  (quint32(0));
QList<QHostAddress> QChatSettings::m_ipList;
QMap<QString, Option*> QChatSettings::m_generalOptions;

QChatSettings::QChatSettings():
  m_myMsgsColor     (Qt::red),
  m_sysMsgsColor    (Qt::gray),
  m_baseMsgColor    (Qt::black),
  m_nlMode          (0),
  m_nHistoryMsgs    (-1),
  m_historyReqTimeout(5000),
  m_smilesThemePath  (defaultSmilesDir()),
  m_smilesPolicy     (AlwaysUseSmilesFromSender),
  m_usersListRefreshInterval(60),
  m_usersListDeepRefreshInterval(600),
  m_toolbarIconsSize(24)
{
  m_iconFormat    = new UserListIconFormat;
  m_messageFilter = new MessageFilter;

  initOptions();

  createShortcut("SendMessage"          , QObject::tr("Send Message"),
                 QObject::tr("Chat")    , QKeySequence("Ctrl+Return"));

  createShortcut("NextMessage"          , QObject::tr("Scroll Message History Forward"),
                 QObject::tr("Chat")    , QKeySequence("Ctrl+Down"));

  createShortcut("PrevMessage"          , QObject::tr("Scroll Message History Backward"),
                 QObject::tr("Chat")    , QKeySequence("Ctrl+Up"));

  createShortcut("RefreshUsersList"     , QObject::tr("Refresh Users List"),
                 QObject::tr("Channels"), QKeySequence("F5"));
  // chatWgt
  createShortcut("ShowSmiles"           , QObject::tr("Show Smiles"),
                 QObject::tr("Chat")    , QKeySequence("Ctrl+S"));

  createShortcut("SingleMessagesHistory", QObject::tr("Single Messages History"),
                 QObject::tr("General") , QKeySequence("Ctrl+M"));

  createShortcut("EditUserDetails"      , QObject::tr("Edit User Details"),
                 QObject::tr("General") , QKeySequence("Ctrl+D"));

  createShortcut("ConfigureQChat"       , QObject::tr("Configure QChat"),
                 QObject::tr("General") , QKeySequence("Ctrl+P"));

  createShortcut("Quit"                 , QObject::tr("Quit"),
                 QObject::tr("General") , QKeySequence("Ctrl+Q"));

  createShortcut("AddChannel"           , QObject::tr("Add Channel"),
                 QObject::tr("Channels"), QKeySequence("Ctrl+N"));

  createShortcut("DelChannel"           , QObject::tr("Close Channel"),
                 QObject::tr("Channels"), QKeySequence("Ctrl+W"));

  createShortcut("AddProfile"           , QObject::tr("Add Profile"),
                 QObject::tr("Profiles"), QKeySequence("Ctrl+Shift+N"));

  createShortcut("DelProfile"           , QObject::tr("Delete Profile"),
                 QObject::tr("Profiles"), QKeySequence("Ctrl+Shift+D"));

  createShortcut("RenameProfile"        , QObject::tr("Rename Profile"),
                 QObject::tr("Profiles"), QKeySequence("Ctrl+Shift+R"));

  createShortcut("Hide2Tray"            , QObject::tr("Hide to Tray"),
                 QObject::tr("General") , QKeySequence("Escape"));

  createShortcut("BroadcastMessage"     , QObject::tr("Send Broadcast Message"),
                 QObject::tr("Chat")    , QKeySequence("Alt+B"));

  //

  createShortcut("NextNewMessage"       , QObject::tr("Next New Message"),
                 QObject::tr("Messages"), QKeySequence(""));

  createShortcut("PrevNewMessage"       , QObject::tr("Previous New Message"),
                 QObject::tr("Messages"), QKeySequence(""));

  createShortcut("NextOpenedMessage"    , QObject::tr("Next Opened Message"),
                 QObject::tr("Messages"), QKeySequence(""));

  createShortcut("PrevOpenedMessage"    , QObject::tr("Previous Opened Message"),
                 QObject::tr("Messages"), QKeySequence(""));

  createShortcut("CloseAllNewMessages"  , QObject::tr("Close All New Messages"),
                 QObject::tr("Messages"), QKeySequence(""));

  createShortcut("CloseAllOpenedMessages", QObject::tr("Close All Opened Messages"),
                 QObject::tr("Messages") , QKeySequence(""));

}

void QChatSettings::setStatusDescription(const QString & descr, int status)
{
  Q_ASSERT(status >=0 && status < 6 || status == Globals::INVISIBLE);

  if(status != Globals::INVISIBLE)
    m_statusDescription[status] = descr;
}

const QString & QChatSettings::statusDescription(int status) const
{
  Q_ASSERT(status >=0 && status < 6 || status == Globals::INVISIBLE);

  if(status == Globals::INVISIBLE)
    return m_statusDescription[0];

  return m_statusDescription[status];
}

void QChatSettings::appendStatusDescription(const QString & value)
{
 if(!value.isEmpty() && !m_statusDescriptions.contains(value))
 {
   m_statusDescriptions.removeAll(value);
   m_statusDescriptions.prepend(value);
 }
}

QString QChatSettings::defaultSmilesDir()
{
  QList<QDir> dirs;
  QString res;
  QDir dir;

  dirs.append(QDir(QChatSettings::settings()->settingsDir() + "/smiles"));

#if defined(Q_OS_LINUX)
  dir.setPath(QApplication::applicationDirPath());
  if(dir.cd("../share/qchat/emoticons"))
    dirs.append(dir);
#else
  dirs.append(QDir(QApplication::applicationDirPath() + "/emoticons"));
#endif

  res = defaultSmilesDir(dirs);

#if defined(Q_OS_LINUX)
  if(res.isEmpty())
  {
    dirs.clear();
    dirs.append(QDir(QDir::homePath() + "/.kde/share/emoticons"));

    dir.setPath(QApplication::applicationDirPath());
    if(dir.cd("../share/emoticons"))
      dirs.append(dir);

    res = defaultSmilesDir(dirs);
  }
#endif

  return res;
}

QString QChatSettings::defaultSmilesDir(QList<QDir> dirs)
{
  QString res;

  foreach(QDir dir, dirs)
    if(dir.exists())
      foreach(QString em_dir, dir.entryList())
      {
        if(em_dir == "." || em_dir == ".." || QFileInfo(dir.absolutePath() + "/" + em_dir).isFile() ||
           !QFile(dir.absolutePath() + "/" + em_dir + "/emoticons.xml").exists())
          continue;

        if(res.isEmpty())
          res = dir.absolutePath() + "/" + em_dir + "/";

        if(!em_dir.compare("default", Qt::CaseInsensitive))
          return dir.absolutePath() + "/" + em_dir + "/";

        else if(em_dir.contains("default", Qt::CaseInsensitive))
          res = dir.absolutePath() + "/" + em_dir + "/";
      }

  return res;
}

void QChatSettings::createShortcut(const QString & name, const QString & displayName, const QString & group, const QKeySequence & seq)
{
  QStringList list;

  list.append(displayName);
  list.append(group);

  setShortcut(name, seq);
  m_shortcutsInfo.insert(name, list);
}

void QChatSettings::initOptions()
{
  // bool options
  m_options.insert("UseAnimatedSmiles"                , new Option(true , "Preferences", Option::bool_opt));
  m_options.insert("ColorWholeMessage"                , new Option(false, "Preferences", Option::bool_opt));
  m_options.insert("ColorWholeSystemMessage"          , new Option(true , "Preferences", Option::bool_opt));
  m_options.insert("ActivateOnMessageIn"              , new Option(false, "Preferences", Option::bool_opt));
  m_options.insert("SoundOnMessageIn"                 , new Option(false, "Preferences", Option::bool_opt));

  m_options.insert("IsExecuteCommandOnIncomingMessage", new Option(false, "Preferences", Option::bool_opt));
  m_options.insert("WarningAboutHidingInTray"         , new Option(true , "Warnings"   , Option::bool_opt));
  m_options.insert("SoundOnMessageIn"                 , new Option(false, "Preferences", Option::bool_opt));

  // int options
  m_options.insert("LastServersNum" , new Option(10, "Preferences", Option::int_opt));
  m_options.insert("LastLoginsNum"  , new Option(10, "Preferences", Option::int_opt));

  // QHostAddress options

  // string options
  m_options.insert("DisplayMessagesFormat" ,
  new Option("%time%hh:mm:ss%time% | [[%user@%comp]] : ", "Preferences", Option::string_opt));

  m_options.insert("NLFormat"              ,
  new Option(QObject::tr("Now Listening to : %t by %a on %b"), "NowListening", Option::string_opt));

  m_options.insert("LastServers" , new Option("", "Preferences", Option::string_opt));
  m_options.insert("LastLogins"  , new Option("", "Preferences", Option::string_opt));

}

void QChatSettings::initGeneralOptions()
{
  m_defaultSettings = new QChatSettings;

  // bool options
  m_generalOptions.insert("AllowDifferentPorts", new Option(false, "Network", Option::bool_opt));
  m_generalOptions.insert("UseIPList"          , new Option(false, "Network", Option::bool_opt));
  m_generalOptions.insert("UseCompression"     , new Option(false, "Network", Option::bool_opt));
  m_generalOptions.insert("UseCompression"     , new Option(false, "Network", Option::bool_opt));
  m_generalOptions.insert("UseCompression"     , new Option(false, "Network", Option::bool_opt));

  // int options
  m_generalOptions.insert("InputPort"          , new Option(61108, "Network", Option::int_opt));
  m_generalOptions.insert("OutputPort"         , new Option(61108, "Network", Option::int_opt));
  m_generalOptions.insert("ProtocolVersion"    , new Option(4    , "Network", Option::int_opt));

  // QHostAddress options
  m_generalOptions.insert("IP"                 , new Option(0x7f000001, "Network", Option::HostAddress_opt));
  m_generalOptions.insert("Broadcast"          , new Option(0xffffffff, "Network", Option::HostAddress_opt));
  m_generalOptions.insert("CustomIP"           , new Option(0x7f000001, "Network", Option::HostAddress_opt));
  m_generalOptions.insert("CustomBroadcast"    , new Option(0xffffffff, "Network", Option::HostAddress_opt));

  // string options
}

void QChatSettings::setOption(const QString & opt, QVariant val)
{
  Option* option;

  Q_ASSERT(m_options.find(opt) != m_options.end() || m_generalOptions.find(opt) != m_generalOptions.end());

  option = m_generalOptions.find(opt) != m_generalOptions.end() ? m_generalOptions[opt] : m_options[opt];

  option->setOption(val);
}

bool QChatSettings::boolOption(const QString & opt) const
{
  Option* option;

  Q_ASSERT(m_options.find(opt) != m_options.end() || m_generalOptions.find(opt) != m_generalOptions.end());

  option = m_generalOptions.find(opt) != m_generalOptions.end() ? m_generalOptions[opt] : m_options[opt];

  Q_ASSERT(option->type() == Option::bool_opt || m_options[opt]->type() == Option::bool_opt);

  return option->option().toBool();
}

qint64 QChatSettings::intOption(const QString & opt) const
{
  Option* option;

  Q_ASSERT(m_options.find(opt) != m_options.end() || m_generalOptions.find(opt) != m_generalOptions.end());

  option = m_generalOptions.find(opt) != m_generalOptions.end() ? m_generalOptions[opt] : m_options[opt];

  Q_ASSERT(option->type() == Option::int_opt || m_options[opt]->type() == Option::int_opt);

  return option->option().toInt();
}

QString QChatSettings::strOption(const QString & opt) const
{
  Option* option;

  Q_ASSERT(m_options.find(opt) != m_options.end() || m_generalOptions.find(opt) != m_generalOptions.end());

  option = m_generalOptions.find(opt) != m_generalOptions.end() ? m_generalOptions[opt] : m_options[opt];

  Q_ASSERT(option->type() == Option::string_opt || m_options[opt]->type() == Option::string_opt);

  return option->option().toString();
}

void QChatSettings::saveOptions(QSettings* settings)
{
  save(settings, m_options);
}

void QChatSettings::saveGeneralOptions(QSettings* settings)
{
  save(settings, m_generalOptions);
}

void QChatSettings::loadGeneralOptions(QSettings* settings)
{
  load(settings, m_generalOptions);
}

void QChatSettings::loadOptions(QSettings* settings)
{
  load(settings, m_options);
}

void QChatSettings::save(QSettings* settings, QMap< QString, Option* > options)
{
  QStringList sections;
  int nsections = 0;

  QMapIterator<QString, Option*> op(options);
  while (op.hasNext())
  {
    op.next();

    sections = op.value()->section().split("/");

    nsections = 0;
    foreach(QString s, sections)
    {
      settings->beginGroup(s);
      nsections++;
    }

    settings->setValue(op.key(), op.value()->option());

    for(int i = 0; i < nsections; i++)
      settings->endGroup();
  }
}

void QChatSettings::load(QSettings* settings, QMap< QString, Option* >& options)
{
  QStringList sections;
  int nsections = 0;

  QMapIterator<QString, Option*> op(options);
  while (op.hasNext())
  {
    op.next();

    sections = op.value()->section().split("/");

    nsections = 0;
    foreach(QString s, sections)
    {
      settings->beginGroup(s);
      nsections++;
    }

    op.value()->setOption(settings->value(op.key(), op.value()->option()));

    for(int i = 0; i < nsections; i++)
      settings->endGroup();
  }
}

QVariant QChatSettings::option(const QString& opt) const
{
  Option* option;

  Q_ASSERT(m_options.find(opt) != m_options.end() || m_generalOptions.find(opt) != m_generalOptions.end());

  option = m_generalOptions.find(opt) != m_generalOptions.end() ? m_generalOptions[opt] : m_options[opt];

  Q_ASSERT(option);

  return option->option();
}

QChatSettings * QChatSettings::settings()
{
 return m_currentSettings ? m_currentSettings : m_defaultSettings;
}

QHostAddress QChatSettings::realBroadcast()
{
  return settings()->hostAddressOption("Broadcast");
}

QHostAddress QChatSettings::hostAddressOption(const QString & opt) const
{
  Option* option;
  QHostAddress addr;

  Q_ASSERT(m_options.find(opt) != m_options.end() || m_generalOptions.find(opt) != m_generalOptions.end());

  option = m_generalOptions.find(opt) != m_generalOptions.end() ? m_generalOptions[opt] : m_options[opt];

  Q_ASSERT(option->type() == Option::HostAddress_opt || m_options[opt]->type() == Option::HostAddress_opt);


  if(!addr.setAddress(option->option().toString()))
    addr.setAddress(option->option().toInt());

  return addr;
}

QHostAddress QChatSettings::broadcast()
{
  return ((m_mode == Server) ? m_servBroadcast : QHostAddress(settings()->option("Broadcast").toString()));
}
