/***************************************************************************
 *   Copyright (C) 2004, 2005 by Johnathan Burchill                        *
 *   jkerrb@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 as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 ***************************************************************************/

#include "KDarInteraction.h"

#include "kdar.h"
#include "controller.h"
#include "kdarListViewItem.h"
#include "kdarProgressEvent.h"
#include "kdarProgressDialogEvent.h"
#include "kdarStatusBarEvent.h"
#include "kdarTarListingEvent.h"
#include "kdarUserInteractionEvent.h"
#include "kdarUserInteractionStringEvent.h"
#include "kdarWarningEvent.h"

#include <kdebug.h>
#include <klocale.h>

#include <qapplication.h>
#include <qregexp.h>
#include <qsemaphore.h>
#include <qstring.h>

#include <dar/libdar.hpp>
#include <dar/erreurs.hpp>

extern kdarListViewItem *currentDirectory;

KDarInteraction::KDarInteraction( controller *aController )
    : libdar::user_interaction()
    , m_controller( aController )
{
    //Tell libdar that we're using our own listing method.
    set_use_listing( true );
}

KDarInteraction::~KDarInteraction()
{
}

KDarInteraction::KDarInteraction( const KDarInteraction & ki ) : libdar::user_interaction()
{
    m_controller = ki.m_controller;
}

KDarInteraction & KDarInteraction::operator= ( const KDarInteraction & ki )
{
    if ( this != & ki )
    {
        m_controller = ki.m_controller;
    }
    return *this;
}

void KDarInteraction::pause( const std::string & message )
{
    //Don't access the GUI directly here because we're not the GUI thread.
    QString userQuestion = message.c_str();
    kdarUserInteractionEvent *questionEvent = new kdarUserInteractionEvent( userQuestion );
    //post the questionEvent
    QApplication::postEvent( m_controller, questionEvent );
    QSemaphore *s = m_controller->semaphore();
    if ( s )
    {
        kdDebug() << "KDarInteraction::pause(): going to sleep..."  << endl;
        (*s)++;
    }
    else
    {
        kdDebug() << "KDarInteraction::pause(): semaphore pointer is 0! Should throw an exception here, eh?" << endl;
    }
    kdDebug() << "KDarInteraction::pause(): waking up!" << endl;
    //What what the user's response?
    bool response = m_controller->userResponse();
    kdDebug() << "KDarInteraction::pause(): User answered " << response << "." << endl;
    //Reset the response to a known value:
    m_controller->setUserResponse( false );
    if ( response == false )
    {
        throw libdar::Euser_abort( message );
    }
}

std::string KDarInteraction::get_string( const std::string & message, bool echo )
{
    //Don't access the GUI directly here because we're not the GUI thread.
    QString question = message.c_str();
    kdarUserInteractionStringEvent *getStringEvent = new kdarUserInteractionStringEvent( question, echo );
    //reset the gotUserResponse boolean:
//    gotUserResponse = false;
    //post the questionEvent
    QApplication::postEvent( m_controller, getStringEvent );
    QSemaphore *s = m_controller->semaphore();
    if ( s )
    {
        kdDebug() << "KDarInteraction::get_string(): going to sleep..."  << endl;
        (*s)++;
    }
    else
    {
        kdDebug() << "KDarInteraction::get_string(): semaphore pointer is 0! Should throw an exception here, eh?" << endl;
    }
    kdDebug() << "KDarInteraction::get_string(): waking up!" << endl;

    //The password is stored in m_controller:
    QString response = "";
    if ( m_controller )
    {
        response = m_controller->password();
        //Clear the password from the m_controller
        m_controller->clearPassword();
    }
    else
    {
        kdDebug() << "KDarInteraction::get_string(): m_controller is 0! Could not get password." << endl;
    }
    return kdar::toStdString( response );
}

