/***************************************************************************
 *   Copyright (C) 2007-2008 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 "chatwgt.h"
#include "globals.h"

#include <assert.h>
#include <string.h>
#include <time.h>

#include <QSplitter>
#include <QMessageBox>
#include <QApplication>
#include <QBuffer>
#include <QDir>
#include <QFile>
#include <QFileDialog>
#include <QHBoxLayout>
#include <QInputDialog>
#include <QLocale>
#include <QCursor>
#include <QStatusBar>
#include <QKeySequence>
#include <QActionGroup>

#include <QPluginLoader>

#include "singlemessagewgt.h"
#include "filetransferwgt.h"
#include "userwgt.h"
#include "userinfo.h"
#include "addchanneldialog.h"
#include "edituserinfodlg.h"
#include "receiverthread.h"
#include "senderthread.h"
#include "largedatagram.h"
#include "largedatagramout.h"
#include "logwgt.h"
#include "qchatsettings.h"
#include "preferencesdlg.h"
#include "chatcore.h"
#include "smileswgt.h"
#include "channelwgt.h"
#include "chattextwgt.h"
#include "inputrichtextwgt.h"
#include "qchattrayicon.h"
#include "message.h"
#include "singlemsgshistoryview.h"
#include "singlemsgshistory.h"

#include "aboutqchat.h"
#include "pluginsinterfaces.h"
#include "login2serverdlg.h"
#include "tcpreceiverthread.h"
#include "formattingtoolbar.h"

#include "qchaticon.h"

#include "shortcutseditor.h"
#include "messagetreeitem.h"
#include "singlemessage.h"
#include "pluginmanager.h"
#include "plugin.h"
#include <QDesktopWidget>
#include <QScrollBar>

const char* BuildDate    = "";

ChatWgt::ChatWgt(ChatCore* chc, QWidget* parent)
 : QMainWindow(parent),
 m_chatCore    (chc),
 m_formattingToolBar(NULL),
 m_menuToolbars(NULL),
 m_cursorX     (-1),
 m_cursorY     (-1),
 m_hidePlugins (true)
{
  m_translator    = new QTranslator;
  m_activityTimer = new QTimer(this);

  createWidgets();

  createActions();

  setupLayout();

  ChatTextWgt::initSmiles(QChatSettings::settings()->smilesThemePath());
  mw_smiles->init();

  mw_log->hide();
  Globals::m_log = mw_log;

  m_trayIcon->show ();
  m_trayIcon->setContextMenu(m_menuFile);

  //***********************************
  connect(this          , SIGNAL(     singleMessage(const QString &, quint64, bool)),
          m_chatCore    , SLOT  (slot_singleMessage(const QString &, quint64, bool)));

  connect(m_chatCore    , SIGNAL(profileLoaded(const QString &)),
          this          , SLOT  (slot_reloadProfileData()));

  connect(this          , SIGNAL(wantLoadProfile (const QString &)),
          m_chatCore    , SLOT  (slot_loadProfile(const QString &)));

  connect(this          , SIGNAL(wantRenameProfile (const QString &, const QString &)),
          m_chatCore    , SLOT  (slot_renameProfile(const QString &, const QString &)));

  connect(this          , SIGNAL(wantDeleteProfile (const QString &)),
          m_chatCore    , SLOT  (slot_deleteProfile(const QString &)));

  connect(m_activityTimer, SIGNAL(timeout()),
          this           , SLOT  (activity()));

  connect(m_chatCore     , SIGNAL(disconnectedFromServer()),
          this           , SLOT  (disconnectedFromServer()));

  connect(m_preferencesDlg, SIGNAL(formatChanged(UserListIconFormat)), this, SLOT(changeIconFormat(UserListIconFormat)));

  connect(m_preferencesDlg, SIGNAL(wantLoadPlugin(QString))  , this, SLOT(loadPlugin(QString)));
  connect(m_preferencesDlg, SIGNAL(wantUnloadPlugin(QString)), this, SLOT(unloadPlugin(QString)));
  connect(m_preferencesDlg, SIGNAL(useAnimatedSmiles(bool))  , this, SLOT(setAnimationsRunning(bool)));

  //***********************************
  UserInfo::myInfo()->setStatus(Globals::FREE);

  setWindowTitle(QString("QChat %1").arg(Globals::VersionStr));

  QApplication::setWindowIcon(QChatIcon::icon("tray-icon"));

  if(!m_translator->load("qchat_" + QLocale().name () + ".qm", QChatSettings::settings()->settingsDir())) {
    if(!m_translator->load("qchat_" + QLocale::system().name() + ".qm", QApplication::applicationDirPath() + "/share/translations/")) {
      if(!m_translator->load("qchat_" + QLocale().name () + ".qm", "/usr/share/qchat/translations/"))
        m_translator->load("qchat_" + QLocale().name () + ".qm", "/usr/local/share/qchat/translations/");
    }
  }

  QApplication::installTranslator(m_translator);

  m_activityTimer->start(1000);

  retranslate();
  setIcons();
}
//\*****************************************************************************
ChatWgt::~ChatWgt()
{
  qDebug("[~ChatWgt]\n");
  m_addChannelDlg->~AddChannelDlg();
}
//\*****************************************************************************
ChannelWgt* ChatWgt::findChannel(const QString & name, quint32 type) const
{
  foreach(ChannelWgt* cw, mw_channels)
    if(cw->name() == name && (1 || cw->type() == type))
      return cw;

  return NULL;
}
//\*****************************************************************************
ChannelWgt* ChatWgt::findChannel(quint64 uid, quint32 type) const
{
  foreach(ChannelWgt* cw, mw_channels)
    if(cw->destUid() == uid && (cw->type() == type))
      return cw;

  return NULL;
}
//\*****************************************************************************
void ChatWgt::slot_singleMessageIn(SingleMessage* msg, bool important)
{
  SingleMessageWgt* smw = new SingleMessageWgt(msg, 1);

  connect(smw , SIGNAL(singleMessage   (const QString &, quint64, bool)),
          this, SIGNAL(singleMessageOut(const QString &, quint64, bool)));

  if(important)
    smw->setWindowFlags(smw->windowFlags() | Qt::WindowStaysOnTopHint/* | Qt::Popup*/);

  SingleMessageWgt::addNewMessage(smw);

  smw->show();
}
//\*****************************************************************************
void ChatWgt::createChannel(const QString & name, quint64 uid)
{
  qDebug("[ChatWgt::createChannel]: begin");
  int new_idx = 0;
  ChannelWgt* new_ch;

  if(uid == 0)
  {
    if(name == "Log" || name == "log")
    {
      new_idx = mw_tabs->addTab(mw_log, QString("Log"));
      mw_tabs->setCurrentIndex(new_idx);
      return;
    }

    if(findChannel(name))
      return;
  }
  else
  {
    if(findChannel(name, 1))
      return;

    foreach(ChannelWgt* cw, mw_channels)
      if(cw->destUid() == uid)
        return;
  }

  if(uid == 0)
  {
    new_ch = new ChannelWgt(name, this);
    new_idx = mw_tabs->addTab(new_ch, name);
  }
  else
  {
    new_ch = new ChannelWgt(name, this, AbstractChatCore::Private, uid);
    new_idx = mw_tabs->addTab(new_ch, name + "(private)");
  }

  if(!mw_channels.contains(new_ch))
    mw_channels.append(new_ch);

  new_ch->show();

  connect(new_ch, SIGNAL(wantActivate   ()), this, SLOT(slot_activateWindow ()));

  connect(new_ch    , SIGNAL(     statusAnswer   (QString, quint64, AbstractChatCore::ChannelType, bool, bool)),
          m_chatCore, SLOT  (slot_statusAnswer   (QString, quint64, AbstractChatCore::ChannelType, bool, bool)));

  connect(new_ch    , SIGNAL(     infoAnswer     (QString, quint64, AbstractChatCore::ChannelType, uchar)),
          m_chatCore, SLOT  (slot_infoAnswer     (QString, quint64, AbstractChatCore::ChannelType, uchar)));

  connect(new_ch    , SIGNAL(sendSomeData(QString, quint64, AbstractChatCore::DataType, QString, AbstractChatCore::ChannelType, QByteArray*)),
          m_chatCore, SLOT  (slot_prepareAndSend(QString, quint64, AbstractChatCore::DataType, QString, AbstractChatCore::ChannelType, QByteArray*)));

  connect(new_ch    , SIGNAL(sendMsgsHistory       (QString, quint64, QByteArray, AbstractChatCore::ChannelType)),
          m_chatCore, SLOT  (slot_msgsHistoryAnswer(QString, quint64, QByteArray, AbstractChatCore::ChannelType)));

  connect(new_ch    , SIGNAL(sendMsgsNum       (const QString &, quint64, quint32, AbstractChatCore::ChannelType)),
          m_chatCore, SLOT  (slot_msgsNumAnswer(const QString &, quint64, quint32, AbstractChatCore::ChannelType)));

  connect(m_preferencesDlg, SIGNAL(ulRefreshIntervalChanged(uint)),
          new_ch          , SLOT  (slot_changeUlRefreshInterval(uint)));

  connect(m_preferencesDlg, SIGNAL(ulDeepRefreshIntervalChanged(uint)),
          new_ch          , SLOT  (slot_changeUlDeepRefreshInterval(uint)));

  connect(new_ch    , SIGNAL(sendMessage     (const QString &, quint64, AbstractChatCore::ChannelType, QTextDocument*)),
          m_chatCore, SLOT  (slot_sendMessage(const QString &, quint64, AbstractChatCore::ChannelType, QTextDocument*)));

  connect(new_ch    , SIGNAL(wantSaveState  (const QString &, const QByteArray &)),
          m_chatCore, SLOT  (setChannelState(const QString &, const QByteArray &)));

  connect(new_ch    , SIGNAL(avatarAnswer     (const QString &, quint64, AbstractChatCore::ChannelType)),
          m_chatCore, SLOT  (slot_avatarAnswer(const QString &, quint64, AbstractChatCore::ChannelType)));

  connect(m_chatCore, SIGNAL(loginFinished (int, QString)),
          new_ch    , SLOT  (slot_refreshUL()));

  new_ch->setFocus();
  new_ch->setFocus2InputText();
  new_ch->setSndOnMsgIn(QChatSettings::settings()->boolOption("SoundOnMessageIn"));

  new_ch->initChannel();

  mw_tabs->setCurrentIndex(new_idx);

  if(uid != 0)
    m_chatCore->slot_privateChatRequest(UserInfo::myInfo()->nickname(), uid);

  new_ch->restoreState(m_chatCore->channelState(name));

  qDebug("[ChatWgt::createChannel]: end");
}
//\*****************************************************************************
void ChatWgt::slot_delChannell()
{
  ChannelWgt* wgt = qobject_cast<ChannelWgt*>(mw_tabs->currentWidget());

  if(!wgt)
  {
    QChatWidgetPlugin* plug = qobject_cast<QChatWidgetPlugin*>(mw_tabs->currentWidget());

    if(plug)
    {
      QMessageBox* msgbx;
      int ans;
      msgbx = new QMessageBox(tr("Are you sure?"), tr("Are you sure you want to unload plugin '%1'?").arg(plug->name()),
                            QMessageBox::Question, QMessageBox::Yes, QMessageBox::No, 0, this, 0);

      ans = msgbx->exec();
      delete msgbx;
      if(ans == QMessageBox::No)
        return;

      unloadPlugin(plug->path());
    }

    return;
  }

  qDebug("[ChatWgt::slot_delChannell]: name = %s\n", wgt->name().toLocal8Bit().data());

  if(mw_tabs->currentWidget() == mw_log)
  {
    mw_tabs->removeTab(mw_tabs->currentIndex());
    return;
  }

  QString name_id = wgt->name();
  quint32 type    = wgt->type();
  ChannelWgt* ch = findChannel(name_id, type);

  if(name_id == "Main")
    return;

  QMessageBox* msgbx;
  int ans;
  msgbx = new QMessageBox(tr("Are you sure?"), tr("Are you sure you want to close channel '%1'?").arg(name_id),
                          QMessageBox::Question, QMessageBox::Yes, QMessageBox::No, 0, this, 0);

  ans = msgbx->exec();
  delete msgbx;
  if(ans == QMessageBox::No)
    return;

  if(ch)
    mw_channels.removeAll(ch);

  delete ch;
}
//\*****************************************************************************
void ChatWgt::slot_license()
{
   QString str =
     "This program is free software; you can redistribute it and/or modify\n"
     "it under the terms of the GNU General Public License version 2\n"
     "as published by the Free Software Foundation;\n\n"
     "This program is distributed in the hope that it will be useful,\n"
     "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
     "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"
     "GNU General Public License for more details.\n\n"
     "Copyright (C) 2007-2008 by Anistratov Oleg\n"
     "ower@users.sourceforge.net";

   QMessageBox::information (this, "License", str);
}
//\*****************************************************************************
void ChatWgt::slot_aboutQt()
{
  QMessageBox::aboutQt(this);
}
//\*****************************************************************************
void ChatWgt::slot_about()
{
  AboutQChat* dlg = new AboutQChat(this);

  dlg->exec();

  delete dlg;
}
//\*****************************************************************************
void ChatWgt::slot_showSettings()
{
  m_userInfoDlg->setReadOnly(false);
  m_userInfoDlg->slot_loadInfo(UserInfo::myInfo());
  m_userInfoDlg->slot_notEdited();
  m_userInfoDlg->toggleVisible();
}
//\*****************************************************************************
void ChatWgt::slot_showPreferences()
{
  m_preferencesDlg->init();
  m_preferencesDlg->toggleVisible();
}
//\*****************************************************************************
void ChatWgt::slot_showUserInfo(UserWgt* user)
{
  m_userInfoDlg->slot_loadInfo(user->info());
  m_userInfoDlg->setReadOnly(true);
  m_userInfoDlg->show();
}
//\*****************************************************************************
void ChatWgt::slot_activateWindow()
{
  if(!QApplication::focusWidget())
    m_trayIcon->setAnimatedIcon(QChatIcon::iconPath("animated-new-message"));

  if(QChatSettings::settings()->boolOption("ActivateOnMessageIn") && isHidden())
    show();

  if(windowState() & Qt::WindowMaximized)
    this->setWindowState(Qt::WindowMaximized|Qt::WindowActive);
  else if(windowState () & Qt::WindowMinimized)
  {
    this->setWindowState(Qt::WindowNoState);
    this->setWindowState(Qt::WindowActive );
  }
  else
    this->setWindowState(Qt::WindowActive);
}
//\*****************************************************************************
void ChatWgt::slot_sendFile(quint64 uid)
{
  QString filename;
  filename = QFileDialog::getOpenFileName(
                    this,
                    tr("Choose a file to open"),
                    "/"
                    "");

  qDebug("[ChatWgt::slot_sendFile]: filename = %s", filename.toLocal8Bit().data());

  if(filename.isEmpty())
    return;

  FileTransferWgt* ftw = new FileTransferWgt(filename, 0);
  quint32 id           = m_chatCore->initSendingFile(uid, filename, ftw);

  UserInfo* info = m_chatCore->getUserInfo(uid);

  if(info)
  {
    ftw->setUserName(info->nickname());
    ftw->setIp(info->ip());
  }

  if(id)
  {
    ftw->setID(id);
    ftw->setUid(uid);
  }

  ftw->init();
}
//\*****************************************************************************
void ChatWgt::slot_receiveFile(const QString & filename, quint16 ID, quint64 srcIP)
{
  FileTransferWgt* ftw = new FileTransferWgt(filename, 1);

  UserInfo* info = m_chatCore->getUserInfo(srcIP);

  if(info)
  {
    ftw->setUserName(info->nickname());
    ftw->setIp(info->ip());
  }

  ftw->setID (ID   );
  ftw->setUid(srcIP);

  ftw->init();

  m_chatCore->initReceivingFile(ftw);
}
//\*****************************************************************************
void ChatWgt::slot_openSocketError(quint16 port)
{
  mw_log->addError(QString("Couldn't open UDP socket on port %1 ").arg(port));
}
//\*****************************************************************************
void ChatWgt::slot_exit()
{
  foreach(ChannelWgt* cw, mw_channels)
    cw->slot_disconnected();

  m_chatCore->stopThreads();
  m_chatCore->saveSettings(true);

  QApplication::quit();
}
//\*****************************************************************************
void ChatWgt::slot_trayIconClicked(QSystemTrayIcon::ActivationReason reason)
{
  ChannelWgt* chnnl = findChannel(currentChannelName());

  if(reason == QSystemTrayIcon::Trigger)
  {
    m_trayIcon->setStaticIcon(QChatIcon::iconPath("tray-icon"));

    if(isHidden() || windowState () & Qt::WindowMinimized)
    {
      show();
      if(windowState() & Qt::WindowMaximized)
        setWindowState(Qt::WindowMaximized|Qt::WindowActive);
      else
        setWindowState(Qt::WindowNoState);

      if(chnnl)
        chnnl->setFocus2InputText();
    }
    else
      hide();
  }
}
//\*****************************************************************************
void ChatWgt::slot_showSmiles()
{
  if(!mw_smiles || !mw_smiles->inited())
    return;

  if(m_smilesScrllArea->isHidden())
  {
    mw_smiles->setOptimalSize();
    mw_smiles->unselectAll();

    QDesktopWidget dsctp;
    int wd = mw_smiles->width();
    int he = mw_smiles->height();
    int max_wd, max_he;

    max_wd = (dsctp.availableGeometry().width()  / 8) * 7;
    max_he = (dsctp.availableGeometry().height() / 8) * 7;

    if(wd > max_wd)
      wd = max_wd;

    if(he > max_he)
      he = max_he;

    m_smilesScrllArea->setWindowFlags(Qt::FramelessWindowHint | m_smilesScrllArea->windowFlags() | Qt::WindowStaysOnTopHint);
    m_smilesScrllArea->resize(wd + 5, he + 5);

    m_smilesScrllArea->move(QCursor().pos());
    m_smilesScrllArea->show();
    mw_smiles->show();

    if(wd >= mw_smiles->width())
      m_smilesScrllArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    else
      m_smilesScrllArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);

    if(he >= mw_smiles->height())
      m_smilesScrllArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    else
      m_smilesScrllArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
  }
  else
    m_smilesScrllArea->hide();
}
//\*****************************************************************************
void ChatWgt::slot_insertSmile(const QString & smile)
{
  ChannelWgt* chnnl = qobject_cast<ChannelWgt*>(mw_tabs->currentWidget());

  if(chnnl)
    chnnl->inputText()->append(smile);
}
//\*****************************************************************************
QString ChatWgt::currentChannelName() const
{
  ChannelWgt* chnnl = qobject_cast<ChannelWgt*>(mw_tabs->currentWidget());

  return (chnnl ? chnnl->name() : "");
}
//\*****************************************************************************
void ChatWgt::fillProfilesCmbx(const QStringList & profiles, const QString & current)
{
  disconnect(m_profilesCmbx, SIGNAL(currentIndexChanged(const QString &)),
             m_chatCore    , SLOT  (slot_loadProfile   (const QString &)));

  QStringList::const_iterator i;
  QStringList::const_iterator end = profiles.constEnd();
  int idx;

  for(i = profiles.constBegin(); i != end; ++i)
    m_profilesCmbx->addItem(*i);

  if((idx = m_profilesCmbx->findText(current)) >= 0)
    m_profilesCmbx->setCurrentIndex(idx);

  connect(m_profilesCmbx, SIGNAL(currentIndexChanged(const QString &)),
          m_chatCore    , SLOT  (slot_loadProfile   (const QString &)));
}
//\*****************************************************************************
void ChatWgt::slot_setCurrentProfileName(const QString & name)
{
  int idx;

  if((idx = m_profilesCmbx->findText(name)) >= 0)
    m_profilesCmbx->setCurrentIndex(idx);
  else
    m_profilesCmbx->addItem(name);

  if((idx = m_profilesCmbx->findText(name)) >= 0)
    m_profilesCmbx->setCurrentIndex(idx);
}

