/***************************************************************************
 *   Copyright (C) 2004-2006 by Pere Constans
 *   constans@molspaces.com
 *   cb2Bib version 0.6.1
 *   See LICENSE file that comes with this distribution
 ***************************************************************************/
#include "c2bnetwork.h"
#include "cb2bib_par.h"

#include <qnetwork.h>
#include <qnetworkprotocol.h>
#include <qprocess.h>
#include <qprogressdialog.h>
#include <qsettings.h>
#include <qurl.h>


c2bNetwork::c2bNetwork(QObject *parent, const char *name)
        : QObject(parent, name)
{
    pWidget = (QWidget*) parent;
    m_get_error = "";
    m_open_error = "";
    m_fetching = FALSE;
    readSettings();
    connect( pWidget, SIGNAL( newSettingAvailable() ), this, SLOT( readSettings() ) );
    qInitNetworkProtocols();
    connect( &fetcher, SIGNAL( finished(QNetworkOperation*) ), this, SLOT( fetcherEnded(QNetworkOperation*) ) );
    pd = new QProgressDialog( tr("Retrieving..."), "&Cancel", 100, pWidget, "progress", TRUE );
    connect( &fetcher, SIGNAL(dataTransferProgress(int,int,QNetworkOperation*)), pd, SLOT(setProgress(int,int)) );
    connect( pd, SIGNAL(canceled()), this, SLOT(fetcherCancel()) );
    connect( &poster, SIGNAL(done(bool)), this, SLOT(posterEnded(bool)) );
    connect( this, SIGNAL(done_private(bool)), this, SLOT(getFilePrivateDone(bool)) );
}

c2bNetwork::~c2bNetwork()
{}


bool c2bNetwork::openFile( const QString& fn )
{
    // Open NetworkFile through kfmclient_open
    m_open_error = "";
    fmclient = new QProcess( this );
    fmclient->addArgument( m_fmclient_open_bin );
    QStringList arglist = QStringList::split( " ", m_fmclient_open_arg );
    int n = arglist.count();
    for ( int i =0; i < n; i++ )
        fmclient->addArgument( arglist[i] );
    fmclient->addArgument( fn );

    if ( fmclient->start() )
        return TRUE;
    else
    {
        m_open_error = tr( "FM Client '%1' could not be launched.").arg(m_fmclient_open_bin);
        return FALSE;
    }
}

const QString c2bNetwork::openErrorString()
{
    return m_open_error;
}

void c2bNetwork::getFile( const QString& orig, const QString& dest, const QString& action, QObject* receiver, const QString& callback )
{
    if ( m_fetching )
    {
        qWarning("c2bNetwork::getFile: File requested while still fetching previous one. Returned.");
        return;
    }
    disconnect( this, SIGNAL(getFileDone(bool, const QString&)), 0, 0 );
    if( receiver )
        connect( this, SIGNAL(getFileDone(bool, const QString&)), receiver, callback );
    m_fetching = getFilePrivate( orig, dest, action );
    if( !m_fetching )
        emit getFileDone( FALSE, m_get_error );
}

const QString c2bNetwork::getErrorString()
{
    return m_get_error;
}

const QString c2bNetwork::getDestFName()
{
    return destFile;
}

const QString c2bNetwork::getOrigFName()
{
    return origFile;
}

bool c2bNetwork::getFilePrivate( const QString& orig, const QString& dest, const QString& action )
{
    m_get_error = "";
    origFile = orig;
    destFile = dest;
    if ( !checkDest() )
        return FALSE;
    if ( origFile.startsWith("<<post>>") )  // cb2Bib keyword to use post http method
        return postHttp_c2b();
    else
        if ( m_fmclient )
            return getFile_client( action );
        else
            return getFile_c2b( action );
}

void c2bNetwork::getFilePrivateDone( bool status )
{
    m_fetching = FALSE;
    emit getFileDone( status, m_get_error );
}

bool c2bNetwork::getFile_client( const QString& action )
{
    // Getting NetworkFile through kfmclient
    fmclient = new QProcess( this );
    QStringList arglist;
    QString m_fmclient_bin;
    if ( action == "copy" )
    {
        fmclient->addArgument( m_fmclient_copy_bin );
        m_fmclient_bin = m_fmclient_copy_bin;
        arglist = QStringList::split( " ", m_fmclient_copy_arg );
    }
    else if ( action == "move" )
    {
        fmclient->addArgument( m_fmclient_move_bin );
        m_fmclient_bin = m_fmclient_move_bin;
        arglist = QStringList::split( " ", m_fmclient_move_arg );
    }
    int n = arglist.count();
    for ( int i =0; i < n; i++ )
        fmclient->addArgument( arglist[i] );
    fmclient->addArgument( QString( "%1" ).arg(origFile) );
    fmclient->addArgument( QString( "%1" ).arg(destFile) );
    connect( fmclient, SIGNAL(processExited()), this, SLOT(clientEnded()) );

    if ( fmclient->start() )
        return TRUE;
    else
    {
        m_get_error = tr( "FM Client '%1' could not be launched.").arg(m_fmclient_open_bin);
        disconnect( fmclient, SIGNAL(processExited()), this, SLOT(clientEnded()) );
        return FALSE;
    }
}

