/***************************************************************************
 *   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 "preferencesdlg.h"
#include "globals.h"

#include <QSpacerItem>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QHostAddress>
#include <QStringList>
#include <QFile>
#include <QCoreApplication>

#include "qchatsettings.h"
#include "colorlabel.h"
#include "pluginsinterfaces.h"
#include "pluginmanager.h"
#include "plugin.h"
#include "userlisticonconfigurewgt.h"
#include "iplisteditor.h"
#include "chatcore.h"
#include "chatwgt.h"
#include "messagefiltereditor.h"

PreferencesDlg::PreferencesDlg(QWidget *parent)
 : QDialog(parent)
{
  m_profileName = "";
  m_edited      = false;

  createWidgets();

  QVBoxLayout* btns_box          = new QVBoxLayout(0);
  QVBoxLayout* msgs_sect_vbox    = new QVBoxLayout(0);
  QGridLayout* grid              = new QGridLayout(this);

  QGridLayout* colors_grid       = new QGridLayout(m_colorsGrbx);
  QGridLayout* network_grid      = new QGridLayout(m_networkGrbx);
  QGridLayout* misc_grid         = new QGridLayout(m_miscGrbx);
  QGridLayout* nl_grid           = new QGridLayout(m_nowListeningGrbx);
  QGridLayout* smiles_grid       = new QGridLayout(m_smilesThemesGrbx);
  QGridLayout* users_list_grid   = new QGridLayout(m_usersListGrbx);
  QGridLayout* style_sheets_grid = new QGridLayout(m_styleSheetsGrbx);
  QGridLayout* plugins_grid      = new QGridLayout(m_pluginsGrbx);
  QGridLayout* iconFormat_grid   = new QGridLayout(m_iconFormatGrbx);
  QGridLayout* filtration_grid   = new QGridLayout(m_filtrationGrbx);
  QGridLayout* protocols_grid    = new QGridLayout(m_protocolsGrbx);

  m_iconFormatWgt = new UserListIconConfigureWgt(this, *QChatSettings::settings()->iconFormat());
  connect(m_iconFormatWgt, SIGNAL(formatChanged(UserListIconFormat)), this, SIGNAL(formatChanged(UserListIconFormat)));

  // Setting up group boxes
  //********************************************
  // Colors
  m_myColor    ->setMinimumWidth (100); m_myColor    ->setMaximumHeight(25);
  m_sysColor   ->setMinimumWidth (100); m_sysColor   ->setMaximumHeight(25);
  m_baseColor  ->setMinimumWidth (100); m_baseColor  ->setMaximumHeight(25);
  m_myColor    ->setFrameStyle(QFrame::StyledPanel | QFrame::Plain);
  m_sysColor   ->setFrameStyle(QFrame::StyledPanel | QFrame::Plain);
  m_baseColor  ->setFrameStyle(QFrame::StyledPanel | QFrame::Plain);

  colors_grid->addWidget(m_myColorLab          , 0, 0);
  colors_grid->addWidget(m_myColor             , 0, 1);
  colors_grid->addWidget(m_sysColorLab         , 1, 0);
  colors_grid->addWidget(m_sysColor            , 1, 1);

  // TODO fully remove baseColor settings
  m_baseColorLab->hide();
  m_baseColor   ->hide();
//   colors_grid->addWidget(m_baseColorLab        , 2, 0);
//   colors_grid->addWidget(m_baseColor           , 2, 1);

  colors_grid->addWidget(m_colorWholeMsgChbx   , 3, 0, 1, 2);
  colors_grid->addWidget(m_colorWholeSysMsgChbx, 4, 0, 1, 2);
  colors_grid->setColumnStretch(1, 1);

  // Network
  m_portOutSpbx->setMaximum(65535);
  m_portInSpbx ->setMaximum(65535);
  m_applyBtn   ->setEnabled(false);

  m_protocolsBgrp->addButton(m_protocolV3Rbtn);
  m_protocolsBgrp->addButton(m_protocolV4Rbtn);

  protocols_grid->addWidget(m_protocolV3Rbtn);
  protocols_grid->addWidget(m_protocolV4Rbtn);


  network_grid->addWidget(m_networkIfLab , 0, 0);
  network_grid->addWidget(m_networkIfCmbx, 0, 1);
  network_grid->addWidget(m_ipLab        , 1, 0);
  network_grid->addWidget(m_ipEdit       , 1, 1);
  network_grid->addWidget(m_broadcastLab , 2, 0);
  network_grid->addWidget(m_broadcastEdit, 2, 1);
  network_grid->addWidget(m_portInLab    , 3, 0);
  network_grid->addWidget(m_portInSpbx   , 3, 1);
  network_grid->addWidget(m_portOutLab   , 4, 0);
  network_grid->addWidget(m_portOutSpbx  , 4, 1);
  network_grid->addWidget(m_ipListEditor , 5, 0, 1, 2);
  network_grid->addWidget(m_useCompressionChbx, 6, 0, 1, 2);

  network_grid->addWidget(m_protocolsGrbx, 7, 0, 1, 2);

  network_grid->setRowStretch(5, 1);

  //Now Listening
  nl_grid->addWidget(m_nlInStatusChbx);
  nl_grid->addWidget(m_nlWithMessageChbx);
  nl_grid->addWidget(m_nlFormatLab);
  nl_grid->addWidget(m_nlFormatEdit);

  // Misc
  misc_grid->addWidget(m_activateOnMsgInChbx, 0, 0);
  misc_grid->addWidget(m_isCommandOnIncomingChbx , 1, 0);
  misc_grid->addWidget(m_commandOnIncomingEdit, 2, 0);

  //Smiles
  smiles_grid->addWidget(m_smilesThemeChooser   , 0, 0, 1, 2);
  smiles_grid->addWidget(m_smilesPolicyLab      , 1, 0);
  smiles_grid->addWidget(m_smilesPolicyCmbx     , 1, 1);
  smiles_grid->addWidget(m_useAnimatedSmilesChbx, 2, 0, 1, 2);

  // Users List
  users_list_grid->addWidget(m_ulRefreshIntervalLab     , 0, 0);
  users_list_grid->addWidget(m_ulRefreshIntervalSpbx    , 0, 1);

  iconFormat_grid->addWidget(m_iconFormatWgt            , 0, 0);
//   users_list_grid->addWidget(m_ulDeepRefreshIntervalLab , 1, 0);
//   users_list_grid->addWidget(m_ulDeepRefreshIntervalSpbx, 1, 1);

  // Style Sheets
  style_sheets_grid->addWidget(m_styleSheetsChooser);

  // Plugins
  plugins_grid->addWidget(m_pluginsChooser     , 0, 0, 1, 2);
  plugins_grid->addWidget(m_loadUnloadPluginBtn, 1, 1);

  plugins_grid->setRowStretch(0, 1);

  // Filtration
  filtration_grid->addWidget(m_messageFilterEditor);

  //********************************************
  btns_box->addWidget(m_okBtn     );
  btns_box->addWidget(m_applyBtn  );
  btns_box->addWidget(m_cancelBtn );

  msgs_sect_vbox->addWidget(m_colorsGrbx);
  msgs_sect_vbox->addWidget(m_miscGrbx);

  grid->addWidget(m_sectionsChooser, 0, 0, 2, 1);
  grid->addWidget(m_sections       , 0, 1, 2, 2);
  grid->addLayout(btns_box         , 0, 3);

  grid->setColumnStretch(1, 1);

  setupSections();

  setupConnections();

  retranslate();

  resize(400, 200);
}
//\*****************************************************************************
PreferencesDlg::~PreferencesDlg()
{
  qDebug("[~PreferencesDlg]");
}

void PreferencesDlg::slot_setMsgColorMode   (int mode)
{QChatSettings::settings()->setOption("ColorWholeMessage", (mode));}

void PreferencesDlg::slot_setSysMsgColorMode(int mode)
{QChatSettings::settings()->setOption("ColorWholeSystemMessage", (mode));}

void PreferencesDlg::slot_setActivateOnMsgIn(int mode)
{QChatSettings::settings()->setOption("ActivateOnMessageIn", (mode));}

void PreferencesDlg::slot_setSoundOnMsgIn   (int mode)
{QChatSettings::settings()->setOption("SoundOnMessageIn", (mode));}

void PreferencesDlg::slot_setNlWithMessage  (int mode)
{QChatSettings::settings()->setNlMode(m_nlInStatusChbx->isChecked() * 2 | (mode == Qt::Checked));}

void PreferencesDlg::slot_setNlInStatus     (int mode)
{QChatSettings::settings()->setNlMode(m_nlWithMessageChbx->isChecked () | (mode == Qt::Checked) * 2);}

void PreferencesDlg::slot_setExecuteCommandMode(int mode)
{
  mode = (mode == Qt::Unchecked ? 0 : 1);
  QChatSettings::settings()->setOption("IsExecuteCommandOnIncomingMessage", (mode));
  m_commandOnIncomingEdit->setEnabled(mode);
}
//\*****************************************************************************
void PreferencesDlg::init()
{
  QChatSettings* settings = QChatSettings::settings();

  if(!QChatSettings::settings()->boolOption("AllowDifferentPorts"))
  {
    m_portOutLab ->hide();
    m_portOutSpbx->hide();
    m_portInLab->setText(tr("Input/Output Port : "));
    connect(m_portInSpbx, SIGNAL(valueChanged(int)), m_portOutSpbx, SLOT(setValue(int)));
  }
  else
  {
    m_portOutLab ->show();
    m_portOutSpbx->show();
    m_portInLab->setText(tr("Input Port : "));
    disconnect(m_portInSpbx, SIGNAL(valueChanged(int)), m_portOutSpbx, SLOT(setValue(int)));
  }

  m_myColor  ->setColor(settings->myColor());
  m_sysColor ->setColor(settings->sysColor());
  m_baseColor->setColor(settings->baseColor());

  // CheckBoxes:
  if(QChatSettings::settings()->boolOption("ColorWholeMessage"))
    m_colorWholeMsgChbx      ->setCheckState(Qt::Checked);
  else
    m_colorWholeMsgChbx      ->setCheckState(Qt::Unchecked);

  if(QChatSettings::settings()->boolOption("ColorWholeSystemMessage"))
    m_colorWholeSysMsgChbx   ->setCheckState(Qt::Checked);
  else
    m_colorWholeSysMsgChbx   ->setCheckState(Qt::Unchecked);

  slot_setExecuteCommandMode(settings->boolOption("IsExecuteCommandOnIncomingMessage") ? Qt::Checked : Qt::Unchecked);
  m_isCommandOnIncomingChbx->setCheckState(settings->boolOption("IsExecuteCommandOnIncomingMessage") ? Qt::Checked : Qt::Unchecked);

  m_useCompressionChbx->setCheckState(QChatSettings::settings()->boolOption("UseCompression") ? Qt::Checked : Qt::Unchecked);

  m_useAnimatedSmilesChbx->setCheckState(settings->boolOption("UseAnimatedSmiles") ? Qt::Checked : Qt::Unchecked);

  m_smilesPolicyCmbx->setCurrentIndex((int)settings->smilesPolicy());

  // NowListening
  int mode = settings->nlMode();
  if(mode & 1)
    m_nlWithMessageChbx->setCheckState(Qt::Checked);
  else
    m_nlWithMessageChbx->setCheckState(Qt::Unchecked);

  if(mode & 2)
    m_nlInStatusChbx->setCheckState(Qt::Checked);
  else
    m_nlInStatusChbx->setCheckState(Qt::Unchecked);

  m_nlFormatEdit->setText(settings->strOption("NLFormat"));

  m_oldPortIn   = settings->intOption("InputPort");
  m_portOutSpbx->setValue(settings->intOption("OutputPort"));
  m_portInSpbx ->setValue(m_oldPortIn);
  m_ipEdit     ->setText (settings->hostAddressOption("IP").toString());

  if(settings->boolOption("ActivateOnMessageIn"))
    m_activateOnMsgInChbx   ->setCheckState(Qt::Checked);
  else
    m_activateOnMsgInChbx   ->setCheckState(Qt::Unchecked);
  if(settings->boolOption("SoundOnMessageIn"))
    m_soundOnMsgInChbx   ->setCheckState(Qt::Checked);
  else
    m_soundOnMsgInChbx   ->setCheckState(Qt::Unchecked);

  //*************************
  m_broadcastEdit->clear();

  QString str       = m_ipEdit->text();
  QString broadcast = QHostAddress(settings->realBroadcast()).toString();
  QStringList list  = str.split(".");

  m_broadcastEdit->setText(broadcast);

  reloadNetworkIfs();
  //*************************

  m_commandOnIncomingEdit    ->setText (settings->executeCommandOnIncomingMsg());
  m_displayMsgFmtEdit        ->setText (settings->strOption("DisplayMessagesFormat"));
  m_msgsHistoryIntervalSpbx  ->setValue(settings->historyReqTimeout());
  m_msgsHistoryNumSpbx       ->setValue(settings->nHistoryMsgs());
  m_ulRefreshIntervalSpbx    ->setValue(settings->usersListRefreshInterval());
  m_ulDeepRefreshIntervalSpbx->setValue(settings->usersListDeepRefreshInterval());

  m_commandOnIncomingEdit->home(0);
  m_displayMsgFmtEdit->home(0);
  m_nlFormatEdit->home(0);

  m_profileName = QChatSettings::profileName();
  m_edited = false;
  m_applyBtn->setEnabled(false);

  m_messageFilterEditor->setFilter(settings->messageFilter());

  if(settings->intOption("ProtocolVersion") == 3)
    m_protocolV3Rbtn->setChecked(true);
  else if(settings->intOption("ProtocolVersion") == 4)
    m_protocolV4Rbtn->setChecked(true);

  if(settings->mode() == QChatSettings::Server)
  {
    m_protocolV4Rbtn->setEnabled(false);
    m_protocolV3Rbtn->setEnabled(false);

    m_protocolV4Rbtn->setChecked(true);
  }
  else
  {
    m_protocolV4Rbtn->setEnabled(true);
    m_protocolV3Rbtn->setEnabled(true);
  }

  setWindowTitle(tr("Preferences [Profile: ") + m_profileName + "]");
}
//\*****************************************************************************
void PreferencesDlg::slot_chooseColor()
{
  QColor color = QColorDialog::getColor(((ColorLabel*)sender())->color(), this);

  if(color.isValid())
  {
    ((ColorLabel*)sender())->setColor(color);
    edited();
  }
}
//\*****************************************************************************
void PreferencesDlg::edited()
{
  m_edited = true;
  m_applyBtn->setEnabled(true);
}
//\*****************************************************************************
void PreferencesDlg::slot_setPrefs()
{
  int idx;

  if(QChatSettings::profileName() == m_profileName)
  {

    switch(Sections(m_sectionsChooser->currentRow()))
    {
      case Network :
        break;

      case Messages :
        break;

      case Filtration :
        break;

      case Smiles :
        idx = m_smilesThemeChooser->currentRow();
        if(idx >= 0)
          emit wantChangeSmileTheme(m_smilesThemes[idx]);
        break;

      case Misc :
        break;

      case StyleSheets :
        idx = m_styleSheetsChooser->currentRow();
        if(idx >= 0)
          emit styleSheetChanged(m_styleSheets[idx]);
        break;

      case Plugins :
        break;

      case LastSection :
        break;
    }

    QChatSettings::settings()->setMyColor  (m_myColor    ->color());
    QChatSettings::settings()->setSysColor (m_sysColor   ->color());
    QChatSettings::settings()->setBaseColor(m_baseColor  ->color());
    QChatSettings::settings()->setOption   ("OutputPort", m_portOutSpbx->value());

    QString str = "";

    if(!m_networkIfCmbx->currentIndex())
    {
      str = m_broadcastEdit->text();
      if(!QHostAddress(str).isNull())
        QChatSettings::settings()->setOption("CustomBroadcast", str);

      str = m_ipEdit->text();
      if(!QHostAddress(str).isNull())
        QChatSettings::settings()->setOption("CustomIP", str);
    }

    str = m_broadcastEdit->text();
    if(!QHostAddress(str).isNull())
      QChatSettings::settings()->setOption("Broadcast", str);

    str = m_ipEdit->text();
    if(!QHostAddress(str).toString().isEmpty())
      QChatSettings::settings()->setOption("IP", str);

    emit ipTextChanged(str);

    if(QChatSettings::settings()->intOption("InputPort") != (int)m_portInSpbx->value())
      emit portChanged(m_portInSpbx->value());

    QChatSettings::settings()->setExecuteCommandOnIncomingMsg(m_commandOnIncomingEdit->text());

    QChatSettings::settings()->setOption("NLFormat", m_nlFormatEdit->text());
    QChatSettings::settings()->setOption("DisplayMessagesFormat", m_displayMsgFmtEdit->text());

    QChatSettings::settings()->setHistoryReqTimeout(m_msgsHistoryIntervalSpbx->value());
    QChatSettings::settings()->setNHistoryMsgs(m_msgsHistoryNumSpbx->value());

    QChatSettings::settings()->setUsersListRefreshInterval(m_ulRefreshIntervalSpbx->value());
    QChatSettings::settings()->setUsersListDeepRefreshInterval(m_ulDeepRefreshIntervalSpbx->value());

    emit ulRefreshIntervalChanged(m_ulRefreshIntervalSpbx->value());
    emit ulDeepRefreshIntervalChanged(m_ulDeepRefreshIntervalSpbx->value());

    QChatSettings::settings()->setOption("UseAnimatedSmiles", m_useAnimatedSmilesChbx->checkState() == Qt::Checked);
    QChatSettings::settings()->setSmilesPolicy(m_smilesPolicyCmbx->currentIndex());

    emit useAnimatedSmiles(m_useAnimatedSmilesChbx->checkState() == Qt::Checked);
  }

  m_edited = false;
  m_applyBtn->setEnabled(false);
}
//\*****************************************************************************
void PreferencesDlg::slot_cancel()
{
  m_edited = false;
  m_applyBtn->setEnabled(false);
  reject();
}
//\*****************************************************************************
void PreferencesDlg::slot_validateIp(const QString & str)
{
  if((QHostAddress(str).isNull()))
    return;

  edited();
}

void PreferencesDlg::retranslate()
{
  m_myColorLab           ->setText(tr("Color of My Messages : "));
  m_sysColorLab          ->setText(tr("Color of System Messages : "));
  m_baseColorLab         ->setText(tr("Base Color for Messages : "));
  m_ipLab                ->setText(tr("IP Address : "));
  m_broadcastLab         ->setText(tr("Broadcast Address : "));
  m_nlFormatLab          ->setText(tr("Now Listening string : \n(%t - Track, %a - Artist, %b - alBum)"));

  m_colorsGrbx           ->setTitle(tr("&Colors"));
  m_networkGrbx          ->setTitle(tr("&Network"));
  m_miscGrbx             ->setTitle(tr("&Misc"));
  m_nowListeningGrbx     ->setTitle(tr("Now &Listening (from Amarok1)"));
  m_smilesThemesGrbx     ->setTitle(tr("Choose smiles theme:"));
  m_usersListGrbx        ->setTitle(tr("Users List"));
  m_styleSheetsGrbx      ->setTitle(tr("Choose Style Sheet :"));
  m_pluginsGrbx          ->setTitle(tr("Available Plugins :"));
  m_iconFormatGrbx       ->setTitle(tr("Users List Icon Format :"));
  m_filtrationGrbx       ->setTitle(tr("Filtration rules :"));
  m_protocolsGrbx        ->setTitle(tr("Choose protocol version :"));

  m_okBtn                ->setText (tr("&OK"));
  m_cancelBtn            ->setText (tr("&Cancel"));
  m_applyBtn             ->setText (tr("&Apply"));

  m_colorWholeMsgChbx    ->setText (tr("Color Whole Message"));
  m_colorWholeSysMsgChbx ->setText (tr("Color Whole System Message"));
  m_activateOnMsgInChbx  ->setText (tr("Activate Window on Incomin Messages"));
  m_soundOnMsgInChbx     ->setText (tr("Play Sound on Incomig Messages"));
  m_nlWithMessageChbx    ->setText (tr("Send 'Now Listening' with messages"));
  m_nlInStatusChbx       ->setText (tr("Set 'Now Listening' in status description"));

  m_portOutLab           ->setText (tr("Output Port : "));
  m_portInLab            ->setText (tr("Input Port : "));

  m_profileSection       ->setText(tr("Profile"));
  m_miscSection          ->setText(tr("Misc"));
  m_messagesSection      ->setText(tr("Messages"));
  m_networkSection       ->setText(tr("Network"));
  m_smilesSection        ->setText(tr("Smiles"));
  m_styleSheetsSection   ->setText(tr("Style Sheets"));
  m_pluginsSection       ->setText(tr("Plugins"));
  m_filtrationSection    ->setText(tr("Filtration"));

  m_isCommandOnIncomingChbx ->setText(tr("Execute command on incoming messages :"));
  m_displayMsgFmtLab        ->setText(tr("Messages display format : "));
  m_msgsHistoryIntervalLab  ->setText(tr("Messages history request interval : "));
  m_msgsHistoryNumLab       ->setText(tr("Maximum number of messages in history answer : "));
  m_ulRefreshIntervalLab    ->setText(tr("Refresh Interval : "));
  m_ulDeepRefreshIntervalLab->setText(tr("Deep Refresh Interval : "));

  m_networkIfLab            ->setText(tr("Choose Network Settings :"));

  m_msgsHistoryIntervalSpbx  ->setSuffix(tr(" ms", "milliseconds"));
  m_ulRefreshIntervalSpbx    ->setSuffix(tr(" s", "seconds"));
  m_ulDeepRefreshIntervalSpbx->setSuffix(tr(" s", "seconds"));

  m_loadUnloadPluginBtn      ->setText(tr("Load Plugin"));
  m_useCompressionChbx       ->setText(tr("Use Compression"));

  m_useAnimatedSmilesChbx    ->setText(tr("Use Animated Smiles"));
  m_smilesPolicyLab          ->setText(tr("Smiles Policy :"));

  int idx = m_smilesPolicyCmbx->currentIndex();

  m_smilesPolicyCmbx->clear();
  m_smilesPolicyCmbx->addItem(tr("Don't use Graphic Smiles"));
  m_smilesPolicyCmbx->addItem(tr("Use only smiles from local theme"));
  m_smilesPolicyCmbx->addItem(tr("Use smiles from sender"));
  m_smilesPolicyCmbx->addItem(tr("Always use smiles from sender"));

  m_smilesPolicyCmbx->setCurrentIndex(idx);

  m_protocolV3Rbtn->setText(tr("Old protocol"));
  m_protocolV4Rbtn->setText(tr("New protocol"));

  setWindowTitle(tr("Preferences"));
}

void PreferencesDlg::createWidgets()
{
  m_messageFilterEditor       = new MessageFilterEditor(this);

  m_colorsGrbx                = new QGroupBox(this);
  m_networkGrbx               = new QGroupBox(this);
  m_miscGrbx                  = new QGroupBox(this);
  m_nowListeningGrbx          = new QGroupBox(this);
  m_smilesThemesGrbx          = new QGroupBox(this);
  m_usersListGrbx             = new QGroupBox(this);
  m_styleSheetsGrbx           = new QGroupBox(this);
  m_pluginsGrbx               = new QGroupBox(this);
  m_iconFormatGrbx            = new QGroupBox(this);
  m_filtrationGrbx            = new QGroupBox(this);
  m_protocolsGrbx             = new QGroupBox(this);

  m_sectionsChooser           = new QListWidget(this);
  m_smilesThemeChooser        = new QListWidget(this);
  m_styleSheetsChooser        = new QListWidget(this);
  m_pluginsChooser            = new QListWidget(this);

  m_networkSection            = new QListWidgetItem();
  m_messagesSection           = new QListWidgetItem();
  m_smilesSection             = new QListWidgetItem();
  m_miscSection               = new QListWidgetItem();
  m_profileSection            = new QListWidgetItem();
  m_styleSheetsSection        = new QListWidgetItem();
  m_pluginsSection            = new QListWidgetItem();
  m_filtrationSection         = new QListWidgetItem();

  m_sections                  = new QStackedWidget(this);

  m_myColor                   = new ColorLabel(this, QChatSettings::settings()->myColor());
  m_sysColor                  = new ColorLabel(this, QChatSettings::settings()->sysColor());
  m_baseColor                 = new ColorLabel(this, QChatSettings::settings()->baseColor());
  m_okBtn                     = new QPushButton(this);
  m_cancelBtn                 = new QPushButton(this);
  m_applyBtn                  = new QPushButton(this);
  m_ipEdit                    = new QLineEdit(this);
  m_broadcastEdit             = new QLineEdit(this);
  m_portOutSpbx               = new QSpinBox (this);
  m_portInSpbx                = new QSpinBox (this);
  m_colorWholeMsgChbx         = new QCheckBox(this);
  m_colorWholeSysMsgChbx      = new QCheckBox(this);
  m_activateOnMsgInChbx       = new QCheckBox(this);
  (m_soundOnMsgInChbx         = new QCheckBox(this))->hide();
  m_nlWithMessageChbx         = new QCheckBox(this);
  m_nlInStatusChbx            = new QCheckBox(this);

  m_portOutLab                = new QLabel(this);
  m_portInLab                 = new QLabel(this);

  m_myColorLab                = new QLabel(this);
  m_sysColorLab               = new QLabel(this);
  m_baseColorLab              = new QLabel(this);
  m_ipLab                     = new QLabel(this);
  m_broadcastLab              = new QLabel(this);
  m_nlFormatLab               = new QLabel(this);
  m_displayMsgFmtLab          = new QLabel(this);
  m_msgsHistoryIntervalLab    = new QLabel(this);
  m_msgsHistoryNumLab         = new QLabel(this);
  m_ulRefreshIntervalLab      = new QLabel(this);
  m_ulDeepRefreshIntervalLab  = new QLabel(this);
  m_networkIfLab              = new QLabel(this);
  m_smilesPolicyLab           = new QLabel(this);

  m_commandOnIncomingEdit     = new QLineEdit(this);
  m_isCommandOnIncomingChbx   = new QCheckBox(this);

  m_nlFormatEdit              = new QLineEdit(this);
  m_displayMsgFmtEdit         = new QLineEdit(this);

  m_msgsHistoryIntervalSpbx   = new QSpinBox(this);
  m_msgsHistoryNumSpbx        = new QSpinBox(this);
  m_ulRefreshIntervalSpbx     = new QSpinBox(this);
  m_ulDeepRefreshIntervalSpbx = new QSpinBox(this);

  m_networkIfCmbx             = new QComboBox(this);

  m_ipListEditor              = new IpListEditor(this);

  m_loadUnloadPluginBtn       = new QPushButton(this);

  m_useCompressionChbx        = new QCheckBox(this);
  m_useAnimatedSmilesChbx     = new QCheckBox(this);
  m_smilesPolicyCmbx          = new QComboBox(this);

  m_protocolsBgrp             = new QButtonGroup(this);
  m_protocolV3Rbtn            = new QRadioButton(this);
  m_protocolV4Rbtn            = new QRadioButton(this);

  m_sectionsChooser->insertItem(Network    , m_networkSection);
  m_sectionsChooser->insertItem(Messages   , m_messagesSection);
  m_sectionsChooser->insertItem(Filtration , m_filtrationSection);
  m_sectionsChooser->insertItem(Smiles     , m_smilesSection);
  m_sectionsChooser->insertItem(Misc       , m_miscSection);
  m_sectionsChooser->insertItem(StyleSheets, m_styleSheetsSection);
  m_sectionsChooser->insertItem(Plugins    , m_pluginsSection);

  m_msgsHistoryNumSpbx       ->setRange(-1, 100000);
  m_msgsHistoryIntervalSpbx  ->setRange(0, 100000);
  m_ulRefreshIntervalSpbx    ->setRange(0, 100000);
  m_ulDeepRefreshIntervalSpbx->setRange(0, 100000);
}

void PreferencesDlg::setupConnections()
{
  connect(m_sectionsChooser, SIGNAL(currentRowChanged(int)), this, SLOT(slot_activateSection(int)));

  connect(m_myColor  , SIGNAL(clicked()), this, SLOT(slot_chooseColor()));
  connect(m_sysColor , SIGNAL(clicked()), this, SLOT(slot_chooseColor()));
  connect(m_baseColor, SIGNAL(clicked()), this, SLOT(slot_chooseColor()));
  connect(m_okBtn    , SIGNAL(clicked()), this, SLOT(slot_setPrefs()));
  connect(m_okBtn    , SIGNAL(clicked()), this, SLOT(slot_accept  ()));
  connect(m_applyBtn , SIGNAL(clicked()), this, SLOT(slot_setPrefs()));
  connect(m_cancelBtn, SIGNAL(clicked()), this, SLOT(slot_cancel  ()));

  connect(m_colorWholeSysMsgChbx, SIGNAL(stateChanged(int)), this, SLOT(slot_setSysMsgColorMode(int)));
  connect(m_colorWholeMsgChbx   , SIGNAL(stateChanged(int)), this, SLOT(slot_setMsgColorMode   (int)));
  connect(m_activateOnMsgInChbx , SIGNAL(stateChanged(int)), this, SLOT(slot_setActivateOnMsgIn(int)));
  connect(m_soundOnMsgInChbx    , SIGNAL(stateChanged(int)), this, SLOT(slot_setSoundOnMsgIn   (int)));
  connect(m_nlInStatusChbx      , SIGNAL(stateChanged(int)), this, SLOT(slot_setNlInStatus     (int)));
  connect(m_nlWithMessageChbx   , SIGNAL(stateChanged(int)), this, SLOT(slot_setNlWithMessage  (int)));

  connect(m_portInSpbx               , SIGNAL(valueChanged(int)), this, SLOT(edited()));
  connect(m_portOutSpbx              , SIGNAL(valueChanged(int)), this, SLOT(edited()));
  connect(m_msgsHistoryIntervalSpbx  , SIGNAL(valueChanged(int)), this, SLOT(edited()));
  connect(m_msgsHistoryNumSpbx       , SIGNAL(valueChanged(int)), this, SLOT(edited()));
  connect(m_ulRefreshIntervalSpbx    , SIGNAL(valueChanged(int)), this, SLOT(edited()));
  connect(m_ulDeepRefreshIntervalSpbx, SIGNAL(valueChanged(int)), this, SLOT(edited()));

  connect(m_ipEdit               , SIGNAL(textChanged (QString)), this, SLOT(slot_validateIp(QString)));
  connect(m_broadcastEdit        , SIGNAL(textChanged (QString)), this, SLOT(slot_validateIp(QString)));
  connect(m_commandOnIncomingEdit, SIGNAL(textChanged (QString)), this, SLOT(edited()));
  connect(m_nlFormatEdit         , SIGNAL(textChanged (QString)), this, SLOT(edited()));
  connect(m_displayMsgFmtEdit    , SIGNAL(textChanged (QString)), this, SLOT(edited()));

  if(!QChatSettings::settings()->boolOption("AllowDifferentPorts"))
    connect(m_portInSpbx, SIGNAL(valueChanged(int)), m_portOutSpbx, SLOT(setValue(int)));

  connect(m_networkIfCmbx, SIGNAL(activated(int)), this, SLOT(setNetworkIf(int)));

  connect(m_isCommandOnIncomingChbx, SIGNAL(stateChanged(int)), this, SLOT(slot_setExecuteCommandMode(int)));

  connect(m_loadUnloadPluginBtn, SIGNAL(clicked()), this, SLOT(loadOrUnloadPlugin()));

  connect(m_useCompressionChbx , SIGNAL(stateChanged(int)), this, SLOT(setUseCompression(int)));

  connect(m_smilesPolicyCmbx     , SIGNAL(activated(int))   , this, SLOT(edited()));
  connect(m_useAnimatedSmilesChbx, SIGNAL(stateChanged(int)), this, SLOT(edited()));

  connect(m_protocolV3Rbtn, SIGNAL(toggled(bool)), this, SLOT(protocolChanged()));
  connect(m_protocolV4Rbtn, SIGNAL(toggled(bool)), this, SLOT(protocolChanged()));
}

void PreferencesDlg::setupSections()
{
  QList<QWidget*> list;

  m_sectionsChooser->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Minimum);
  m_sectionsChooser->setFixedWidth(150);

  // Network
  m_sections->insertWidget(Network, setupSectionLayout(m_networkGrbx));

  list.append(m_colorsGrbx);
  list.append(m_miscGrbx);
  list.append(m_displayMsgFmtLab);
  list.append(m_displayMsgFmtEdit);
  list.append(m_msgsHistoryIntervalLab);
  list.append(m_msgsHistoryIntervalSpbx);
  list.append(m_msgsHistoryNumLab);
  list.append(m_msgsHistoryNumSpbx);

  // Messages
  m_sections->insertWidget(Messages, setupSectionLayout(list));

  // Filtration
  m_sections->insertWidget(Filtration, m_filtrationGrbx);

  // Smiles
  connect(m_smilesThemeChooser, SIGNAL(currentRowChanged(int)), this, SLOT(edited()));
  m_sections->insertWidget(Smiles, m_smilesThemesGrbx);

  // Misc
  list.clear();
#if defined(Q_OS_LINUX)
  list.append(m_nowListeningGrbx);
#else
  m_nowListeningGrbx->hide();
#endif
  list.append(m_usersListGrbx);
  list.append(m_iconFormatGrbx);

  m_sections->insertWidget(Misc, setupSectionLayout(list));

  // StylesSheets
  connect(m_styleSheetsChooser, SIGNAL(currentRowChanged(int)), this, SLOT(edited()));
  m_sections->insertWidget(StyleSheets, m_styleSheetsGrbx);

  // Plugins
  m_sections->insertWidget(Plugins, m_pluginsGrbx);
  connect(m_pluginsChooser, SIGNAL(currentRowChanged(int)), this, SLOT(updatePluginButtons(int)));

  m_ulDeepRefreshIntervalSpbx->hide();
  m_ulDeepRefreshIntervalLab->hide();
}

QWidget* PreferencesDlg::setupSectionLayout(QList<QWidget*> list)
{
  QWidget*     wgt  = new QWidget(0);
  QVBoxLayout* vbox = new QVBoxLayout(wgt);
  int i;

  vbox->setMargin(0);

  for(i = 0; i < list.size(); i++)
    vbox->addWidget(list[i]);

  vbox->addStretch();

  return wgt;
}

QWidget* PreferencesDlg::setupSectionLayout(QWidget* w, bool add_stretch)
{
  QWidget*     wgt  = new QWidget(0);
  QGridLayout* grid = new QGridLayout(wgt);

  grid->setMargin(0);

  grid->addWidget(w, 0, 0);

  if(add_stretch)
    grid->setRowStretch(1, 1);

  return wgt;
}

void PreferencesDlg::slot_activateSection(int idx)
{
  int idx_;
  int edited = m_edited;

  switch(idx)
  {
    case Network :
      reloadNetworkIfs();
      m_ipListEditor->init();
      break;

    case Messages :
      break;

    case Filtration :
      m_messageFilterEditor->refresh();
      break;

    case Smiles :
      reloadSmileThemeList();

      if((idx_ = m_smilesThemes.indexOf(QChatSettings::settings()->smilesThemePath())) >= 0)
        m_smilesThemeChooser->setCurrentRow(idx_);

      m_edited = edited;
      m_applyBtn->setEnabled(edited);

      break;

    case Misc :
      break;

    case StyleSheets :
      reloadStyleSheetsList();
      m_edited = edited;
      m_applyBtn->setEnabled(edited);
      break;

    case Plugins :
      reloadPluginsList();
      break;
  }

  m_sections->setCurrentIndex(idx);
}

void PreferencesDlg::reloadSmileThemeList()
{
  QDir dir(QChatSettings::settings()->settingsDir() + "/smiles");

  m_smilesThemes.clear();
  m_smilesThemeChooser->clear();

  emoticonsThemesFromDir(dir);

#if defined(Q_OS_LINUX)
  dir.setPath(QDir::homePath() + "/.kde/share/emoticons");
  emoticonsThemesFromDir(dir);
#endif

#if defined(Q_OS_LINUX)
  dir.setPath(QCoreApplication::applicationDirPath());
  if(dir.cd("../share/emoticons"))
    emoticonsThemesFromDir(dir);
  if(dir.path() != "/usr/share/emoticons" && dir.cd("/usr/share/emoticons"))
    emoticonsThemesFromDir(dir);
#else
  dir.setPath(QCoreApplication::applicationDirPath() + "/emoticons");
  emoticonsThemesFromDir(dir);
#endif
}

void PreferencesDlg::reloadStyleSheetsList()
{
  QDir dir(QChatSettings::settings()->settingsDir() + "/stylesheets");
  QFile file;
  QStringList list;
  bool ok = 1;

  m_styleSheets.clear();
  m_styleSheetsChooser->clear();

  list = dir.entryList();
  for(int i = 0; i < list.size(); i++)
  {
    if(list[i] == "." || list[i] == ".." || !QFileInfo(dir.absolutePath() + "/" + list[i]).isFile())
      continue;

    m_styleSheetsChooser->addItem(list[i]);
    m_styleSheets.append(dir.absolutePath() + "/" + list[i]);
  }


#if defined(Q_OS_LINUX)
  dir.setPath(QCoreApplication::applicationDirPath());
  ok = dir.cd("../share/qchat/stylesheets");
#else
  dir.setPath(QCoreApplication::applicationDirPath() + "/stylesheets");
#endif

  if(ok)
  {
    list = dir.entryList();
    for(int i = 0; i < list.size(); i++)
    {
      if(list[i] == "." || list[i] == ".." || !QFileInfo(dir.absolutePath() + "/" + list[i]).isFile())
        continue;

      m_styleSheetsChooser->addItem(list[i]);
      m_styleSheets.append(dir.absolutePath() + "/" + list[i]);
    }
  }
}

void PreferencesDlg::emoticonsThemesFromDir(QDir dir)
{
  QFile file;

  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;

      m_smilesThemeChooser->addItem(em_dir);
      m_smilesThemes.append(dir.absolutePath() + "/" + em_dir + "/");
    }
}

void PreferencesDlg::reloadNetworkIfs()
{
  QList<QNetworkInterface> all_i = QNetworkInterface::allInterfaces();

  m_networkIfCmbx->clear();

  m_networkIfCmbx->addItem(tr("Custom (not recommended)"));

  m_addressEntries.clear();

  foreach(QNetworkInterface i, all_i)
    foreach(QNetworkAddressEntry e, i.addressEntries())
    {
      if(e.broadcast().isNull())
        continue;

      m_addressEntries.append(e);
      m_networkIfCmbx->addItem(i.name());
    }

  for(int i = 0; i < m_addressEntries.size(); i++)
    if((m_addressEntries[i].ip() == QHostAddress(QChatSettings::settings()->hostAddressOption("IP"))) &&
       (m_addressEntries[i].broadcast() == QChatSettings::settings()->realBroadcast()))
    {
      m_networkIfCmbx->setCurrentIndex(i + 1);
      m_ipEdit       ->setEnabled(false);
      m_broadcastEdit->setEnabled(false);
    }
}

void PreferencesDlg::setNetworkIf(int idx)
{
  m_ipEdit       ->setEnabled(!idx);
  m_broadcastEdit->setEnabled(!idx);

  if(!idx)
  {
    m_broadcastEdit->setText(QChatSettings::settings()->hostAddressOption("CustomBroadcast").toString());
    m_ipEdit       ->setText(QChatSettings::settings()->hostAddressOption("CustomIP").toString());
  }
  else
  {
    QNetworkAddressEntry e = m_addressEntries[idx - 1];
    m_broadcastEdit->setText(e.broadcast().toString());
    m_ipEdit->setText(e.ip().toString());
  }
}

int PreferencesDlg::addSection(QWidget* section, const QString & name)
{
  if(section)
  {
    m_sectionsChooser->addItem(name);
    m_sections       ->addWidget(section);
    return m_sectionsChooser->count() - 1;
  }

  return 0;
}

void PreferencesDlg::setupPluginsSection(QList< QObject * > plugins)
{
  QChatBasicPlugin* plugin;

  m_pluginsChooser->clear();

  foreach(QObject* obj, plugins)
  {
    plugin = qobject_cast<QChatWidgetPlugin*>(obj);
    if(plugin)
      m_pluginsChooser->addItem(plugin->name());
  }
}

void PreferencesDlg::setIconFormat(const UserListIconFormat & fmt)
{
  m_iconFormatWgt->setFormat(fmt);
}

void PreferencesDlg::removeSection(QWidget* section)
{
  int idx;

  if(section)
  {
    if((idx = m_sections->indexOf(section)) >= 0/*LastSection*/)
    {
      m_sections->removeWidget(section);
      delete m_sectionsChooser->takeItem(idx);
    }
  }
}