void ChatWgt::slot_reloadProfileData()
{
  if(!m_userInfoDlg->isHidden() && !m_userInfoDlg->readOnly())
    m_userInfoDlg->slot_loadInfo(UserInfo::myInfo());

  if(!m_preferencesDlg->isHidden())
    m_preferencesDlg->init();

  ChatTextWgt::initSmiles(QChatSettings::settings()->smilesThemePath());
  mw_smiles->loadTheme(QChatSettings::settings()->smilesThemePath());

  // FIXME incorrect works if other channel set its status in myInfo
  foreach(ChannelWgt* cw, mw_channels)
    m_chatCore->slot_statusAnswer(cw->name(), QChatSettings::settings()->broadcast().toIPv4Address(), AbstractChatCore::Common, 0, 1);

  m_preferencesDlg->setIconFormat(*QChatSettings::settings()->iconFormat());
  changeIconFormat(*QChatSettings::settings()->iconFormat());
}

void ChatWgt::createActions()
{
  m_showSettingsAct      = new QAction(this);
  m_showPreferencesAct   = new QAction(this);
  m_exitAct              = new QAction(this);
  m_showSmilesAct        = new QAction(this);
  m_showEditShortcutsAct = new QAction(this);
  m_addChannelAct        = new QAction(this);
  m_delChannelAct        = new QAction(this);
  m_aboutAct             = new QAction(this);
  m_aboutQtAct           = new QAction(this);
  m_licenseAct           = new QAction(this);
  m_writeSettingsAct     = new QAction(this);

  m_addProfileAct        = new QAction(this);
  m_deleteProfileAct     = new QAction(this);
  m_renameProfileAct     = new QAction(this);

  (m_translateEnAct      = new QAction(this))->setData("en");
  (m_translatePlAct      = new QAction(this))->setData("pl");
  (m_translateRuAct      = new QAction(this))->setData("ru");
  (m_translateUkAct      = new QAction(this))->setData("uk");
  (m_translateEsAct      = new QAction(this))->setData("es");
  (m_translateDeAct      = new QAction(this))->setData("de");
  (m_translateSrAct      = new QAction(this))->setData("sr");

  (m_showMainTBarAct       = new QAction(this))->setCheckable(true);
  (m_showProfilesTBarAct   = new QAction(this))->setCheckable(true);
  (m_showPluginsTBarAct    = new QAction(this))->setCheckable(true);
  (m_showFormattingTBarAct = new QAction(this))->setCheckable(true);

  m_showSingleMessagesAct= new QAction(this);

  m_showPluginsAct       = new QAction(this);
  m_broadcastMessageAct  = new QAction(this);

  (m_setServerModeAct       = new QAction(this))->setCheckable(true);
  (m_setServerlessModeAct   = new QAction(this))->setCheckable(true);
  m_connectToServerAct      = new QAction(this);
  m_disconnectFromServerAct = new QAction(this);

  (m_toolButtonsSizeDefault  = new QAction(this))->setData(0);
  (m_toolButtonsSize16       = new QAction(this))->setData(16);
  (m_toolButtonsSize24       = new QAction(this))->setData(24);
  (m_toolButtonsSize32       = new QAction(this))->setData(32);
  (m_toolButtonsSize48       = new QAction(this))->setData(48);

  QActionGroup* tbSizeGroup  = new QActionGroup(this);

  m_toolButtonsSizeDefault->setCheckable(true);
  m_toolButtonsSize16     ->setCheckable(true);
  m_toolButtonsSize24     ->setCheckable(true);
  m_toolButtonsSize32     ->setCheckable(true);
  m_toolButtonsSize48     ->setCheckable(true);

  m_toolButtonsSizeDefault->setActionGroup(tbSizeGroup);
  m_toolButtonsSize16     ->setActionGroup(tbSizeGroup);
  m_toolButtonsSize24     ->setActionGroup(tbSizeGroup);
  m_toolButtonsSize32     ->setActionGroup(tbSizeGroup);
  m_toolButtonsSize48     ->setActionGroup(tbSizeGroup);

  m_disconnectFromServerAct->setVisible(false);

  m_setServerModeAct    ->setData(ChatCore::Server);
  m_setServerlessModeAct->setData(ChatCore::Serverless);

  QActionGroup* actGrp = new QActionGroup(this);

  actGrp->addAction(m_setServerModeAct);
  actGrp->addAction(m_setServerlessModeAct);

  m_menuFile->addAction(m_connectToServerAct);
  m_menuFile->addAction(m_disconnectFromServerAct);
  m_menuFile->addAction(m_setServerModeAct);
  m_menuFile->addAction(m_setServerlessModeAct);
  m_menuFile->addSeparator();

  m_menuTranslations->addAction(m_translateEnAct);
  m_menuTranslations->addAction(m_translateDeAct);
  m_menuTranslations->addAction(m_translatePlAct);
  m_menuTranslations->addAction(m_translateRuAct);
  m_menuTranslations->addAction(m_translateSrAct);
  m_menuTranslations->addAction(m_translateEsAct);
  m_menuTranslations->addAction(m_translateUkAct);

  m_menuFile    ->addAction(m_broadcastMessageAct);
  m_menuFile    ->addAction(m_addChannelAct);
  m_menuFile    ->addAction(m_delChannelAct);
  m_menuFile    ->addAction(m_exitAct);

  m_menuSettings->addAction(m_showSettingsAct);
  m_menuSettings->addAction(m_showPreferencesAct);
//   m_menuSettings->addAction(m_writeSettingsAct);
  m_menuSettings->addAction(m_showEditShortcutsAct);

  m_menuSettings->addMenu  (m_menuTranslations);
  m_menuSettings->addMenu  (m_menuToolbars);

  m_menuView    ->addAction(m_showSmilesAct);
  m_menuView    ->addAction(m_showSingleMessagesAct);
  m_menuView    ->addAction(m_showPluginsAct);

  m_menuHelp    ->addAction(m_aboutAct);
  m_menuHelp    ->addAction(m_aboutQtAct);
  m_menuHelp    ->addAction(m_licenseAct);

  m_menuToolbars->addAction(m_showMainTBarAct);
  m_menuToolbars->addAction(m_showProfilesTBarAct);
  m_menuToolbars->addAction(m_showPluginsTBarAct);
  m_menuToolbars->addAction(m_showFormattingTBarAct);

  m_menuBar     ->addMenu(m_menuFile);
  m_menuBar     ->addMenu(m_menuView);
  m_menuBar     ->addMenu(m_menuSettings);
  m_menuBar     ->addMenu(m_menuHelp);

  connect(m_showSettingsAct    , SIGNAL(triggered(bool)), this             , SLOT(slot_showSettings()));
  connect(m_showPreferencesAct , SIGNAL(triggered(bool)), this             , SLOT(slot_showPreferences()));
  connect(m_exitAct            , SIGNAL(triggered(bool)), this             , SLOT(slot_exit()));
  connect(m_showSmilesAct      , SIGNAL(triggered(bool)), this             , SLOT(slot_showSmiles()));
  connect(m_showEditShortcutsAct, SIGNAL(triggered(bool)), this            , SLOT(showConfigureShortcuts()));
  connect(m_addChannelAct      , SIGNAL(triggered(bool)), m_addChannelDlg  , SLOT(getValues()));
  connect(m_delChannelAct      , SIGNAL(triggered(bool)), this             , SLOT(slot_delChannell()));
  connect(m_aboutAct           , SIGNAL(triggered(bool)), this             , SLOT(slot_about()));
  connect(m_aboutQtAct         , SIGNAL(triggered(bool)), this             , SLOT(slot_aboutQt()));
  connect(m_licenseAct         , SIGNAL(triggered(bool)), this             , SLOT(slot_license()));
  connect(m_writeSettingsAct   , SIGNAL(triggered(bool)), m_chatCore       , SLOT(slot_saveSettings()));
  connect(m_renameProfileAct   , SIGNAL(triggered(bool)), this             , SLOT(slot_editProfileName()));
  connect(m_addProfileAct      , SIGNAL(triggered(bool)), this             , SLOT(slot_addProfile()));
  connect(m_deleteProfileAct   , SIGNAL(triggered(bool)), this             , SLOT(slot_delProfile()));

  connect(m_showMainTBarAct      , SIGNAL(triggered(bool)), m_mainToolBar      , SLOT(setVisible(bool)));
  connect(m_showProfilesTBarAct  , SIGNAL(triggered(bool)), m_profilesToolBar  , SLOT(setVisible(bool)));
  connect(m_showPluginsTBarAct   , SIGNAL(triggered(bool)), m_pluginsToolBar   , SLOT(setVisible(bool)));
  connect(m_showFormattingTBarAct, SIGNAL(triggered(bool)), m_formattingToolBar, SLOT(setVisible(bool)));

  connect(m_showSingleMessagesAct, SIGNAL(triggered(bool)), this           , SLOT(slot_showSingleMessagesHistory()));
  connect(m_showPluginsAct       , SIGNAL(triggered(bool)), this           , SLOT(showPlugins()));
  connect(m_broadcastMessageAct  , SIGNAL(triggered(bool)), this           , SLOT(sendBroadcastMessage()));

  connect(m_translatePlAct     , SIGNAL(triggered(bool)), this             , SLOT(setLanguage()));
  connect(m_translateUkAct     , SIGNAL(triggered(bool)), this             , SLOT(setLanguage()));
  connect(m_translateRuAct     , SIGNAL(triggered(bool)), this             , SLOT(setLanguage()));
  connect(m_translateEnAct     , SIGNAL(triggered(bool)), this             , SLOT(setLanguage()));
  connect(m_translateEsAct     , SIGNAL(triggered(bool)), this             , SLOT(setLanguage()));
  connect(m_translateDeAct     , SIGNAL(triggered(bool)), this             , SLOT(setLanguage()));
  connect(m_translateSrAct     , SIGNAL(triggered(bool)), this             , SLOT(setLanguage()));

  connect(m_setServerlessModeAct, SIGNAL(triggered(bool)), this      , SLOT(setMode()));
  connect(m_setServerModeAct    , SIGNAL(triggered(bool)), this      , SLOT(setMode()));

  connect(m_setServerModeAct    , SIGNAL(triggered(bool)), this, SLOT(chvisConnectToServerAct()));
  connect(m_setServerlessModeAct, SIGNAL(triggered(bool)), this, SLOT(chvisConnectToServerAct()));

  connect(m_connectToServerAct     , SIGNAL(triggered(bool)), this, SLOT(connect2server()));
  connect(m_disconnectFromServerAct, SIGNAL(triggered(bool)), this, SLOT(disconnectFromServer()));
  connect(m_toolButtonsSizeDefault , SIGNAL(triggered(bool)), this, SLOT(setToolbarsIconsSize()));
  connect(m_toolButtonsSize16      , SIGNAL(triggered(bool)), this, SLOT(setToolbarsIconsSize()));
  connect(m_toolButtonsSize24      , SIGNAL(triggered(bool)), this, SLOT(setToolbarsIconsSize()));
  connect(m_toolButtonsSize32      , SIGNAL(triggered(bool)), this, SLOT(setToolbarsIconsSize()));
  connect(m_toolButtonsSize48      , SIGNAL(triggered(bool)), this, SLOT(setToolbarsIconsSize()));

  connect(m_preferencesDlg         , SIGNAL(wantChangeProtocol(uint)), m_chatCore, SLOT(changeProtocolVersion(uint)));
}

