/***************************************************************************
 *   Copyright (C) 2004-2009 by Thomas Fischer                             *
 *   fischer@unix-ag.uni-kl.de                                             *
 *                                                                         *
 *   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.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/
#include <tqlayout.h>
#include <tqlabel.h>
#include <tqspinbox.h>
#include <tqbuffer.h>
#include <tqfile.h>

#include <kpushbutton.h>
#include <tdelocale.h>
#include <kcombobox.h>
#include <kiconloader.h>
#include <tdeio/jobclasses.h>
#include <tdeio/job.h>
#include <tdeio/netaccess.h>

#include "settings.h"
#include "fileimporterris.h"
#include "webquerysciencedirect.h"

namespace KBibTeX
{
    WebQueryScienceDirectWidget::WebQueryScienceDirectWidget( TQWidget *parent, const char *name )
            : WebQueryWidget( parent, name )
    {
        init();

        TQString allValues;
        Settings *settings = Settings::self();
        TQString value = settings->getWebQueryDefault( "ScienceDirect_title" );
        value = value == TQString::null ? "" : value;
        lineEditQuery->setText( value );
        allValues += value;
        value = settings->getWebQueryDefault( "ScienceDirect_author" );
        value = value == TQString::null ? "" : value;
        lineEditAuthor->setText( value );
        allValues += value;
        value = settings->getWebQueryDefault( "ScienceDirect_journal" );
        value = value == TQString::null ? "" : value;
        lineEditJournal->setText( value );
        allValues += value;
        value = settings->getWebQueryDefault( "ScienceDirect_volume" );
        value = value == TQString::null ? "" : value;
        lineEditVolume->setText( value );
        allValues += value;
        value = settings->getWebQueryDefault( "ScienceDirect_issue" );
        value = value == TQString::null ? "" : value;
        lineEditIssue->setText( value );
        allValues += value;
        value = settings->getWebQueryDefault( "ScienceDirect_page" );
        value = value == TQString::null ? "" : value;
        lineEditPage->setText( value );
        allValues += value;

        slotTextChanged( allValues, true );
    }

    void WebQueryScienceDirectWidget::init()
    {
        TQVBoxLayout *vLayout = new TQVBoxLayout( this, 0, KDialog::spacingHint() );

        TQHBoxLayout *hLayout = new TQHBoxLayout( );
        vLayout->addLayout( hLayout );
        KPushButton *clearSearchText = new KPushButton( this );
        clearSearchText->setIconSet( TQIconSet( SmallIcon( "locationbar_erase" ) ) );
        hLayout->addWidget( clearSearchText );
        TQLabel *label = new TQLabel( i18n( "Title, abstract, keywords:" ), this );
        hLayout->addWidget( label );
        lineEditQuery = new KLineEdit( this );
        TDECompletion *completionQuery = lineEditQuery->completionObject();
        hLayout->addWidget( lineEditQuery );
        label->setBuddy( lineEditQuery );
        connect( clearSearchText, TQ_SIGNAL( clicked() ), lineEditQuery, TQ_SLOT( clear() ) );
        connect( lineEditQuery, TQ_SIGNAL( textChanged( const TQString& ) ), this, TQ_SLOT( slotTextChangedSD( ) ) );
        hLayout->setStretchFactor( lineEditQuery, 7 );
        connect( lineEditQuery, TQ_SIGNAL( returnPressed() ), this, TQ_SIGNAL( startSearch() ) );
        connect( lineEditQuery, TQ_SIGNAL( returnPressed( const TQString& ) ), completionQuery, TQ_SLOT( addItem( const TQString& ) ) );


        hLayout = new TQHBoxLayout( );
        vLayout->addLayout( hLayout );

        KPushButton *clearAuthor = new KPushButton( this );
        clearAuthor->setIconSet( TQIconSet( SmallIcon( "locationbar_erase" ) ) );
        hLayout->addWidget( clearAuthor );
        label = new TQLabel( i18n( "Author:" ), this );
        hLayout->addWidget( label );
        lineEditAuthor = new KLineEdit( this );
        completionQuery = lineEditAuthor->completionObject();
        hLayout->addWidget( lineEditAuthor );
        label->setBuddy( lineEditAuthor );
        connect( clearAuthor, TQ_SIGNAL( clicked() ), lineEditAuthor, TQ_SLOT( clear() ) );
        connect( lineEditAuthor, TQ_SIGNAL( textChanged( const TQString& ) ), this, TQ_SLOT( slotTextChangedSD( ) ) );
        hLayout->setStretchFactor( lineEditAuthor, 7 );
        connect( lineEditAuthor, TQ_SIGNAL( returnPressed() ), this, TQ_SIGNAL( startSearch() ) );
        connect( lineEditAuthor, TQ_SIGNAL( returnPressed( const TQString& ) ), completionQuery, TQ_SLOT( addItem( const TQString& ) ) );

        hLayout->addSpacing( KDialog::spacingHint() * 2 );

        KPushButton *clearJournal = new KPushButton( this );
        clearJournal->setIconSet( TQIconSet( SmallIcon( "locationbar_erase" ) ) );
        hLayout->addWidget( clearJournal );
        label = new TQLabel( i18n( "Journal/book title:" ), this );
        hLayout->addWidget( label );
        lineEditJournal = new KLineEdit( this );
        completionQuery = lineEditJournal->completionObject();
        hLayout->addWidget( lineEditJournal );
        label->setBuddy( lineEditJournal );
        connect( clearJournal, TQ_SIGNAL( clicked() ), lineEditJournal, TQ_SLOT( clear() ) );
        connect( lineEditJournal, TQ_SIGNAL( textChanged( const TQString& ) ), this, TQ_SLOT( slotTextChangedSD( ) ) );
        hLayout->setStretchFactor( lineEditJournal, 4 );
        connect( lineEditJournal, TQ_SIGNAL( returnPressed() ), this, TQ_SIGNAL( startSearch() ) );
        connect( lineEditJournal, TQ_SIGNAL( returnPressed( const TQString& ) ), completionQuery, TQ_SLOT( addItem( const TQString& ) ) );

        hLayout = new TQHBoxLayout( );
        vLayout->addLayout( hLayout );

        label = new TQLabel( i18n( "Volume:" ), this );
        hLayout->addWidget( label );
        lineEditVolume = new KLineEdit( this );
        hLayout->addWidget( lineEditVolume );
        hLayout->setStretchFactor( lineEditVolume, 1 );
        label->setBuddy( lineEditVolume );
        connect( lineEditVolume, TQ_SIGNAL( returnPressed() ), this, TQ_SIGNAL( startSearch() ) );

        hLayout->addSpacing( KDialog::spacingHint() * 2 );

        label = new TQLabel( i18n( "Issue:" ), this );
        hLayout->addWidget( label );
        lineEditIssue = new KLineEdit( this );
        hLayout->addWidget( lineEditIssue );
        label->setBuddy( lineEditIssue );
        hLayout->setStretchFactor( lineEditIssue, 1 );
        connect( lineEditIssue, TQ_SIGNAL( returnPressed() ), this, TQ_SIGNAL( startSearch() ) );

        hLayout->addSpacing( KDialog::spacingHint() * 2 );

        label = new TQLabel( i18n( "Page:" ), this );
        hLayout->addWidget( label );
        lineEditPage = new KLineEdit( this );
        hLayout->addWidget( lineEditPage );
        hLayout->setStretchFactor( lineEditPage, 1 );
        label->setBuddy( lineEditPage );
        connect( lineEditPage, TQ_SIGNAL( returnPressed() ), this, TQ_SIGNAL( startSearch() ) );

        hLayout->addSpacing( KDialog::spacingHint() * 2 );

        label = new TQLabel( i18n( "&Number of results:" ), this );
        hLayout->addWidget( label );
        spinBoxMaxHits = new TQSpinBox( 1, 100, 1, this );
        spinBoxMaxHits->setValue( 10 );
        hLayout->addWidget( spinBoxMaxHits );
        hLayout->setStretchFactor( spinBoxMaxHits, 1 );
        label->setBuddy( spinBoxMaxHits );
        hLayout->addStretch( 5 );
    }

    void WebQueryScienceDirectWidget::slotTextChangedSD()
    {
        TQString text = lineEditQuery->text().stripWhiteSpace().append( lineEditAuthor->text().stripWhiteSpace() ).append( lineEditJournal->text().stripWhiteSpace() ).replace( '$', "" );
        emit enableSearch( !text.isEmpty() );
    }

    WebQueryScienceDirect::WebQueryScienceDirect( TQWidget* parent ): WebQuery( parent )
    {
        m_importer = new BibTeX::FileImporterBibTeX( false );
        m_importer->setIgnoreComments( true );
        m_widget = new WebQueryScienceDirectWidget( parent );
    }

    WebQueryScienceDirect::~WebQueryScienceDirect()
    {
        delete m_widget;
        delete m_importer;
    }

    TQString WebQueryScienceDirect::title()
    {
        return i18n( "ScienceDirect" );
    }

    TQString WebQueryScienceDirect::disclaimer()
    {
        return i18n( "About ScienceDirect" );
    }

    TQString WebQueryScienceDirect::disclaimerURL()
    {
        return "http://info.sciencedirect.com/";
    }

    WebQueryWidget *WebQueryScienceDirect::widget()
    {
        return m_widget;
    }

    void WebQueryScienceDirect::query()
    {
        WebQuery::query();

        Settings *settings = Settings::self();
        settings->setWebQueryDefault( "ScienceDirect_author", m_widget->lineEditAuthor->text() );
        settings->setWebQueryDefault( "ScienceDirect_journal", m_widget->lineEditJournal->text() );
        settings->setWebQueryDefault( "ScienceDirect_volume", m_widget->lineEditVolume->text() );
        settings->setWebQueryDefault( "ScienceDirect_issue", m_widget->lineEditIssue->text() );
        settings->setWebQueryDefault( "ScienceDirect_page", m_widget->lineEditPage->text() );

        TQString tak = m_widget->lineEditQuery->text().stripWhiteSpace().replace( '$', "" ).replace( "%", "%25" ).replace( "+", "%2B" ).replace( " ", "%20" ).replace( "#", "%23" ).replace( "&", "%26" ).replace( "?", "%3F" );
        TQString author = m_widget->lineEditAuthor->text().stripWhiteSpace().replace( '$', "" ).replace( "%", "%25" ).replace( "+", "%2B" ).replace( " ", "%20" ).replace( "#", "%23" ).replace( "&", "%26" ).replace( "?", "%3F" );
        TQString journal = m_widget->lineEditJournal->text().stripWhiteSpace().replace( '$', "" ).replace( "%", "%25" ).replace( "+", "%2B" ).replace( " ", "%20" ).replace( "#", "%23" ).replace( "&", "%26" ).replace( "?", "%3F" );
        TQString volume = m_widget->lineEditVolume->text().stripWhiteSpace().replace( '$', "" ).replace( "%", "%25" ).replace( "+", "%2B" ).replace( " ", "%20" ).replace( "#", "%23" ).replace( "&", "%26" ).replace( "?", "%3F" );
        TQString issue = m_widget->lineEditIssue->text().stripWhiteSpace().replace( '$', "" ).replace( "%", "%25" ).replace( "+", "%2B" ).replace( " ", "%20" ).replace( "#", "%23" ).replace( "&", "%26" ).replace( "?", "%3F" );
        TQString page = m_widget->lineEditPage->text().stripWhiteSpace().replace( '$', "" ).replace( "%", "%25" ).replace( "+", "%2B" ).replace( " ", "%20" ).replace( "#", "%23" ).replace( "&", "%26" ).replace( "?", "%3F" );

        if ( tak.isEmpty() && author.isEmpty() && journal.isEmpty() )
        {
            setEndSearch( WebQuery::statusInvalidQuery );
            return;
        }

        setNumStages( 4 );

        if ( !getStartPage() ) return;

        if ( !getResultPage( tak, author, journal, volume, issue, page ) ) return;

        if ( !getArticleListPage() ) return;

        if ( !getRISFile() ) return;
    }

    bool  WebQueryScienceDirect::getStartPage()
    {
        TQString startPage = downloadHTML( KURL( "http://www.sciencedirect.com/" ) );
        if ( m_aborted )
        {
            setEndSearch( WebQuery::statusAborted );
            return false;
        }
        else if ( startPage == TQString::null )
        {
            setEndSearch( WebQuery::statusError );
            return false;
        }

        int pos = startPage.find( "<input type=\"hidden\" name=\"_acct\" value=\"" );
        if ( pos < 0 )
        {
            setEndSearch( WebQuery::statusError );
            return false;
        }
        m_account = startPage.mid( pos + 41, startPage.find( "\"", pos + 43 ) - pos - 41 );
        pos = startPage.find( "<input type=\"hidden\" name=\"md5\" value=\"" );
        if ( pos < 0 )
        {
            setEndSearch( WebQuery::statusError );
            return false;
        }
        m_md5 = startPage.mid( pos + 39, startPage.find( "\"", pos + 41 ) - pos - 39 );

        return true;
    }

    bool WebQueryScienceDirect::getResultPage( const TQString &tak, const TQString &author, const TQString &journal, const TQString &volume, const TQString &issue, const TQString &page )
    {
        KURL url = KURL( TQString( "http://www.sciencedirect.com/science?_ob=QuickSearchURL&_method=submitForm&qs_tak=" ).append( tak ).append( "&qs_author=" ).append( author ).append( "&qs_title=" ).append( journal ).append( "&qs_vol=" ).append( volume ).append( "&qs_issue=" ).append( issue ).append( "&qs_pages=" ).append( page ).append( "&_acct=" ).append( m_account ).append( "&md5=" ).append( m_md5 ).append( "&x=0&y=0&=Submit" ) );
        TQString resultPage = downloadHTML( url );
        if ( m_aborted )
        {
            setEndSearch( WebQuery::statusAborted );
            return false;
        }
        else if ( resultPage == TQString::null )
        {
            setEndSearch( WebQuery::statusError );
            return false;
        }

        int pos = resultPage.find( "<input type=\"hidden\" name=\"_ArticleListID\" value=" );
        if ( pos < 0 )
        {
            setEndSearch( WebQuery::statusError );
            return false;
        }
        m_articleListID = resultPage.mid( pos + 49, resultPage.find( ">", pos + 50 ) - pos - 49 );
        pos = resultPage.find( "<input type=\"hidden\" name=\"md5\" value=\"" );
        pos = resultPage.find( "<input type=\"hidden\" name=\"md5\" value=\"" , pos + 2 );
        if ( pos < 0 )
        {
            setEndSearch( WebQuery::statusError );
            return false;
        }
        m_md5 = resultPage.mid( pos + 39, 32 );
        pos = resultPage.find( "_userid=" );
        if ( pos < 0 )
        {
            setEndSearch( WebQuery::statusError );
            return false;
        }
        m_userid = resultPage.mid( pos + 8, resultPage.find( "&", pos + 9 ) - pos - 8 );

        return true;
    }

    bool WebQueryScienceDirect::getArticleListPage()
    {
        KURL url = KURL( TQString( "http://www.sciencedirect.com/science?_ob=ArticleListURL&_method=tag&refSource=search&_st=13&_chunk=0&NEXT_LIST=1&view=c&md5=%1&_ArticleListID=%2&sisr_search=&sisrterm=&export=Export+Citations&count=%3" ).arg( m_md5 ).arg( m_articleListID ).arg( m_widget->spinBoxMaxHits->value() ) );
        TQString articleListPage = downloadHTML( url );
        if ( m_aborted )
        {
            setEndSearch( WebQuery::statusAborted );
            return false;
        }
        else if ( articleListPage == TQString::null )
        {
            setEndSearch( WebQuery::statusError );
            return false;
        }
        else if ( articleListPage.find( "subscription does not entitle" ) >= 0 )
        {
            tqWarning( "Your subscription does not entitle you to access the download feature of ScienceDirect" );
            setEndSearch( WebQuery::statusInsufficientPermissions );
            return false;
        }

        int pos = articleListPage.find( "<input type=hidden name=md5 value=" );
        if ( pos < 0 )
        {
            setEndSearch( WebQuery::statusError );
            return false;
        }
        m_md5 = articleListPage.mid( pos + 34, articleListPage.find( ">", pos + 36 ) - pos - 34 );
        pos = articleListPage.find( "<input type=hidden name=_ArticleListID value=" );
        if ( pos < 0 )
        {
            setEndSearch( WebQuery::statusError );
            return false;
        }
        m_articleListID = articleListPage.mid( pos + 45, articleListPage.find( ">", pos + 46 ) - pos - 45 );

        return true;
    }

    bool WebQueryScienceDirect::getRISFile()
    {
        m_incomingData = "";
        TQString data = TQString( "_ob=DownloadURL&_method=finish&_acct=%1&_userid=%2&_ArticleListID=%3&count=10&md5=%4&JAVASCRIPT_ON=&format=cite&citation-type=RIS&RETURN_URL=http://www.sciencedirect.com/science/home" ).arg( m_account ).arg( m_userid ).arg( m_articleListID ).arg( m_md5 );
        KURL url = KURL( "http://www.sciencedirect.com/science" );
        TDEIO::TransferJob *job = TDEIO::http_post( url, data.utf8(), false );
        job->addMetaData( "content-type", "Content-Type: application/x-www-form-urlencoded" );
        connect( job, TQ_SIGNAL( data( TDEIO::Job *, const TQByteArray & ) ), this, TQ_SLOT( slotData( TDEIO::Job *, const TQByteArray & ) ) );
        connect( job, TQ_SIGNAL( result( TDEIO::Job * ) ), this, TQ_SLOT( slotResult( TDEIO::Job * ) ) );

        return true;
    }

    void WebQueryScienceDirect::slotData( TDEIO::Job *, const TQByteArray &data )
    {
        if ( data.size() > 0 )
            m_incomingData.append( TQCString( data, data.size() + 1 ) );
    }

    void WebQueryScienceDirect::slotResult( TDEIO::Job *job )
    {
        if ( job->error() )
        {
            setEndSearch( WebQuery::statusError );
            return;
        }

        BibTeX::FileImporterRIS importer;
        TQBuffer buffer;

        buffer.open( IO_WriteOnly );
        TQTextStream ts( &buffer );
        ts.setEncoding( TQTextStream::UnicodeUTF8 );
        ts << m_incomingData << endl;
        buffer.close();

        buffer.open( IO_ReadOnly );
        BibTeX::File *tmpBibFile = importer.load( &buffer );
        buffer.close();

        if ( tmpBibFile != NULL )
        {
            int count = m_widget->spinBoxMaxHits->value();
            for ( BibTeX::File::ElementList::iterator it = tmpBibFile->begin(); count > 0 && it != tmpBibFile->end(); ++it )
            {
                BibTeX::Entry *entry = dynamic_cast<BibTeX::Entry*>( *it );
                if ( entry != NULL )
                {
                    emit foundEntry( new BibTeX::Entry( entry ), false );
                    --count;
                }
            }

            delete tmpBibFile;
        }
        else
        {
            setEndSearch( WebQuery::statusError );
            return;
        }

        setEndSearch( WebQuery::statusSuccess );
    }
}
#include "webquerysciencedirect.moc"
