//
// C++ Implementation: scholarsearcher
//
// Description:
//
//
// Author: Thach Nguyen <thach.nguyen@rmit.edu.au>, (C) 2008
//
// Copyright: See COPYING file that comes with this distribution
//
//
#include "scholarsearcher.h"
#include "searchmanager.h"
#include "bibfile.h"
#include "filters/bibprogs.h"
#include "bibentrytable.h"

#include <klocale.h>
#include <kconfig.h>
#include <kstandarddirs.h>

#include <qlabel.h>
#include <qlayout.h>
#include <qfile.h>
#include <qregexp.h>

#include <fstream>

ScholarSearcher::ScholarSearcher ( QObject *parent, const char *name )
		: searcher ( parent, name ),m_step ( Begin ), m_started ( false )
{
}


ScholarSearcher::~ScholarSearcher()
{
}

QString ScholarSearcher::defaultName()
{
	return i18n ( "Google Scholar" );
}

QString ScholarSearcher::source() const
{
	return m_name.isEmpty() ? defaultName() : m_name;
}


void ScholarSearcher::readConfig ( KConfig* config_, const QString& group_ )
{
	KConfigGroupSaver groupSaver ( config_, group_ );
	QString s = config_->readEntry ( "Name", defaultName() ); // default to pubmed
	if ( !s.isEmpty() )
	{
		m_name = s;
	}
}

void ScholarSearcher::saveConfig ( KConfig* config )
{

}

void ScholarSearcher::search ( SearchKey key1, SearchKey key2, SearchKey key3 , const QString& value1, const QString& value2, const QString& value3, int operator1, int operator2 )
{
	QString str;
	QString query = QString();
	if ( !value1.isEmpty() )
	{


		switch ( key1 )
		{
			case Title:
				query = QString::fromLatin1 ( "intitle:" ) +value1;
				break;

			case Author:
				query = str + QString::fromLatin1 ( "author:" ) +value1;
				break;

			case All:
				query = value1;
				break;
			default:
				stop();
				return;
		}
	}

	if ( !value2.isEmpty() )
	{
		if ( !query.isEmpty() )
		{
			switch ( operator1 )
			{
				case 0:
					query += QString::fromLatin1 ( " " );
					break;
				case 1:
					query += QString::fromLatin1 ( " OR " );
					break;
				case 2:
					query += QString::fromLatin1 ( " -" );
					break;
				default:
					stop();
					return;
			}

		}
		switch ( key2 )
		{
			case Title:
				query += QString::fromLatin1 ( "intitle:" ) +value2;
				break;

			case Author:
				query += QString::fromLatin1 ( "author:" ) +value2;
				break;

			case All:
				query += value2;
				break;

			default:
				stop();
				return;
		}

	}

	if ( !value3.isEmpty() )
	{
		if ( !query.isEmpty() )
		{
			switch ( operator2 )
			{
				case 0:
					query += QString::fromLatin1 ( " " );
					break;
				case 1:
					query += QString::fromLatin1 ( " OR " );
					break;
				case 2:
					query += QString::fromLatin1 ( " -" );
					break;
				default:
					stop();
					return;
			}

		}
		switch ( key3 )
		{
			case Title:
				query += QString::fromLatin1 ( "intitle:" ) +value3;
				break;

			case Author:
				query += QString::fromLatin1 ( "author:" ) +value3;
				break;

			case All:
				query += value3;
				break;

			default:
				stop();
				return;
		}

	}
	search ( query );

}

void ScholarSearcher::stop()
{
	if ( !m_started )
	{
		return;
	}
	if ( m_job )
	{
		m_job->kill();
		m_job = 0;
	}
	m_started = false;
	m_data.truncate ( 0 );
	m_step = Begin;
	emit signalDone ( this );
}


void ScholarSearcher::search ( QString query )
{
	m_query = query;

	m_started = true;

	if ( query.isEmpty() )
	{
		stop();
		return;
	}




	m_step = SetPref;
	startRequest ( QString::fromLatin1 ( "http://scholar.google.com/scholar_setprefs?inststart=0&hl=en&lang=all&instq=&inst=cat-aus&num=50&scis=yes&scisf=4&submit=Save+Preferences:" ) );

}

void ScholarSearcher::slotData ( KIO::Job*, const QByteArray& data_ )
{
	QDataStream stream ( m_data, IO_WriteOnly | IO_Append );
	stream.writeRawBytes ( data_.data(), data_.size() );
}

void ScholarSearcher::slotComplete ( KIO::Job* job_ )
{
	// since the fetch is done, don't worry about holding the job pointer
	m_job = 0;

	if ( job_->error() )
	{
		emit signalMessage ( job_->errorString(), 0 );
		stop();
		return;
	}

	if ( m_data.isEmpty() )
	{
		std::cerr << "ScholarSearcher::slotComplete() - no data\n";
		stop();
		return;
	}

	switch ( m_step )
	{
		case SetPref:
			startQuery();
			break;
		case Query:
			searchResults();
			break;
		case Fetch:
			fetchResults();
			break;
		case FetchItem:
			fetchItem();
			break;
		default:
			std::cerr << "ScholarSearcher::slotComplete() - wrong step = " << m_step << "\n";
			break;
	}

}


void ScholarSearcher::startQuery()
{
	m_step = Query;
	startRequest ( QString::fromLatin1 ( "http://scholar.google.com/scholar?q=%1&num=1&hl=en&lr=&start=0&sa=N" ).arg ( m_query ) );

}