void ChatWgt::createWidgets()
{
  m_profilesLab          = new QLabel(this);

  m_pluginsTabs          = new QTabWidget(this);
  m_widgetsStack         = new QStackedWidget(this);

  mw_tabs                = new QTabWidget (this);
  m_addChannelBtn        = new QToolButton(mw_tabs);
  m_delChannelBtn        = new QToolButton(mw_tabs);

  m_addChannelDlg        = new AddChannelDlg(this);
  m_userInfoDlg          = new EditUserInfoDlg (0);
  m_preferencesDlg       = new PreferencesDlg  (this);

  mw_log                 = new LogWgt(this);
  mw_smiles              = new SmilesWgt;
  m_trayIcon             = new QChatTrayIcon(QChatIcon::icon("tray-icon"), this);
  m_profilesCmbx         = new QComboBox(this);

  m_menuBar              = new QMenuBar   (this);
  (m_mainToolBar         = new QToolBar   (this))->setObjectName("Main Toolbar");
  (m_profilesToolBar     = new QToolBar   (this))->setObjectName("Profiles Toolbar");
  (m_pluginsToolBar      = new QToolBar   (this))->setObjectName("Plugins Toolbar");
  (m_formattingToolBar   = new FormattingToolBar(this))->setObjectName("Formatting Toolbar");
  m_menuFile             = new QMenu      (this);
  m_menuView             = new QMenu      (this);
  m_menuSettings         = new QMenu      (this);
  m_menuHelp             = new QMenu      (this);
  m_menuTranslations     = new QMenu      (this);
  m_menuToolbars         = new QMenu      (this);

  m_smilesScrllArea      = new QScrollArea(0);

  m_smhView              = new SingleMsgsHistoryView(0);

  m_smhView->setModel(m_chatCore->smhModel());

  m_smhView->resizeColumnToContents(0);
  m_smhView->resizeColumnToContents(1);
  m_smhView->resizeColumnToContents(2);
  m_smhView->resizeColumnToContents(3);

  m_smhView->resize(800, 600);

  setStatusBar(new QStatusBar(this));
  statusBar()->setSizeGripEnabled(false);

  m_profilesCmbx->setMinimumWidth(150);

  m_smilesScrllArea->setWidget(mw_smiles);
  m_smilesScrllArea->resize(400, 400);

  connect(m_preferencesDlg, SIGNAL(portChanged  (int)),
          m_chatCore      , SLOT  (slot_bindInputPort(int)));

  connect(m_preferencesDlg, SIGNAL(wantChangeSmileTheme (const QString &)),
          this            , SLOT  (slot_changeSmileTheme(const QString &)));

  connect(m_preferencesDlg, SIGNAL(styleSheetChanged(QString)),
          this            , SIGNAL(wantChangeStyleSheet(QString)));

  connect(m_preferencesDlg, SIGNAL(accepted()),
          m_chatCore      , SLOT  (slot_saveSettings()));

  connect(m_userInfoDlg   , SIGNAL(accepted()),
          m_chatCore      , SLOT  (slot_saveSettings()));

  connect(m_userInfoDlg   , SIGNAL(wantChangeNickname(QString)),
          m_chatCore      , SLOT  (changeLogin(QString)));

  connect(mw_smiles      , SIGNAL(smileClicked(const QString &)), this, SLOT(slot_insertSmile(const QString &)));
  connect(mw_smiles      , SIGNAL(wantHide())      , m_smilesScrllArea, SLOT(hide()));
  connect(m_addChannelDlg, SIGNAL(dataAccepted(const QString &)), this, SLOT(slot_addChannell(const QString &)));
  connect(m_trayIcon     , SIGNAL(activated           (QSystemTrayIcon::ActivationReason)),
          this           , SLOT  (slot_trayIconClicked(QSystemTrayIcon::ActivationReason)));

  connect(m_smhView      , SIGNAL(doubleClicked(const QModelIndex &)), this, SLOT(showSingleMessage(const QModelIndex &)));

//   connect(m_pluginsTabs, SIGNAL(currentChanged(int)), this, SLOT(pluginSwitched()));
  connect(mw_tabs      , SIGNAL(currentChanged(int)), this, SLOT(pluginSwitched()));
}

