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

#include <QSplashScreen>
#include <QTime>

#include "chatcore.h"
#include "chatwgt.h"

#include "qchateventfilter.h"
#include "qchaticon.h"
#include "qchatsettings.h"

QChat::QChat(QObject *parent)
 : QObject(parent),
  m_chat(NULL),
  m_core(NULL)
{
}

QChat::~QChat()
{
  qDebug("[QChat::~QChat]\n");

  m_core->saveSettings(true);

  delete m_chat;
  delete m_core;
}

void QChat::start(int argc, char *argv[], QApplication* app)
{
//   QSplashScreen *splash = new QSplashScreen(QPixmap(":/images/splash.png"));

//   splash->show();
  QTime t, tt;
  QChatEventFilter* eventFilter;

  QChatSettings::initGeneralOptions();

  t.start();
  tt.start();

  m_app = app;

  // Processing command line arguments
  // *********************************
  CmdArgs* args = processCmdArgs(argc, argv);

  if(!args->unknown_option.isEmpty())
  {
    unknownOptionMessage(args->unknown_option);

    delete args;
    delete m_core;

    exit(1);
  }

  if(args->show_version)
  {
    printf("%s\n", Globals::VersionStr.toLocal8Bit().data());

    delete args;
    delete m_core;

    exit(0);
  }

  if(args->show_help)
  {
    helpMessage();

    delete args;
    delete m_core;

    exit(0);
  }

  if(args->show_author)
  {
    authorMessage();

    delete args;
    delete m_core;

    exit(0);
  }

  app->setQuitOnLastWindowClosed(false);

  m_core = new ChatCore;

  qDebug("Time elapsed: %d ms", t.restart());
  qDebug("QChat: [Loading settings...]\n");
//   splash->showMessage(tr("Loading settings..."), Qt::AlignBottom | Qt::AlignCenter, Qt::red);

  QChatSettings::setLoggingDir(args->chat_log_dir);

  m_core->initSettings(args->settings_dir);
  m_core->slot_loadSettings();

  if(args->port_in > 0)
    QChatSettings::settings()->setOption("InputPort", (args->port_in));

  if(args->port_out > 0)
    QChatSettings::settings()->setOption("OutputPort", args->port_out);

  delete args;
  // *********************************

  QChatIcon::initIcons();

  qDebug("Time elapsed: %d ms", t.restart());
  qDebug("QChat: [Creating Main Window...]\n");
//   splash->showMessage(tr("Creating Main Window..."), Qt::AlignBottom | Qt::AlignCenter, Qt::red);

  m_chat = new ChatWgt(m_core);
  m_chat->setCursor(QCursor(Qt::WaitCursor));

  m_core->setChatWgt(m_chat);
  m_chat->fillProfilesCmbx(m_core->profiles(), m_core->currentProfile());

  qDebug("Time elapsed: %d ms", t.restart());
  qDebug("QChat: [Starting threads...]\n");
//   splash->showMessage(QObject::tr("Starting threads..."), Qt::AlignBottom | Qt::AlignCenter, Qt::red);

  m_core->startThreads();

  connect(m_chat, SIGNAL(     singleMessageOut  (QString, quint64, bool)),
          m_core, SLOT  (slot_singleMessage     (QString, quint64, bool)));

  connect(m_core, SIGNAL(     singleMessageIn   (SingleMessage*, bool)),
          m_chat, SLOT  (slot_singleMessageIn   (SingleMessage*, bool)));


  connect(m_core, SIGNAL(     privateChatRequest(QString, quint64)),
          m_chat, SLOT  (slot_privateChat       (QString, quint64)));

  connect(m_core, SIGNAL(chatDataReceived(QC_DatagramHeader*)),
          m_chat, SLOT  (slot_processData(QC_DatagramHeader*)));

  connect((QObject*)m_core->tcpReceiver(), SIGNAL(wantReceiveFile (QString, quint16, quint64)),
          m_chat            , SLOT  (slot_receiveFile(QString, quint16, quint64)));

  connect((QObject*)m_core->udpReceiver(), SIGNAL(wantReceiveFile (QString, quint16, quint64)),
          m_chat            , SLOT  (slot_receiveFile(QString, quint16, quint64)));

  connect(app   , SIGNAL(focusChanged(QWidget*, QWidget*)),
          m_chat, SLOT  (slot_focusChanged(QWidget*, QWidget*)));

  connect(m_chat, SIGNAL(closed()),
          app   , SLOT  (quit()));

  connect(m_chat, SIGNAL(wantChangeStyleSheet(QString)), this, SLOT(setStyleSheet(QString)));

  m_core->initPlugins();

  qDebug("Time elapsed: %d ms", t.restart());
  qDebug("QChat: [Creating channel 'Main'...]\n");
//   splash->showMessage(QObject::tr("Creating channel 'Main'..."), Qt::AlignBottom | Qt::AlignCenter, Qt::red);

  m_chat->slot_addChannell("Main");

  qDebug("Time elapsed: %d ms", t.restart());
  qDebug("QChat: [Restoring Window Geometry...]\n");
//   splash->showMessage(tr("Restoring Window Geometry..."), Qt::AlignBottom | Qt::AlignCenter, Qt::red);

  m_chat->restoreAndShow();

  qDebug("Time elapsed: %d ms", t.restart());
  qDebug("QChat: [Finishin initialization]\n");
//   splash->showMessage(tr("Ready to Chat :)"), Qt::AlignBottom | Qt::AlignCenter, Qt::red);

//   splash->finish(m_chat);
  m_chat->setCursor(QCursor(Qt::ArrowCursor));

  eventFilter = new QChatEventFilter(this);
  app->installEventFilter(eventFilter);

  eventFilter->setChatWgt(m_chat);

  AbstractChatCore::setProtocolVersion(QChatSettings::settings()->intOption("ProtocolVersion"));

  connect(eventFilter, SIGNAL(wantHide2Tray()), this, SLOT(hide2tray()));

  qDebug("Time elapsed: %d ms", t.restart());
  qDebug("QChat: [Ready to Chat :)]\n");
  qDebug("Starting Time: %d ms", tt.elapsed());
}