void PreferencesDlg::reloadPluginsList()
{
  ChatWgt* wgt   = qobject_cast<ChatWgt*>(parentWidget());
  QListWidgetItem* item;

  if(wgt)
  {
    m_pluginsChooser->clear();

    foreach(Plugin* pl, wgt->core()->pluginManager()->plugins())
    {
      item = new QListWidgetItem(pl->name() + (pl->isLoaded() ? tr(" (Loaded)") : tr(" (Not loaded)")), m_pluginsChooser);

      item->setData(Qt::UserRole, pl->path());
      item->setData(Qt::UserRole + 1, pl->isLoaded());

      m_pluginsChooser->addItem(item);
    }

  }
}

void PreferencesDlg::updatePluginButtons(int row)
{
  if(row >= 0)
  {
    bool loaded = false;
    QListWidgetItem* item = m_pluginsChooser->currentItem();

    if(item)
      loaded = item->data(Qt::UserRole + 1).toBool();

    m_loadUnloadPluginBtn->setText(loaded ? tr("Unload plugin") : tr("Load plugin"));
    m_loadUnloadPluginBtn->setEnabled(true);
  }
  else
    m_loadUnloadPluginBtn->setEnabled(false);
}

void PreferencesDlg::loadOrUnloadPlugin()
{
  QListWidgetItem* item = m_pluginsChooser->currentItem();
  QString path;
  bool loaded;

  if(item)
  {
    path   = item->data(Qt::UserRole).toString();
    loaded = item->data(Qt::UserRole + 1).toBool();

    if(loaded)
      emit wantUnloadPlugin(path);
    else
      emit wantLoadPlugin(path);

    m_loadUnloadPluginBtn->setText(loaded ? tr("Unload plugin") : tr("Load plugin"));
    reloadPluginsList();
  }
}

void PreferencesDlg::hidePluginsSection()
{
  m_sectionsChooser->takeItem(Plugins);
  m_sections->removeWidget(m_pluginsGrbx);
}

void PreferencesDlg::setUseCompression(int state)
{
  QChatSettings::settings()->setOption("UseCompression", (state == Qt::Checked));
}

void PreferencesDlg::protocolChanged()
{
  if(sender() == m_protocolV3Rbtn)
  {
    m_useCompressionChbx->setEnabled(false);
    emit wantChangeProtocol(3);
  }
  else if(sender() == m_protocolV4Rbtn)
  {
    m_useCompressionChbx->setEnabled(true);
    emit wantChangeProtocol(4);
  }
}