void ChatWgt::setupLayout()
{
  mw_tabs->setCornerWidget (m_addChannelBtn, Qt::TopLeftCorner);
  mw_tabs->setCornerWidget (m_delChannelBtn, Qt::TopRightCorner);

  m_addChannelBtn->setDefaultAction(m_addChannelAct);
  m_delChannelBtn->setDefaultAction(m_delChannelAct);

  m_mainToolBar->addAction(m_showSmilesAct);
  m_mainToolBar->addAction(m_showSettingsAct);
  m_mainToolBar->addAction(m_showPreferencesAct);
//   m_mainToolBar->addAction(m_writeSettingsAct);

  m_profilesToolBar->addWidget(m_profilesLab);
  m_profilesToolBar->addAction(m_addProfileAct);
  m_profilesToolBar->addWidget(m_profilesCmbx);
  m_profilesToolBar->addAction(m_renameProfileAct);
  m_profilesToolBar->addAction(m_deleteProfileAct);

  m_widgetsStack->insertWidget(0, mw_tabs);
  m_widgetsStack->insertWidget(1, m_pluginsTabs);

  setMenuBar(m_menuBar);

  addToolbar(m_mainToolBar);
  addToolbar(m_profilesToolBar);
  addToolbar(m_pluginsToolBar);
  addToolbar(m_formattingToolBar);

  setCentralWidget(m_widgetsStack);
}