void QChat::reloadStyleSheet()
{
  m_app->setStyleSheet(m_styleSheet);
}

void QChat::setStyleSheet(const QString & filename)
{
  QFile file(filename);
  QByteArray ba;

  file.open(QFile::ReadOnly | QFile::Unbuffered);

  // etogo bolee chem dostatochno, i v sluchae esli budet vybran ochen' bol'shoi fail
  // ne budet popytki zagruzit' ego tselikom v pamyat'
  if(file.size() < 1024 * 1024)
    ba = file.readAll();

  file.close();

  m_styleSheet = QString().fromUtf8(ba);

  m_app->setStyleSheet(m_styleSheet);
}

void QChat::hide2tray()
{
  QWidget* wgt = QApplication::activeWindow();

  if(wgt)
    wgt->close();
}

void QChat::unknownOptionMessage(const QString& msg)
{
  printf("%s\n", tr("Unknown option: %1\nUse -h for list of available options.").arg(msg).toLocal8Bit().data());
}

void QChat::helpMessage()
{
  QString msg;

  msg = tr
  (
  "  List of available options:\n"
  "    -h, --help               Prints this message\n"
  "    -v, --version            Prints version of QChat\n"
  "        --author             Information about author\n"
  "        --settingsdir <dir>  Directory with settings\n"
  "        --logdir      <dir>  Directory for saving chat logs\n"
  );

  printf("%s\n", msg.toLocal8Bit().data());
}

void QChat::welcomeMessage()
{
  printf("%s\n", tr("QChat %1 - Network chat").arg(Globals::VersionStr).toLocal8Bit().data());
}

void QChat::authorMessage()
{
  welcomeMessage();
  printf("%s\n", tr("Author: Ower <ower@users.sourceforge.net>").toLocal8Bit().data());
}

CmdArgs* QChat::processCmdArgs(int argc, char* argv[])
{
  int i;
  CmdArgs* args = new CmdArgs;

  for(i = 1; i < argc; i++)
  {
    if(!strcmp("--logdir", argv[i])){
      if(++i < argc)
        args->chat_log_dir = QString().fromLocal8Bit(argv[i]);}

    else if(!strcmp("--settingsdir", argv[i])){
      if(++i < argc)
        args->settings_dir = QString().fromLocal8Bit(argv[i]);}

    else if(!strcmp("--iport", argv[i])){
      if(++i < argc)
        args->port_in = atoi(argv[i]);}

    else if(!strcmp("--oport", argv[i])){
      if(++i < argc)
        args->port_out = atoi(argv[i]);}

    else if(!strcmp("-h", argv[i]) || !strcmp("--help", argv[i]))
      args->show_help = true;

    else if(!strcmp("-v", argv[i]) || !strcmp("--version", argv[i]))
      args->show_version = true;

    else if(!strcmp("--author", argv[i]))
      args->show_author = true;

    else
    {
      args->unknown_option = argv[i];
      break;
    }
  }

  return args;
}
