/***************************************************************************
                          kmessapplication.cpp -  description
                             -------------------
    begin                : Wed 7 13 2005
    copyright            : (C) 2005 by Diederik van der Boor
    email                : vdboor --at-- codingdomain.com
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/

#include "kmessapplication.h"

#include "accountsmanager.h"
#include "kmess.h"
#include "kmesstest.h"
#include "kmessdebug.h"
#include "utils/crashhandler.h"

#include "config-kmess.h"

#include <KCmdLineArgs>
#include <KIconLoader>
#include <KStandardDirs>



/**
 * The application constructor
 */
KMessApplication::KMessApplication()
  : KApplication()
  , contactListWindow_(0)
  , quitSelected_(false)
{
  // KMessApplication is created from main.cpp.
  // It continues the initialisation of the application.

  // Install a message handler, so KMESS_ASSERT won't do a exit(1) or abort()
  // It makes debugging output on Windows disappear, so don't use it there
#ifndef Q_OS_WIN
  qInstallMsgHandler( kmessDebugPrinter );
#endif

#ifdef KMESSTEST
  kDebug() << "Starting KMess " KMESS_VERSION " on" << QDateTime::currentDateTime().toString( Qt::ISODate );
  kDebug() << "Compiled with KDE" KDE_VERSION_STRING ", Qt" QT_VERSION_STR;
  kDebug() << "Running on KDE" << KDE::versionString() << ", Qt" << qVersion();
#endif

  // Install our crash handler.
  CrashHandler::activate();

  // Start remaining initialisation
  initializePaths();
  initializeMainWindow();
}



/**
 * Destructor
 */
KMessApplication::~KMessApplication()
{
  // automatically destroyed
  contactListWindow_ = 0;
}



/**
 * Return the contact list window
 */
KMess* KMessApplication::getContactListWindow() const
{
  return contactListWindow_;
}



/**
 * Return the server used in test server mode
 */
const QString &KMessApplication::getTestServer() const
{
  return testServerAddress_;
}



/**
 * Return whether to use an alternative server as the Live Service server
 */
bool KMessApplication::getUseTestServer() const
{
  return ( ! testServerAddress_.isEmpty() );
}



/**
 * Initialisation of the main window.
 */
void KMessApplication::initializeMainWindow()
{
  // Fetch the command line arguments
  KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
  QString autologinHandle( args->getOption( "autologin" ) );

  // Enable KDE session restore.
  // We should use KMainWindow's RESTORE macro, or the kRestoreMainWindows
  // macro (see kmainwindow.h).
  // But they create new objects and also restore all windows: we have no
  // point in restoring chat windows. Our initialization process is also
  // different.
  // So we just manually restore the KMess main window, which is the
  // contact list window.
  int restoredWindow = -1;
  if( kapp->isSessionRestored() )
  {
    int n = 0;
    while( KMainWindow::canBeRestored( ++n ) )
    {
#ifdef KMESSDEBUG_KMESSAPPLICATION
      kDebug() << "Checking if window" << n << "named" << KMainWindow::classNameOfToplevel( n ) << "can be restored...";
#endif
      if( KMainWindow::classNameOfToplevel( n ) != QLatin1String( "KMess" ) )
      {
        continue;
      }

#ifdef KMESSDEBUG_KMESSAPPLICATION
      kDebug() << "Contact List window found!";
#endif
      restoredWindow = n;
      break;
    }
  }

  // Create the main window and initialize it
  contactListWindow_ = new KMess( 0 );
  if( ! contactListWindow_->initialize() )
  {
    exit(1);
    return;
  }

  // Initialize KApplication
  setTopWidget( contactListWindow_ );

  // Apply our own quit policy.
  // Only quit when the user wanted to, or KDE is logging out.
  setQuitOnLastWindowClosed( false );
  connect( this, SIGNAL(lastWindowClosed()), this, SLOT(slotLastWindowClosed()) );
  connect( this, SIGNAL(aboutToQuit()),      this, SLOT(slotAboutToQuit()) );

#if ( KMESS_DEBUG == 1 )
  // The debug build allows to use an alternative server
  testServerAddress_ = args->getOption( "server" );

  // The debug build allows to run tests from the command line.
  QString testName( args->getOption( "runtest" ) );
  if( ! testName.isEmpty() )
  {
    // KMessTest is deleted when the app closes
    KMessTest *kmessTest = new KMessTest( contactListWindow_ );
    kmessTest->runTest( testName );
    kmessTest->endTest();
    return;
  }
#endif

  // We found session data for the Contact List, to restore it
  if( kapp->isSessionRestored() && restoredWindow != -1 )
  {
    // Wait for the user passwords
    AccountsManager::instance()->readPasswords( true );

    contactListWindow_->restore( restoredWindow, false );
  }
  else
  {
    // Start auto login if needed, then show the login screen
    contactListWindow_->checkAutologin( autologinHandle );

    if( ! args->isSet( "hidden" ) )
    {
      contactListWindow_->show();
    }
  }
}



/**
 * Initialize additional paths
 */
void KMessApplication::initializePaths()
{
  // Add compile time paths as fallback
  KGlobal::dirs()       -> addPrefix( KMESS_PREFIX );
  KIconLoader::global() -> addAppDir( KMESS_PREFIX "/share" );

  // Test whether the prefix is correct.
  if( KGlobal::dirs()->findResource( "appdata", "pics/kmesspic.png" ).isNull() )
  {
    kWarning() << "KMess could not find resources in the search paths: "
               << KGlobal::dirs()->findDirs( "appdata", QString::null ).join(", ") << endl;
  }
}



/**
 * Called when QCoreApplication notifies the app is really quitting now.
 */
void KMessApplication::slotAboutToQuit()
{
  // No user-interaction is possible here anymore..!

#ifdef KMESSDEBUG_KMESSAPPLICATION
  kDebug() << "KMess is about to quit...";
#endif
}



/**
 * Called when the last window is closed.
 *
 * Also see: KMessInterface::queryClose().
 */
void KMessApplication::slotLastWindowClosed()
{
#ifdef KMESSTEST
  KMESS_ASSERT( quitOnLastWindowClosed() == false );
#endif

  if( quitSelected_ || sessionSaving() )
  {
#ifdef KMESSDEBUG_KMESSAPPLICATION
    kDebug() << "Last window closed, user really wants to quit now. Initiate quit() call.";
#endif

    quit();
  }
  else
  {
#ifdef KMESSDEBUG_KMESSAPPLICATION
    kDebug() << "User closed last window, but keep KMess running with all windows closed.";
#endif
  }
}



/**
 * Return true if quit was selected
 */
bool KMessApplication::quitSelected() const
{
  return quitSelected_;
}



/**
 * Tell the application that quit was selected
 */
void KMessApplication::setQuitSelected(bool quitSelected)
{
  quitSelected_ = quitSelected;
}


#include "kmessapplication.moc"