void ChatWgt::slot_editProfileName()
{
  bool ok;
  QString str = QInputDialog::getText(this,
                                      QString(tr("Input new name for '%1'")).arg(m_profilesCmbx->currentText()),
                                      tr("New name:"),
                                      QLineEdit::Normal,
                                      m_profilesCmbx->currentText(),
                                      &ok);

  if(ok && !str.isEmpty() && (m_profilesCmbx->findText(str) < 0) )
  {
    emit wantRenameProfile(m_profilesCmbx->currentText(), str);
    m_profilesCmbx->setItemText(m_profilesCmbx->currentIndex(), str);
  }
}

void ChatWgt::slot_addProfile()
{
  bool ok;
  QString str = QInputDialog::getText(this,
                                      tr("Input name for new profile"),
                                      tr("New profile name:"),
                                      QLineEdit::Normal,
                                      "",
                                      &ok);

  if(ok && !str.isEmpty() && (m_profilesCmbx->findText(str) < 0) )
  {
    emit wantLoadProfile(str);
    m_profilesCmbx->addItem(str);
    m_profilesCmbx->setCurrentIndex(m_profilesCmbx->findText(str));
  }
}

void ChatWgt::slot_delProfile()
{
  if(m_profilesCmbx->count() > 1)
  {
     QMessageBox* msgbx;
     int ans;
     msgbx = new QMessageBox(tr("Are you sure?"),
                             tr("Are you sure you want delete profile %1?").arg(m_profilesCmbx->currentText()),
                             QMessageBox::Question, QMessageBox::Yes, QMessageBox::No, 0, this, 0);
     ans = msgbx->exec();
     delete msgbx;

     if(ans == QMessageBox::No)
       return;

     emit wantDeleteProfile(m_profilesCmbx->currentText());
     m_profilesCmbx->removeItem(m_profilesCmbx->currentIndex());
  }
}