bool c2bNetwork::getFile_c2b( const QString& action )
{
    // Getting NetworkFile
    QUrl u( origFile );
    pd->setLabelText( tr("Retrieving from %1...").arg(u.host()) );
    fetcher.copy( origFile, destFile, ( action == "move" ), FALSE );
    return TRUE;
}

bool c2bNetwork::postHttp_c2b()
{
    // HTTP Form Posting
    QUrl u( origFile );
    QString host = u.host();
    pd->setLabelText( tr("Retrieving from %1...").arg(host) );
    QString userAgent = "cb2Bib/" + APP_VERSION + " (Bibliographic Browser Tool)";
    QHttpRequestHeader header("POST", u.path()+"/");
    header.setValue("Host", host);
    header.setValue("User-Agent", userAgent);
    header.setContentType("application/x-www-form-urlencoded");
    QString searchString = u.query();
    fDestFile = new QFile( destFile );
    poster.setHost( host );
    poster.request( header, searchString.utf8(), fDestFile );
    return TRUE;
}

void c2bNetwork::fetcherEnded( QNetworkOperation* op )
{
    // Returns true only if destFile is available
    if ( op->errorCode() == 0 )
    {
        if ( op->operation() == QNetworkProtocol::OpPut )
        {
            m_get_error = "";
            emit done_private( TRUE );
        }
        else if ( op->operation() == QNetworkProtocol::OpGet && !op->protocolDetail().isEmpty() )
        {   // User cancellation
            m_get_error = op->protocolDetail();
            emit done_private( FALSE );
        }
    }
    else
    {
        m_get_error = op->protocolDetail();
        emit done_private( FALSE );
    }
}

void c2bNetwork::posterEnded( bool err )
{
    delete fDestFile; // Delete IO device, not the file
    if ( err )
        m_get_error = poster.errorString().latin1();
    else
        m_get_error = "";
    emit done_private( !err );
}

void c2bNetwork::fetcherCancel()
{
    fetcher.stop();
}

void c2bNetwork::clientEnded()
{
    QFile f( destFile );
    if ( f.exists() )
    {
        m_get_error = "";
        emit done_private( TRUE );
    }
    else
    {
        m_get_error = tr("File '%1' has not been written.").arg(origFile);
        emit done_private( FALSE );
    }
}

bool c2bNetwork::checkDest()
{
    // Checks whether or not writing to dest is safe
    // Returns false if file exists
    QFile f( destFile );
    if ( f.exists() )
    {
        m_get_error = tr( "Destination file '%1' already exists." ).arg(destFile);
        return FALSE;
    }
    else
        return TRUE;
}

void c2bNetwork::readSettings()
{
    QSettings settings;
    settings.insertSearchPath( QSettings::Windows, WINDOWS_REGISTRY );
    m_fmclient = settings.readBoolEntry( APP_KEY + "fmclient", APP_FMCLIENT );
    m_fmclient_copy_bin = settings.readEntry( APP_KEY + "fmclient_copy_bin", APP_FMCLIENT_COPY_BIN );
    m_fmclient_move_bin = settings.readEntry( APP_KEY + "fmclient_move_bin", APP_FMCLIENT_MOVE_BIN );
    m_fmclient_open_bin = settings.readEntry( APP_KEY + "fmclient_open_bin", APP_FMCLIENT_OPEN_BIN );
    m_fmclient_copy_arg = settings.readEntry( APP_KEY + "fmclient_copy_arg", APP_FMCLIENT_COPY_ARG );
    m_fmclient_copy_arg = m_fmclient_copy_arg.simplifyWhiteSpace();
    m_fmclient_move_arg = settings.readEntry( APP_KEY + "fmclient_move_arg", APP_FMCLIENT_MOVE_ARG );
    m_fmclient_move_arg = m_fmclient_move_arg.simplifyWhiteSpace();
    m_fmclient_open_arg = settings.readEntry( APP_KEY + "fmclient_open_arg", APP_FMCLIENT_OPEN_ARG );
    m_fmclient_open_arg = m_fmclient_open_arg.simplifyWhiteSpace();
}
