/*
 * Copyright (C) 2003,2004,2005 Johnathan Burchill
 * <jkerrb@users.sourceforge.net>
 */

#include "kdar.h"
#include "kdarConfig.h"
#include "kdarSplash.h"
#include "kdartestsdialog.h"
#include "archiveHandle.h"
#include "createArchiveThread.h"
#include "openArchiveThread.h"

#include "kdarcontroller.h"
#include "kdardeclarations.h"

#include <kapplication.h>
#include <dcopclient.h>
#include <kaboutdata.h>
#include <kcmdlineargs.h>
#include <klocale.h>
#include <kconfig.h>
#include <kdebug.h>
#include <kurl.h>

#include <qcstring.h>
#include <qstring.h>
#include <qdir.h>
#include <qfileinfo.h>
#include <qtimer.h>

#include <dar/libdar.hpp>
#include <config.h>

static const char *description =
    I18N_NOOP("KDar: the KDE Disk archiver.");
//
static const char *version = VERSION;

static KCmdLineOptions options[] =
{
        { "create <profile>", I18N_NOOP( "Create an archive from a profile." ), 0 },
        { "restore <profile>", I18N_NOOP( "Restore an archive from a profile." ), 0 },
    { "test-kdar", I18N_NOOP( "Run KDar's test suite." ), 0 },
        { "+[archive]", I18N_NOOP( "Archive to open." ), 0 },
        KCmdLineLastOption
};