void KDarInteraction::warning( const std::string & message )
{
    //We have to post a custom event here to display the message because we're not the GUI thread.
    QString userMessage = message.c_str();
    //Implementing a progress bar that shows the percentage of total files
    //that have been processed, as a function of the total number of files
    //to be processed.

    bool sendToStatusBar = false;
    bool sendToProgressDialog = false;
    bool increaseProgressBar = false;
    int field = 0;

    QRegExp addingRegExp = QRegExp( i18n( "libdar create message", "^Adding file to archive: " ) );
    QRegExp savingEARegExp = QRegExp( i18n( "libdar saving EA message", "^Saving Extended Attributes for " ) );
    QRegExp diffOKRegExp = QRegExp( i18n( "libdar diff message", "^OK   " ) );
    QRegExp testOKRegExp = QRegExp( i18n( "libdar test message", "^OK  <ROOT>" ) );
    QRegExp restoringRegExp = QRegExp( i18n( "libdar restore message", "^Restoring file: " ) );
//    QRegExp extractingRegExp = QRegExp( "^Extracting contents of the archive..." );
    if ( userMessage.contains( addingRegExp ) )
    {
        userMessage.replace( addingRegExp, i18n( "statusbar replacement for creation message", "Adding " ) );
        sendToProgressDialog = true;
        increaseProgressBar = true;
    }
    else if ( userMessage.contains( savingEARegExp ) )
    {
        userMessage.replace( savingEARegExp, i18n( "statusbar replacement for saving EA message", "Saved EA for " ) );
        sendToProgressDialog = true;
        field = 1;
        increaseProgressBar = false;
    }
    else if ( userMessage.contains( diffOKRegExp ) || userMessage.contains( testOKRegExp ) )
    {
        sendToStatusBar = true;
        increaseProgressBar = true;
    }
    else if ( userMessage.contains( restoringRegExp ) )
    {
        userMessage.replace( restoringRegExp, i18n( "statubar replacement for restore message", "Restoring " ) );
        sendToStatusBar = true;
        increaseProgressBar = true;
    }
/*    else if ( userMessage.contains( extractingRegExp ) )
    {
        //Do nothing
        //KDar displays this information.
    }
*/
    if ( sendToStatusBar )
    {
        //Post the statusBar event
        kdarStatusBarEvent *statusEvent = new kdarStatusBarEvent( userMessage, FOREVER );
        QApplication::postEvent( m_controller, statusEvent );
    }
    else if ( sendToProgressDialog )
    {
        //Post the progressDialog event
        kdarProgressDialogEvent *progressEvent = new kdarProgressDialogEvent( userMessage, field );
        QApplication::postEvent( m_controller, progressEvent );
    }
    else
    {
        kdarWarningEvent *warnEvent = new kdarWarningEvent( userMessage );
        QApplication::postEvent( m_controller, warnEvent );
    }
    if ( increaseProgressBar )
    {
        //increase the progress counter
        kdarProgressEvent *addEvent = new kdarProgressEvent( kdarProgressEvent::PROGRESS_INCREASE_ADDED );
        QApplication::postEvent( m_controller, addEvent );
    }

}

libdar::user_interaction * KDarInteraction::clone() const
{
    libdar::user_interaction *ui = new KDarInteraction( *this );
    if ( ui == NULL )
    {
        throw libdar::Ememory( "KDarInteraction::clone" );
    }
    else
    {
        return ui;
    }
}

void KDarInteraction::listing( const std::string & flag, const std::string & perm, const std::string & uid, const std::string & gid, const std::string & size, const std::string & date, const std::string & filename, bool is_dir, bool has_children )
{
    //We have to post a custom event here to display the listing because we're not the GUI thread.
    QString qflag = flag.c_str();
    QString qperm = perm.c_str();
    QString quid = uid.c_str();
    QString qgid = gid.c_str();
    QString qsize = size.c_str();
    QString qdate = date.c_str();
    QString qfilename = filename.c_str();
    bool qisdir = is_dir;
    bool qhaschildren = has_children;

    kdDebug() << "KDarInteraction::listing() reached: posting a tarListing Event." << endl;
    //create and post a new tarListingEvent
    kdarTarListingEvent *tarListingEvent = new kdarTarListingEvent( currentDirectory, qflag, qperm, quid, qgid, qsize, qdate, qfilename, qisdir, qhaschildren );
    QApplication::postEvent( m_controller, tarListingEvent );
}

/*void KDarInteraction::setController( controller *aController )
{
    m_controller = aController;
}
*/