void ChatWgt::retranslate()
{
  m_showSettingsAct    ->setText(tr("&Edit User Details..."));
  m_showPreferencesAct ->setText(tr("&Configure QChat..."      ));
  m_exitAct            ->setText(tr("&Exit"                ));
  m_showSmilesAct      ->setText(tr("&Show Smiles.."       ));
  m_addChannelAct      ->setText(tr("&Add Channel.."       ));
  m_delChannelAct      ->setText(tr("&Delete Channel.."    ));
  m_aboutAct           ->setText(tr("&About"               ));
  m_aboutQtAct         ->setText(tr("About &Qt"            ));
  m_licenseAct         ->setText(tr("&License"             ));
//   m_writeSettingsAct   ->setText(tr("&Write Settings"      ));
  m_showEditShortcutsAct->setText(tr("Configure Shortcuts..."));

  m_showMainTBarAct      ->setText(tr("Main Toolbar"         ));
  m_showProfilesTBarAct  ->setText(tr("Profiles Toolbar"     ));
  m_showPluginsTBarAct   ->setText(tr("Plugins Toolbar"      ));
  m_showFormattingTBarAct->setText(tr("Formatting Toolbar"      ));

  m_addProfileAct        ->setText(tr("Add pro&file..."      ));
  m_deleteProfileAct     ->setText(tr("Delete p&rofile..."   ));
  m_renameProfileAct     ->setText(tr("&Rename profile..."   ));
  m_showSingleMessagesAct->setText(tr("Show Single Messages History..."));
  m_showPluginsAct       ->setText(tr("Show Plugins"));
  m_broadcastMessageAct  ->setText(tr("Send Broadcast Message..."));

  m_mainToolBar        ->setWindowTitle(tr("Main Toolbar"    ));
  m_profilesToolBar    ->setWindowTitle(tr("Profiles Toolbar"));
  m_pluginsToolBar     ->setWindowTitle(tr("Plugins Toolbar"));

  m_smhView            ->setWindowTitle(tr("Single Messages History"));

  m_menuFile           ->setTitle(tr("&Chat"    ));
  m_menuView           ->setTitle(tr("&View"    ));
  m_menuSettings       ->setTitle(tr("&Settings"));
  m_menuHelp           ->setTitle(tr("&Help"    ));
  m_menuTranslations   ->setTitle(tr("&Language"));
  m_menuToolbars       ->setTitle(tr("Toolbars" ));

  m_translatePlAct     ->setText(tr("Polish"));
  m_translateUkAct     ->setText(tr("Ukrainian"));
  m_translateRuAct     ->setText(tr("Russian"));
  m_translateEnAct     ->setText(tr("English"));
  m_translateEsAct     ->setText(tr("Spanish"));
  m_translateDeAct     ->setText(tr("German"));
  m_translateSrAct     ->setText(tr("Serbian"));

  m_connectToServerAct     ->setText(tr("Connect to server.."));
  m_disconnectFromServerAct->setText(tr("Disconnect from server"));
  m_setServerModeAct       ->setText(tr("Server Mode"));
  m_setServerlessModeAct   ->setText(tr("Serverless Mode"));

  m_profilesLab        ->setText(tr("Current profile:"));

  m_toolButtonsSizeDefault->setText(tr("Default"));
  m_toolButtonsSize16     ->setText(tr("16x16"));
  m_toolButtonsSize24     ->setText(tr("24x24"));
  m_toolButtonsSize32     ->setText(tr("32x32"));
  m_toolButtonsSize48     ->setText(tr("48x48"));

  updateShortcuts();
}

void ChatWgt::setLanguage()
{
  QString lang = ((QAction*)sender())->data().toString();

  m_chatCore->setLang(lang);

#if defined(Q_OS_LINUX)
  QDir dir(QCoreApplication::applicationDirPath() + "/../share/qchat/translations");
#else
  QDir dir(QCoreApplication::applicationDirPath() + "/translations");
#endif

  if(!m_translator->load("qchat_" + m_chatCore->lang() + ".qm", QChatSettings::settings()->settingsDir()))
    if(!m_translator->load("qchat_" + m_chatCore->lang() + ".qm", dir.path()))
      if(!m_translator->load("qchat_" + m_chatCore->lang() + ".qm", "/usr/share/qchat/translations/"))
        m_translator->load("qchat_" + m_chatCore->lang() + ".qm", "/usr/local/share/qchat/translations/");

  QApplication::installTranslator(m_translator);

  retranslate();
}

void ChatWgt::slot_changeSmileTheme(const QString & path)
{
  qDebug("[ChatWgt::slot_changeSmileTheme]: path = %s", path.toLocal8Bit().data());

  if(path != QChatSettings::settings()->smilesThemePath())
  {
    QChatSettings::settings()->setSmilesThemePath(path);
    ChatTextWgt::initSmiles(path);
    mw_smiles->loadTheme(path);
  }
}

QMenu* ChatWgt::createPopupMenu()
{
  QMenu* menu    = new QMenu(this);
  QMenu* menu_tb = new QMenu(tr("Toolbars"), menu);
  QMenu* menu_sz = new QMenu(tr("Icons Size"), menu);

  menu_tb->addAction(m_showMainTBarAct);
  menu_tb->addAction(m_showProfilesTBarAct);
  if(!m_hidePlugins)
    menu_tb->addAction(m_showPluginsTBarAct);
  menu_tb->addAction(m_showFormattingTBarAct);

  menu_sz->addAction(m_toolButtonsSizeDefault);
  menu_sz->addAction(m_toolButtonsSize16);
  menu_sz->addAction(m_toolButtonsSize24);
  menu_sz->addAction(m_toolButtonsSize32);
  menu_sz->addAction(m_toolButtonsSize48);

  menu->addMenu(menu_tb);
  menu->addMenu(menu_sz);

  return menu;
}

void ChatWgt::restoreAndShow()
{
  QMessageBox::StandardButton ans;
  QString msg;

  restoreState(m_chatCore->state());

  if(!m_chatCore->geometry().isEmpty())
    restoreGeometry(m_chatCore->geometry());
  else
    resize(800, 600);

  show();

  m_showMainTBarAct      ->setChecked(m_mainToolBar      ->isVisible());
  m_showProfilesTBarAct  ->setChecked(m_profilesToolBar  ->isVisible());
  m_showPluginsTBarAct   ->setChecked(m_pluginsToolBar   ->isVisible());
  m_showFormattingTBarAct->setChecked(m_formattingToolBar->isVisible());

  // restoring tool buttons size
  int sz = QChatSettings::settings()->toolbarIconsSize();
  switch(sz)
  {
    case 16 : m_toolButtonsSize16->setChecked(true); break;
    case 24 : m_toolButtonsSize24->setChecked(true); break;
    case 32 : m_toolButtonsSize32->setChecked(true); break;
    case 48 : m_toolButtonsSize48->setChecked(true); break;
  }

  foreach(QToolBar* tb, m_toolbars)
    tb->setIconSize(QSize(sz, sz));

  if(!m_chatCore->lang().isEmpty())
  {
#if defined(Q_OS_LINUX)
  QDir dir(QCoreApplication::applicationDirPath() + "/../share/qchat/translations");
#else
  QDir dir(QCoreApplication::applicationDirPath() + "/translations");
#endif

    if(!m_translator->load("qchat_" + m_chatCore->lang() + ".qm", QChatSettings::settings()->settingsDir()))
      if(!m_translator->load("qchat_" + m_chatCore->lang() + ".qm", dir.path()))
        if(!m_translator->load("qchat_" + m_chatCore->lang() + ".qm", "/usr/share/qchat/translations/"))
          m_translator->load("qchat_" + m_chatCore->lang() + ".qm", "/usr/local/share/qchat/translations/");

    QApplication::installTranslator(m_translator);
  }

  retranslate();

  if(m_chatCore->needCheckIp() == 1)
  {
    msg = tr("Your network settings don't corresponds any of existing network interfaces.\n"
             "The program may not work.\n\n"
             "Do you want to configure it now?");

    ans = QMessageBox::warning(this,
                               tr("Incorrect network settings"),
                               msg,
                               QMessageBox::Yes | QMessageBox::No);

    if(ans == QMessageBox::Yes)
      slot_showPreferences();
  }

  else if(m_chatCore->needCheckIp() == 2)
  {
    msg = tr("Couldn't find any network interface that can broadcast.\n"
             "The program may not work.\n\n"
             "Do you want to see your network settings?");

    ans = QMessageBox::warning(this,
                               tr("No valid network interface!"),
                               msg,
                               QMessageBox::Yes | QMessageBox::No);

    if(ans == QMessageBox::Yes)
      slot_showPreferences();
  }

  setHidePlugins(!m_chatCore->pluginManager()->plugins().size());

  if(m_hidePlugins)
  {
    m_showPluginsTBarAct->setVisible(false);
    m_pluginsToolBar->hide();
    m_preferencesDlg->hidePluginsSection();
  }

  m_showPluginsAct->setVisible(false);

  m_setServerlessModeAct->trigger();
}

