/* ====================================================================
 * Copyright (c) 2003-2009  Martin Hauner
 *                          http://subcommander.tigris.org
 *
 * Subcommander is licensed as described in the file doc/COPYING, which
 * you should have received as part of this distribution.
 * ====================================================================
 */

// sc
#include "config.h"
#include "MainWindow.h"
#include "ScModel.h"
#include "Repository.h"
#include "ConfigManager.h"
#include "Settings.h"
#include "sublib/Utility.h"
#include "sublib/ErrorDialog.h"
#include "sublib/MacStyle.h"
#include "sublib/TargetRepository.h"
#include "sublib/MsgHandler.h"
#include "sublib/IconFactory.h"
#include "svn/svn.h"
#include "util/apr.h"
#include "util/Exception.h"
#include "tests/testrunner.h"

// qt
#include <QtGui/QApplication>
#include <QtGui/QStyleFactory>
#include <QtCore/QtPlugin>

#ifdef SC_HAVE_NEON
#include <neon/ne_socket.h>
#include <neon/ne_utils.h>
#endif // SC_HAVE_NEON

#ifdef SC_HAVE_SERF
#include <serf-0/serf.h>
#endif // SC_HAVE_SERF

// openssl
#include <openssl/evp.h>
#include <openssl/err.h>

// required for the static MacOSX qt build to use the plugin.
#ifdef _MACOSX
Q_IMPORT_PLUGIN(qmng)
#endif // _MACOSX


// cleanup neon/ssl stuff to avoid a lot of noise when running with
// memory leak detection.

void exit_ssl()
{
#ifdef _WIN32
  /* clean up (memory) allocations by SSL_library_init(),
  an SSL_library_exit() wouldn't be bad... */
  EVP_cleanup(); 

  /* clean up (memory) allocations by SSL_load_error_strings */
  ERR_free_strings();
#endif // _WIN32
}

void exit_neon()
{
#ifdef _WIN32
  ne_sock_exit();
#endif // _WIN32
}


/** main for running the tests. */
int maintst( int argc, char* argv[] )
{
#ifdef SC_EMBED_TESTRUNNER
  return testrunner(argc,argv);
#else
  fprintf( stderr, "Subcommander was not build with test code!" );
  return EXIT_SUCCESS;
#endif // SC_EMBED_TESTRUNNER 
}

/** main for running the application. */
int mainsc( int argc, char* argv[] )
{
  QApplication* app = 0;
  try
  {
    setLocale();

    // init stacktrace
    initStackProcess();

    // init apr
    apr::initialize(argc,argv);

    // init target repository
    TargetRepository::setup();

    // init qt
    app = new QApplication( argc, argv );
    setAppName("subcommander");
    setPluginPath();
    Q_INIT_RESOURCE(sublib);

#if SC_HAVE_NEON
    setNeonVersion( ne_version_string() );
#endif // SC_HAVE_NEON
#if SC_HAVE_SERF
    setSerfVersion( SERF_VERSION_STRING );
#endif // SC_HAVE_SERF

#ifdef Q_WS_X11
    // set icon
    app->setWindowIcon(IconFactory::createIcon("Logo_Icon_16x16.png"));
#endif // Q_WS_X11
  }
  catch( sc::Exception& e )
  {
    // no way to bring up a dialog if something went wrong in the basic
    // initialization.

    fprintf( stderr, e.getError()->getMessage() );
    return EXIT_FAILURE;
  }

  try
  {
    // read config
    ConfigManager config;
    Settings::setup(config);
    config.load();

    // set font
    // if we set the font allthough it is the same font as the default (system)
    // font we get a different font in popup menus. Looks like a bug in Qt 3.
    if( qApp->font() != config.getGeneralFont() )
    {
      QApplication::setFont( config.getGeneralFont() );
    }

    // setup locale path
    enableLocale( config.getL10n() );

    // set the working copy admin directory name
    svn::setAspDotNetAdmDir( config.getAspDotNetHack() );

    // setup main model
    ScModel model( &config );

    // setup gui
    MainWindow* mw = new MainWindow(&model,&config);
    qApp->setMainWidget(mw);

    // run gui
    mw->show();
    mw->runWcAutoUpdate();
    long result = app->exec();

    delete mw;
    delete app;

    model.saveProjects();
    //config.save();

    exit_ssl();
    exit_neon();

    TargetRepository::teardown();
    stopStackProcess();

    return result;
  }
  catch( sc::Exception& e )
  {
    ErrorDialog* dlg = new ErrorDialog( e );
    dlg->exec();

    return EXIT_FAILURE;
  }
}

int main( int argc, char* argv[] )
{
  if( argc >= 1 && sc::String("-test") == argv[1] )
    return maintst(argc,argv);
  else
    return mainsc(argc,argv);
}

#if 0
// boost
#include <boost/function.hpp>
#include <boost/bind.hpp>

typedef boost::function<void (int, int)> callback_t; 

class foo
{
public:
  void callback( int a, int b )
  {
    int y = a + b;
  }
};

class bar
{
public:
  void callthecallback( boost::function<void (int, int)> cb )
  {
    cb( 1, 2 );
  }

  void callthecallback2( callback_t cb )
  {
    cb( 1, 2 );
  }
};

void x( int a, int b )
{
  int y = a + b;
}

  bar b;
  foo f;

  b.callthecallback( x );
  b.callthecallback( boost::bind(foo::callback,&f,_1,_2) );
#endif