void ScholarSearcher::searchResults()
{

	QString str = QString::fromUtf8 ( m_data, m_data.size() );


	QRegExp rx ( QString::fromLatin1 ( ".*Results <b>1</b> - <b>1</b> of about <b>((\\d|,)+)</b> for <b>.*" ) );

	if ( !rx.exactMatch ( str ) )
	{
		signalMessage ( i18n ( "No reference was found" ), 1 );
		stop();
	}
	str = rx.cap ( 1 );
	str = str.remove ( ',' );
	m_total = str.toInt();
	m_waitingRetrieveRange = true;
	m_step = Wait;
	if ( m_total > 0 )
	{
		emit signalQueryResult ( m_total );
	}
	else
	{
		signalMessage ( i18n ( "No reference was found" ), 1 );
		stop();
	}

}

void ScholarSearcher::fetchResults()
{
	QString str = QString::fromUtf8 ( m_data, m_data.size() );

	m_step = FetchItem;

	int start = 0;
	int end;
	int itemStart;
	int itemEnd;
	QString url;
	QString itemStr;
	QString note;

	while (( start = str.find ("<p class=g><span class=\"w\">" , start ) ) >= 0){
		end = str.find ( "\">Import into BibTeX", start );
		itemStr = str.mid ( start, end-start );
		itemStart = itemStr.find ( "scholar.bib?", 0 ) ;
		url = itemStr.mid ( itemStart, itemStr.length()-19 );
		itemUrlList.append ( url );
		itemEnd = itemStr.find ( "\" onmousedown=", 0 ) ;
		itemStart = itemStr.find ("<a href=\"", 0);
		url = itemStr.mid (itemStart+9, itemEnd-itemStart-9);
		urlList.append( url);
		itemStart = itemStr.find("cites=");
		itemEnd = itemStr.find("Cited by");
		if (itemStart >=0 && itemEnd >=0){
			note = itemStr.mid(itemStart, itemEnd-itemStart-2);
			itemStart = itemEnd;
			itemEnd = itemStr.find("</a>", itemStart);
			note = itemStr.mid(itemStart, itemEnd - itemStart) + " (http://scholar.google.com.au/scholar?num=50&"+note+")";
			noteList.append(note);
		}
		else{
			note = QString("");
			noteList.append(note); 
		}
		start = end;

	}

	if ( itemUrlList.size() > 0 )
	{
		url = *itemUrlList.begin();
		itemUrlList.pop_front();
		url = QString::fromLatin1 ( "http://scholar.google.com/" ) +url;
		startRequest ( url );

	}

}

void ScholarSearcher::fetchItem()
{
	QString str = QString::fromUtf8 ( m_data, m_data.size() );

	m_step = FetchItem;

	BibEntry *bib;
	int last_char;
	bib = processBibEntryFromString ( str.ascii(), last_char );
	QString urlStr = *urlList.begin();
	urlList.pop_front();
	QString note = *noteList.begin();
	noteList.pop_front();
	
	if ( bib ){
		bib->setField(QString::fromLatin1("url"), urlStr);
		bib->setField(QString::fromLatin1("note"), note);
		
		emit signalResultFound ( new BibEntry ( *bib ) );
	}
	if ( itemUrlList.size() > 0 )
	{
		QString url = *itemUrlList.begin();
		itemUrlList.pop_front();
		url = QString::fromLatin1 ( "http://scholar.google.com/" ) +url;
		startRequest ( url );

	}
	else
		stop();

}


void ScholarSearcher::retrieveRange ( unsigned int min, unsigned int max )
{
	if ( m_step != Wait )
		return;
	m_waitingRetrieveRange = false;
	if ( min < 1 && max < 1 )
	{
		stop();
		return;
	}

	m_step = Fetch;
	QString url = QString ( "http://scholar.google.com/scholar?q=%1&hl=en&lr=&sa=N&start=%2&num=%3" ).arg ( m_query ).arg ( min-1 ).arg ( max-min+1 );
	startRequest ( url );
}


void ScholarSearcher::startRequest ( QString url )
{
	m_data.truncate ( 0 );
	m_url = KURL ( url );

//	std::cerr << m_url.prettyURL() << "\n";
	m_job = KIO::get ( m_url, false, false );
	connect ( m_job, SIGNAL ( data ( KIO::Job*, const QByteArray& ) ),
	          SLOT ( slotData ( KIO::Job*, const QByteArray& ) ) );
	connect ( m_job, SIGNAL ( result ( KIO::Job* ) ),
	          SLOT ( slotComplete ( KIO::Job* ) ) );


}

void ScholarSearcher::setSource ( const QString s )
{
	m_name = s ;
}


QStringList ScholarSearcher::searchKey()
{
	QStringList keyList;
	keyList << searchManager::self()->searchKeyString ( All ) << searchManager::self()->searchKeyString ( Author )
	<< searchManager::self()->searchKeyString ( Title );
	return keyList;
}

SearcherConfigWidget* ScholarSearcher::configWidget ( QWidget* parent_ )
{
	return new ScholarConfigWidget ( parent_, this );
}

ScholarConfigWidget::ScholarConfigWidget ( QWidget* parent_, ScholarSearcher* searcher_/*=0*/ )
		: SearcherConfigWidget ( parent_ )
{
	m_searcher = searcher_;
	QVBoxLayout* l = new QVBoxLayout ( optionsWidget() );
	l->addWidget ( new QLabel ( i18n ( "This source has no options." ), optionsWidget() ) );
	KURLLabel *urlLab = new KURLLabel( optionsWidget() );
	l->addWidget(urlLab);
	urlLab->setText( "More information about Google Scholar");
        urlLab->setURL("http://scholar.google.com");
    
	connect(urlLab , SIGNAL( leftClickedURL( const QString& ) ), kapp, SLOT( invokeBrowser( const QString& ) ) );

	l->addStretch();

}




#include "scholarsearcher.moc"