void ChatWgt::slot_focusChanged(QWidget* old, QWidget* new_)
{
  QChatWidgetPlugin* plug;

  m_trayIcon->setStaticIcon(QChatIcon::iconPath("tray-icon"));

  if(!mw_smiles || !mw_smiles->inited())
    return;

  if(new_ && new_ != m_smilesScrllArea)
    m_smilesScrllArea->hide();

  if(isPLugin(old))
  {
//     m_pluginsToolBar->clear();
    if((plug = isPLugin(new_)))
    {
//       plug->setupToolBar(m_pluginsToolBar);
    }
  }
}

void ChatWgt::slot_processData(QC_DatagramHeader* Hdr)
{
  ChannelWgt* chnnl;

  qDebug("[ChatWgt::slot_processData]: chnnl_name = %s\n", QString().fromUtf8(ChatCore::getParametr("Channel", Hdr->parametrs)).toLocal8Bit().data());
  qDebug("[ChatWgt::slot_processData]: src_ip = %u\n", (uint)Hdr->src_ip);

  // checking if data arrived into private channel
  if(Hdr->chnnl_id == 1)
  {
    // checking is data arrived from us

    // in serverless mode we using IP addresses but in Server - UIDs
    quint64 uid;
    if(QChatSettings::settings()->mode() == QChatSettings::Serverless)
      uid  = QChatSettings::settings()->hostAddressOption("IP").toIPv4Address();
    else
      uid  = UserInfo::myInfo()->uid();

    if(Hdr->src_ip == uid || Hdr->src_ip == 0x7f000001 || Hdr->src_ip == 1)
      chnnl = findChannel(QString().fromUtf8(ChatCore::getParametr("Channel", Hdr->parametrs)));
    else
      chnnl = findChannel(Hdr->src_ip, 1);
  }
  else
    chnnl = findChannel(QString().fromUtf8(ChatCore::getParametr("Channel", Hdr->parametrs)));

  if(chnnl)
  {
    chnnl->processData(Hdr);

    if(Hdr->type == AbstractChatCore::INFO_ANSWER       &&  m_userInfoDlg->readOnly() &&
       m_userInfoDlg->userUid() == Hdr->src_ip && !m_userInfoDlg->isHidden())
      {
        UserWgt* user = chnnl->findUser(Hdr->src_ip);
        if(user)
          m_userInfoDlg->slot_loadInfo(user->info());
      }
  }

  delete Hdr;
}

void ChatWgt::activity()
{

}

void ChatWgt::closeEvent(QCloseEvent * ev)
{
  int res;
  MessageWithCheckBox* mes;
  QMessageBox* mbox;

  if(QChatSettings::settings()->boolOption("WarningAboutHidingInTray"))
  {
    mbox = new QMessageBox;
    mbox->setIcon(QMessageBox::Information);
    mes = new MessageWithCheckBox(tr("Hiding in tray"),
                                  tr("Now QChat will be available from system tray.\n"
                                     "If you want to quit from QChat - use Exit action from menu Chat."),
                                  tr("Don't show this message again"), &res, this);
    mes->setIcon(mbox->iconPixmap());
    mes->exec();
    QChatSettings::settings()->setOption("WarningAboutHidingInTray", res);

    delete mes;
    delete mbox;
  }

  ev->accept();
}

void ChatWgt::slot_showSingleMessagesHistory()
{
  m_smhView->setHidden(!m_smhView->isHidden());
}

void ChatWgt::showSingleMessage(const QModelIndex & idx)
{
  SingleMessage* msg = NULL;
  MessageTreeItem *item = static_cast<MessageTreeItem*>(idx.internalPointer());

  if(item)
    msg = item->message();

  if(msg && !msg->activate())
  {
    SingleMessageWgt* smw = new SingleMessageWgt(msg, msg->isIncoming());
    connect(smw , SIGNAL(singleMessage   (const QString &, quint64, bool)),
            this, SIGNAL(singleMessageOut(const QString &, quint64, bool)));

    smw->show();
  }

}

void ChatWgt::showPlugins()
{
  m_widgetsStack->setCurrentIndex(!m_widgetsStack->currentIndex());
}

QChatWidgetPlugin* ChatWgt::isPLugin(QWidget* wgt)
{
  QTabWidget* tab;
  QChatWidgetPlugin* plugin = NULL;

  tab = qobject_cast<QTabWidget*>(wgt);

  if(tab)
  {
    wgt = tab->currentWidget();
    while(wgt)
    {
      plugin = qobject_cast<QChatWidgetPlugin*>(wgt);
      if(plugin)
        return plugin;

      wgt = wgt->parentWidget();
    }
  }


  while(wgt)
  {
    plugin = qobject_cast<QChatWidgetPlugin*>(wgt);
    if(plugin)
      return plugin;

    wgt = wgt->parentWidget();
  }

  return plugin;
}

void ChatWgt::setupPluginToolBar(QWidget* wgt)
{
  QChatWidgetPlugin* plug = qobject_cast<QChatWidgetPlugin*>(wgt);
  m_pluginsToolBar->clear();

  if(plug)
    plug->setupToolBar(m_pluginsToolBar);
}

void ChatWgt::pluginSwitched()
{
    setupPluginToolBar(mw_tabs->currentWidget());
//   setupPluginToolBar(m_pluginsTabs->currentWidget());
}

void ChatWgt::connect2server()
{
  QStringList m_lastServers = QChatSettings::settings()->strOption("LastServers").split("\n", QString::SkipEmptyParts);
  QStringList m_lastLogins  = QChatSettings::settings()->strOption("LastLogins").split("\n", QString::SkipEmptyParts);

  QString server = !m_lastServers.count() ? QString("127.0.0.1") : m_lastServers[0];

  Login2ServerDlg* dlg = new Login2ServerDlg(&m_lastServers, &m_lastLogins, this, server, UserInfo::myInfo()->nickname());
  bool res;

  dlg->setModal(true);

  connect(dlg       , SIGNAL(wantLogin(QHostAddress, QString)), m_chatCore, SLOT(slot_login(QHostAddress, QString)));
  connect(m_chatCore, SIGNAL(loginFinished(int, QString))     , dlg       , SLOT(loginFinished(int, QString)));
  connect(dlg       , SIGNAL(loginSuccessful())               , this      , SLOT(swapConnectDisconnectAct()));

  res = dlg->exec();

  delete dlg;
}

void ChatWgt::disconnectFromServer()
{
  statusBar()->showMessage(tr("Disconnecting from server..."));
  m_chatCore->disconnectFromServer();
}