int main(int argc, char **argv)
{
    //Are we running from the correct major version of libdar?
    libdar::U_I maj, med, min;
    libdar::get_version(maj, med, min);

    if(maj != libdar::LIBDAR_COMPILE_TIME_MAJOR)
    {
        // abort the program, we are not using the correct library
        std::cout << "kdar: found libdar major version " << maj << "," << std::endl;
        std::cout << "         but kdar requires libdar major version " << libdar::LIBDAR_COMPILE_TIME_MAJOR << "." << std::endl;
        std::cout << "         Please obtain the correct version of libdar." << std::endl;
        return -1;
    }
    //Libdar version:
    QString libdarVersion = QString( "Libdar version " ) + QString( libdar::deci( maj ).human().c_str() + QString( "." ) + libdar::deci( med ).human().c_str() + QString( "." ) + libdar::deci( min ).human().c_str() ) + QString( " cabilities:" );

    //OK to procede! Let's get the compile-time capabilities:
    bool ea, largefile, nodump, special_alloc, thread_safe;
    bool libz, libbz2, libcrypto;
    libdar::U_I bits;

    libdar::get_compile_time_features(ea, largefile, nodump, special_alloc, bits, thread_safe, libz, libbz2, libcrypto );
    if ( !thread_safe )
    {
        std::cout << "kdar: KDar now requires a thread-safe dar library. Please upgrade your libdar, and configure it with thread support." << std::endl;
        return -2;
    }
    //convert the integer bit value to something the QT can handle.
    //The libdar::deci class is very useful indeed!
    libdar::deci deci_bits = libdar::deci(bits);
    QString text_bits = QString("\n   Maximum integer size: ") + QString(deci_bits.human().c_str())+QString(" bits");
    if ( deci_bits.computer() == libdar::infinint( 0 ) ) text_bits = QString( "\n   Maximum integer size: infinite" );
    QString text_libz = QString( "\n   libz compression (gzip): " ) + QString( libz ? "yes" : "no" );
    QString text_libbz2= QString( "\n   libbz2 compression (bzip2): " ) + QString( libbz2 ? "yes" : "no" );
    QString text_libcrypto= QString( "\n   strong encryption: " ) + QString( libcrypto ? "yes" : "no" );
    QString text_ea = QString( "\n   Extended attributes: " ) + QString( ea ? "yes" : "no" );
    QString text_large = QString( "\n   Large files (> 2GB): " ) + QString( largefile ? "yes" : "no" );
    QString text_nodump = QString( "\n   ext3fs \"NODUMP\" flag: " ) + QString( nodump ? "yes" : "no" );
    QString text_special_alloc = QString( "\n   Special memory allocation: " ) + QString( special_alloc ? "yes" : "no" );
    //Don't need to display thread-safe status --- if the library is not thread-safe we will never get to this point anyway.
    //Might as well let people know it's thread-safe:
    QString thread_safe_library = QString( "\n   Thread-safe library: " ) + QString( thread_safe ? "yes" : "no" );
    QString compile_features = libdarVersion + text_libz + text_libbz2 + text_libcrypto + text_ea + text_large + text_nodump + text_special_alloc + text_bits + thread_safe_library;

    //Add the program, author, credit, etc., information to the "About" dialog:
    KAboutData about("kdar", I18N_NOOP("KDar"), version, description,
    KAboutData::License_GPL, "(C) 2003, 2004, 2005 Johnathan K. Burchill", compile_features, "http://kdar.sourceforge.net", "jkerrb@users.sourceforge.net");
    about.addAuthor( "Johnathan K. Burchill", "Development", "jkerrb@users.sourceforge.net", "http://members.shaw.ca/jkerrb");
    about.addCredit( "Denis Corbin", I18N_NOOP("For writing and maintaining libdar, \n and for answering my questions about the API."), 0, "http://sourceforge.net/projects/dar");
    about.addCredit( "Mark McSweeny", I18N_NOOP( "For an in-depth tutorial on C++ programming techniques and pitfalls.\nAlso for suggesting the polling method for cancelling libdar operations, among other things. Cheers." ), 0, 0);
    about.addCredit( "Sven Bergner", I18N_NOOP("Code cleanups in kdar-1.0-beta1"), 0, 0);
    about.addCredit( "Simon Batchelor, Walter Gray, Andreas Pour, Christos Francheteau, Aad Rijnberg", I18N_NOOP("For reporting compilation problems/fixes."), 0, 0);
    about.addCredit( "WWagner", I18N_NOOP("For reporting directory include/exclude problem."), 0, 0);
    about.addCredit( "Alban Minassian", I18N_NOOP("For reporting directory filter bug, along with fix. Also for suggesting that \n a double-click on the archive name should list the contents in the file browser."), 0, 0);
    about.addCredit( "Eugenia Loli-Queru", I18N_NOOP("For reporting the crash due to missing directory in new archive paths.\nAlso for suggesting that a default backup directory be used,\nso users can enter archive names without a full path."), 0, 0);
    about.addCredit( "Daniel Nelson", I18N_NOOP( "For reporting the missing directory filters bug (#995601)" ), 0, 0 );
    about.addCredit( "Andrew E. Schulman", I18N_NOOP( "For reporting the unsaved execute command bug (#995780),\nthe endless-loop bug (#995772), the missing archive name bug (#996539), \nand many others!. Also for suggesting many features." ), 0, 0 );
    about.addCredit( "Axel Braun", I18N_NOOP( "For reporting the unexpected archive problem when directory filters are not subdirectories of the root (bug#1061114)." ), 0, 0);
    about.addCredit( "Peter Landgren", I18N_NOOP( "For reporting the \"//\" crash (bug#1071164), and the total time display error (bug#1076005)." ), 0, 0);
    about.addCredit( "Hans-Ulrich Steck", I18N_NOOP( "For reporting the problem where filters were not set when loading a new profile (bug#1044696)." ), 0, 0);
    about.addCredit( "Gour", I18N_NOOP( "For reporting the Gentoo 64-bit configure problem (bug#1075570)." ), 0, 0);
    about.addCredit( "nathanv", I18N_NOOP( "For reporting the individual file restore bug#1088069)." ), 0, 0);
    about.addCredit( "Jeffrey Ratcliffe", I18N_NOOP( "For reporting the export command bugs #1097255 and #1097257." ), 0, 0);
    about.addCredit( "Anders Lund", I18N_NOOP( "For several suggestions concerning kdar profiles. Also for finding the problem with the default storage directory set to \"/\". (bug#1102120)" ), 0, 0);
    about.addCredit( "Mark Richards", I18N_NOOP( "For reporting the export command missing basename bug#1098706." ), 0, 0);
    about.addCredit( "Philippe C. Martin", I18N_NOOP( "For reporting the wrong media bug#1190416." ), 0, 0);
    about.addCredit( "Michael Zaugg", I18N_NOOP( "For reporting the export command -A bug#1293717." ), 0, 0);

    //initialize the commandline procressing
    KCmdLineArgs::init(argc, argv, &about);
    KCmdLineArgs::addCmdLineOptions(options);
    //Let's get the program going:
    KApplication app;

    // register it as a dcop client
    app.dcopClient()->registerAs(app.name(), false);

    KDarController *kdarcontroller = new KDarController;
    //Session management stuff?
    if (app.isRestored())
    {
        RESTORE( kdar( kdarcontroller ) );
    }
    else
    {
        //Parse the commandline:
        KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
        QCString createProfile = args->getOption( "create" );
        QCString restoreProfile = args->getOption( "restore" );
        if ( args->isSet( "test-kdar" ) )
        {
            KDarTestsDialog * testWidget = new KDarTestsDialog;
            testWidget->show();
            int ret = app.exec();
            if ( kdarcontroller )
            {
                delete kdarcontroller;
                kdarcontroller = 0;
            }
            return ret;
        }
        kdar *widget = new kdar( kdarcontroller );
        if ( !createProfile.isEmpty() )
        {
            //Create an archive based on the profile
            std::cout << "main(): creating archive from " << createProfile << std::endl;
            //instantiate a KDarConfig using the supplied creation profile.
            KDarConfig * createConfig = new KDarConfig();
            KConfig* newConfig = new KConfig( createProfile, false, false );
            createConfig->setGlobalConfig( newConfig );
            createConfig->readGlobalSettings();
            //Insert full path into archiveBaseTest if necessary.
            QString archiveBaseTest = createConfig->newArchiveName();
            if ( archiveBaseTest[0] != '/' )
            {
                //User wants to override the default storage directory.
                KURL archiveStorageDirKURL( createConfig->archiveStorageDirectory() );
                createConfig->setNewArchiveName( archiveStorageDirKURL.path(1) + archiveBaseTest );
            }
            kdDebug() << "main(): createConfig->newArchiveName(): " << createConfig->newArchiveName() << endl;
            kdDebug() << "main(): createConfig->newArchiveName(): " << createConfig->newArchiveName() << endl;
            //Do not pause between slices: this feature is supposed to be
            //automatic.
            createConfig->setPauseBetweenSlices( false );
            //This is a commandline option: no GUI to display messages in.
            //This will change when we have a logfile.
            createConfig->setVerbose( false );
            //Ask the controller to create the archive, and wait for the
            //operation to finish. The boolean in createArchive() tells the
            //controller not to update the listView with the reference archive,
            //if there is one.
            kdarcontroller->createArchive( createConfig, false );
            kdarcontroller->waitForThread( controller::CREATE_THREAD );

            if ( kdarcontroller )
            {
                delete kdarcontroller;
                kdarcontroller = 0;
            }
            return 0;
        }
        else if ( !restoreProfile.isEmpty() )
        {
            //Restore an archive based on the profile
            std::cout << "main(): restoring archive from " << restoreProfile << std::endl;
            if ( kdarcontroller )
            {
                delete kdarcontroller;
                kdarcontroller = 0;
            }
            return 0;
        }
        else if ( args->count() > 0 )
        {
            //Get the archive to open and open it:
            QFileInfo archiveName( QFile::decodeName( args->arg( 0 ) ) );
            archiveHandle archiveHndl( archiveName.absFilePath() );
            QFileInfo firstArchiveSlice( archiveHndl.getArchivePath() + "/" + archiveHndl.getArchiveBasename() + ".1." + EXTENSION );
            if ( firstArchiveSlice.exists() )
            {
                widget->slotArchiveChoose( firstArchiveSlice.absFilePath() );
            }
            else
            {
                std::cout << "kdar: archive \"" << firstArchiveSlice.absFilePath() << "\" not found." << std::endl;
                std::cout << "kdar: archive \"" << archiveName.absFilePath() << "\" not found." << std::endl;
                if ( kdarcontroller )
                {
                    delete kdarcontroller;
                    kdarcontroller = 0;
                }
                return 1;
            }
        }
        //Run KDarSplash
        KDarSplash * splash = 0;
        app.config()->setGroup( "General" );
        if ( app.config()->readBoolEntry("showKDarSplashScreen", true ) )
        {
            splash = new KDarSplash( 0 );
            //splash->connect( &app, SIGNAL( initializationInfo( const QString& ) ), SLOT( addInfo( const QString& ) ) );
            //Kill splash in 3 seconds
            splash->show();
            QTimer::singleShot( 3000, splash, SLOT( close() ) );
            //This is ridiculous!
            QTimer::singleShot( 3000, widget, SLOT( show() ) );
        }
        else
        {
            widget->show();
        }
    }
    //Run KDar
    int result = app.exec();
    if ( kdarcontroller )
    {
        delete kdarcontroller;
        kdarcontroller = 0;
    }
    return result;
}