void ChatWgt::disconnectedFromServer()
{
  m_disconnectFromServerAct->setVisible(0);
  m_connectToServerAct->setVisible(1);

  statusBar()->showMessage(tr("Disconnected from server"));
  m_setServerlessModeAct->trigger();
}

void ChatWgt::chvisConnectToServerAct()
{
  QAction* act = qobject_cast<QAction*>(sender());
  bool conn;

  if(act)
  {
    switch(act->data().toInt())
    {
      case ChatCore::Server :
        conn = (m_chatCore->tcpReceiver()->state() == QAbstractSocket::ConnectedState);
        m_connectToServerAct->setVisible(!conn);
        m_disconnectFromServerAct->setVisible(conn);
        break;

      case ChatCore::Serverless :
        m_connectToServerAct->setVisible(false);
        m_disconnectFromServerAct->setVisible(false);
    }

    foreach(ChannelWgt* cw, channels())
      cw->slot_refreshUL();
  }
}

UserInfo* ChatWgt::findUser(quint64 uid)
{
  UserWgt* usr;

  foreach(ChannelWgt* cw, mw_channels)
    if((usr = cw->findUser(uid)))
      return usr->info();

  return NULL;
}

void ChatWgt::setIcons()
{
  m_showSettingsAct   ->setIcon(QChatIcon::icon("personal"));
  m_showPreferencesAct->setIcon(QChatIcon::icon("configure"));
  m_exitAct           ->setIcon(QChatIcon::icon("application-exit"));
  m_showSmilesAct     ->setIcon(QChatIcon::icon("emotes"));
  m_addChannelAct     ->setIcon(QChatIcon::icon("tab-new"));
  m_delChannelAct     ->setIcon(QChatIcon::icon("tab-close"));
  m_aboutAct          ->setIcon(QChatIcon::icon("help-about"));
  m_aboutQtAct        ->setIcon(QChatIcon::icon("help-about"));
  m_licenseAct        ->setIcon(QChatIcon::icon("help-about"));
  m_writeSettingsAct  ->setIcon(QChatIcon::icon("write-settings"));
  m_addProfileAct     ->setIcon(QChatIcon::icon("add-profile"));
  m_deleteProfileAct  ->setIcon(QChatIcon::icon("remove-profile"));
  m_renameProfileAct  ->setIcon(QChatIcon::icon("edit-rename"));
}

void ChatWgt::setToolbarsIconsSize()
{
  QAction* act = qobject_cast<QAction*>(sender());

  if(act)
  {
    int sz = act->data().toInt();

    if(!sz)
      sz = QStyle::PM_ToolBarIconSize;

    foreach(QToolBar* tb, m_toolbars)
      tb->setIconSize(QSize(sz, sz));

    QChatSettings::settings()->setToolbarIconsSize(sz);
  }
}

void ChatWgt::setToolButtonsStyle()
{
  QAction* act = qobject_cast<QAction*>(sender());

  if(act)
  {
    Qt::ToolButtonStyle style = (Qt::ToolButtonStyle)(act->data().toInt());

    foreach(QToolBar* tb, m_toolbars)
      tb->setToolButtonStyle(style);
  }
}

void ChatWgt::addToolbar(QToolBar* tb)
{
  m_toolbars.append(tb);
  addToolBar(tb);
}

void ChatWgt::changeIconFormat(const UserListIconFormat & fmt)
{
  *(QChatSettings::settings()->iconFormat()) = fmt;

  foreach(ChannelWgt* ch, channels())
    ch->redrawIcons();
}

void ChatWgt::showConfigureShortcuts()
{
  ShortcutsEditor* dlg = new ShortcutsEditor(0);

  dlg->resize(800, 600);
  dlg->exec();

  delete dlg;

  updateShortcuts();

  m_chatCore->saveSettings(true);
}

void ChatWgt::updateShortcuts()
{
  QChatSettings* prefs = QChatSettings::settings();

  m_showSingleMessagesAct->setShortcut(prefs->shortcut("SingleMessagesHistory"));
  m_showSettingsAct      ->setShortcut(prefs->shortcut("EditUserDetails"));
  m_showPreferencesAct   ->setShortcut(prefs->shortcut("ConfigureQChat"));
  m_exitAct              ->setShortcut(prefs->shortcut("Quit"));
  m_showSmilesAct        ->setShortcut(prefs->shortcut("ShowSmiles"));

  m_addChannelAct        ->setShortcut(prefs->shortcut("AddChannel"));
  m_delChannelAct        ->setShortcut(prefs->shortcut("DelChannel"));

  m_addProfileAct        ->setShortcut(prefs->shortcut("AddProfile"));
  m_deleteProfileAct     ->setShortcut(prefs->shortcut("DelProfile"));
  m_renameProfileAct     ->setShortcut(prefs->shortcut("RenameProfile"));
  m_broadcastMessageAct  ->setShortcut(prefs->shortcut("BroadcastMessage"));

  m_smhView->updateShortcuts();
}

void ChatWgt::sendBroadcastMessage()
{
  SingleMessageWgt* smw = new SingleMessageWgt(tr("Broadcast Message"),
                                               "",
                                               QChatSettings::settings()->broadcast().toIPv4Address(),
                                               QHostAddress("255.255.255.255")
                                               );

  connect(smw , SIGNAL(singleMessage    (QString, quint64, bool)),
          this, SIGNAL(singleMessage    (QString, quint64, bool)));

  smw->show();
}

void ChatWgt::loadPlugin(const QString & path)
{
  qDebug("![ChatWgt::loadPlugin]: loading '%s'\n", path.toAscii().data());

  m_chatCore->pluginManager()->load(path);

  Plugin* loader = m_chatCore->pluginManager()->getPluginByPath(path);

  QChatWidgetPlugin* pluginWgt = NULL;
  QChatBasicPlugin*  plugin = NULL;

  if(loader)
  {
    pluginWgt = loader->instanceWgt();

    if(!pluginWgt)
      plugin = loader->instanceBasic();
    else
      plugin = pluginWgt;

    if(loader->isLoaded() && plugin)
    {
      plugin->setPath(loader->path());
      m_allPlugins.append(loader->instance());
      m_preferencesDlg->addSection(plugin->settingsPage(), plugin->name());

      if(pluginWgt)
      {
//         m_pluginsTabs->addTab(pluginWgt->widget(), pluginWgt->name());
        mw_tabs->addTab(pluginWgt->widget(), pluginWgt->name());
        setupPluginToolBar(m_pluginsTabs->currentWidget());
      }
    }
  }
}

void ChatWgt::unloadPlugin(const QString & path)
{
  qDebug("![ChatWgt::unloadPlugin]: unloading '%s'\n", path.toAscii().data());
  setupPluginToolBar(NULL);

  QChatBasicPlugin* plugin;

  Plugin* loader = m_chatCore->pluginManager()->getPluginByPath(path);

  if(loader)
  {
    plugin = loader->instanceBasic();
    if(plugin)
      m_preferencesDlg->removeSection(plugin->settingsPage());
  }

  m_chatCore->pluginManager()->unload(path);

  setupPluginToolBar(m_pluginsTabs->currentWidget());
}

void ChatWgt::keyPressEvent(QKeyEvent* ev)
{
  QKeySequence seq = ev->key() + ev->modifiers();



  QWidget::keyPressEvent(ev);
}

void ChatWgt::setAnimationsRunning(bool b)
{
  foreach(ChannelWgt* cw, mw_channels)
    cw->setAnimationsRunning(b);
}

void ChatWgt::setMode()
{
  QAction* act = qobject_cast<QAction*>(sender());

  if(act)
    m_chatCore->initMode((ChatCore::Mode)act->data().toInt());

  if((ChatCore::Mode)act->data().toInt() == ChatCore::Server && !m_chatCore->loggedIn())
    connect2server();
}
