//
// C++ Implementation: kbibremotesearchdlg
//
// Description:
//
//
// Author: Thach Nguyen <thach.nguyen@rmit.edu.au>, (C) 2006
//
// Copyright: See COPYING file that comes with this distribution
//
//
#include "kbib.h"
#include "kbibdoc.h"
#include "kbibremotesearchdlg.h"
#include "kbiblistviewitem.h"
#include "queryresultdlg.h"

#include <klocale.h>
#include <kiconloader.h>
#include <kmessagebox.h>
#include <kaccelmanager.h>
#include <qlayout.h>
#include <qhbox.h>
#include <qhgroupbox.h>
#include <qvgroupbox.h>
#include <qsplitter.h>
#include <qwhatsthis.h>



KBibRemoteSearchDlg::KBibRemoteSearchDlg ( QWidget *parent, const char *name )
		:KDialogBase ( parent, name , true, i18n ( "Remote Database Search" ), KDialogBase::Close, KDialogBase::Close, false )
{

	m_started = false;
	QWidget* mainWidget = new QWidget ( this, "Remote Search" );
	setMainWidget ( mainWidget );
	QVBoxLayout* topLayout = new QVBoxLayout ( mainWidget, 0, KDialog::spacingHint() );

	QVGroupBox* queryBox = new QVGroupBox ( i18n ( "Search Query" ), mainWidget, "Query Box" );
	topLayout->addWidget ( queryBox );

	QHBox* box0 = new QHBox ( queryBox, "box0" );
	box0->setSpacing ( KDialog::spacingHint() );

	QLabel* label = new QLabel ( i18n ( "Search s&ource:" ), box0 );
	dataSource = new KComboBox ( box0 );
	QStringList sources = searchManager::self()->sources();
	for (int i = 0; i < sources.count(); i++){
		QString source = sources[i];
		searcher *s = searchManager::self()->searcherFromName(source);
		dataSource->insertItem( searchManager::self()->searcherIcon(s), source);
	}
	label->setBuddy ( dataSource );
	QWhatsThis::add ( dataSource, i18n ( "Select the database to search" ) );

	queryTab = new QTabWidget (queryBox);
	QWidget *simpleWidget = new  QWidget ( queryTab );
	queryTab->addTab ( simpleWidget, i18n("Simple search") );
	
	QVBoxLayout* simpleBox = new QVBoxLayout ( simpleWidget,  KDialog::marginHint(), 0 );
	
	QHBox* box1 = new QHBox ( simpleWidget, "box1" );
	simpleBox->addWidget(box1);
	box1->setSpacing ( KDialog::spacingHint() );
	box1->setMargin(0);
	
	searchTerms1 = new KLineEdit ( box1 );
	QWhatsThis::add ( searchTerms1, i18n ( "Enter a search value." ) );
	label = new QLabel ( i18n ( "within:" ), box1 );

	searchKey1 = new KComboBox ( box1 );
	QWhatsThis::add ( searchKey1, i18n ( "Choose the type of search" ) );

	QHBox* box3 = new QHBox ( simpleWidget, "box3" );
	simpleBox->addWidget(box3);
	box3->setSpacing ( KDialog::spacingHint() );
	box3->setMargin(0);
	
	operator1 = new KComboBox ( box3 );
	operator1->insertItem ( "AND" );
	operator1->insertItem ( "OR" );
	operator1->insertItem ( "AND NOT" );

	searchTerms2 = new KLineEdit ( box3 );
	QWhatsThis::add ( searchTerms2, i18n ( "Enter a search value." ) );
	label = new QLabel ( i18n ( "within:" ), box3 );

	searchKey2 = new KComboBox ( box3 );
	QWhatsThis::add ( searchKey2, i18n ( "Choose the type of search" ) );

	QHBox* box5 = new QHBox ( simpleWidget, "box5" );
	simpleBox->addWidget(box5);
	box5->setSpacing ( KDialog::spacingHint() );

	operator2 = new KComboBox ( box5 );
	operator2->insertItem ( "AND" );
	operator2->insertItem ( "OR" );
	operator2->insertItem ( "AND NOT" );
	searchTerms3 = new KLineEdit ( box5 );
	QWhatsThis::add ( searchTerms3, i18n ( "Enter a search value." ) );
	label = new QLabel ( i18n ( "within:" ), box5 );

	searchKey3 = new KComboBox ( box5 );

	QWhatsThis::add ( searchKey2, i18n ( "Choose the type of search" ) );

	
	QWidget *advancedWidget = new  QWidget ( queryTab );
	queryTab->addTab ( advancedWidget, i18n("Advanced search") );
	QVBoxLayout* queryStringBox = new QVBoxLayout ( advancedWidget, KDialog::marginHint(), KDialog::spacingHint() );
	
	label = new QLabel(i18n("Enter your query string into the box below."), advancedWidget);
	queryStringBox->addWidget(label);
	
	QHBox* labBox = new QHBox ( advancedWidget, "labBox" );
	labBox->setSpacing ( 0 );
	queryStringBox->addWidget(labBox);
	
	queryStringEdit = new KTextEdit(advancedWidget);
	queryStringEdit->setMaximumHeight(50);
	queryStringBox->addWidget(queryStringEdit);
	QWhatsThis::add( queryStringEdit, i18n ( "You can enter your query string directly into this box and press Search button or press Enter to perform the search." ) );
	
	
	label = new QLabel(i18n("For query syntax, see "), labBox);
	querySyntaxURLLab = new KURLLabel( labBox );
    querySyntaxURLLab->setText( "URL");
    querySyntaxURLLab->setURL( "URL");
    
	connect(querySyntaxURLLab , SIGNAL( leftClickedURL( const QString& ) ), kapp, SLOT( invokeBrowser( const QString& ) ) );
	
	QWidget *dummy = new QWidget(labBox);
	labBox->setStretchFactor(label, 0);
	labBox->setStretchFactor(querySyntaxURLLab, 0);
	labBox->setStretchFactor(dummy, 1);
	
	
	
	QHBox* box6 = new QHBox ( queryBox, "box6" );
	box6->setStretchFactor ( new QWidget ( box6 ), 1 );
	searchButton = new KPushButton ( i18n ( "&Search" ), box6 );
	searchButton->setGuiItem ( KGuiItem ( i18n ( "&Search" ),
	                                      SmallIconSet ( QString::fromLatin1 ( "find" ) ) ) );
	connect ( searchButton, SIGNAL ( clicked() ), SLOT ( slotSearchClick() ) );
	QWhatsThis::add ( searchButton, i18n ( "Click to start or stop the search" ) );
	searchButton->polish();

	QSplitter* split = new QSplitter ( QSplitter::Vertical, mainWidget );
	topLayout->addWidget ( split );

	listView = new KListView ( split );
	listView->setShowSortIndicator ( true );
	listView->setSorting ( 10 );
	listView->setAllColumnsShowFocus ( true );
	listView->setSelectionMode ( QListView::Extended );

	listView->addColumn ( i18n ( "Author" ) );
	listView->setColumnWidthMode ( 0, QListView::Manual );
	listView->addColumn ( i18n ( "Year" ) );
	listView->addColumn ( i18n ( "Title" ) );
	listView->setColumnWidth ( 0, 200 );
	listView->setColumnWidth ( 1, 50 );

	connect ( listView, SIGNAL ( clicked ( QListViewItem* ) ), SLOT ( slotEntryClicked ( QListViewItem* ) ) );
	connect ( listView, SIGNAL ( doubleClicked ( QListViewItem * ) ), SLOT ( slotEntryDoubleClicked ( QListViewItem * ) ) );
	connect ( listView, SIGNAL ( selectionChanged () ), SLOT ( slotSelectionChanged() ) );

	entryPreview = new KTextEdit ( split );
	entryPreview->setReadOnly ( TRUE );

	QHGroupBox* optionBox = new QHGroupBox ( i18n ( "When adding references" ), mainWidget, "Option Box" );
	topLayout->addWidget ( optionBox );
	ignoreExistingSelect = new QCheckBox ( i18n ( "Do not add existing references" ), optionBox );
	createKeySelect = new QCheckBox ( i18n ( "Fix duplicated citation keys" ), optionBox );
	ignoreExistingSelect->setChecked ( true );
	createKeySelect->setChecked ( true );

	QHBox* box7 = new QHBox ( mainWidget );
	topLayout->addWidget ( box7 );
	box7->setSpacing ( KDialog::spacingHint() );

	addButton = new KPushButton ( i18n ( "Add Selected References" ), box7 );
	addButton->setGuiItem ( KGuiItem ( i18n ( "Add References" ),
	                                   SmallIconSet ( QString::fromLatin1 ( "add" ) ) ) );
	addButton->setEnabled ( false );

	addAllButton = new KPushButton ( i18n ( "Add All References" ), box7 );
	addAllButton->setGuiItem ( KGuiItem ( i18n ( "Add All References" ),
	                                   SmallIconSet ( QString::fromLatin1 ( "apply" ) ) ) );
	addAllButton->setEnabled ( false );


	this->setMinimumWidth ( 600 );

	searchTerms1->setFocus();

	connect ( dataSource, SIGNAL ( activated ( const QString& ) ), SLOT ( slotSourceSelected ( const QString& ) ) );

	connect ( addButton, SIGNAL ( clicked() ), SLOT ( slotAddEntryClick() ) );
	connect ( addAllButton, SIGNAL ( clicked() ), SLOT ( slotAddAllEntryClick() ) );
	

	clearButton = new KPushButton ( KStdGuiItem::clear(), box7 );

	connect ( clearButton, SIGNAL ( clicked() ), SLOT ( slotClearClick() ) );

	connect ( searchManager::self(), SIGNAL ( signalResultFound ( BibEntry* ) ),
	          SLOT ( slotResultFound ( BibEntry* ) ) );

	connect ( searchManager::self(), SIGNAL ( signalQueryResult ( unsigned int ) ),
	          SLOT ( slotQueryResult ( unsigned int ) ) );
	connect ( searchManager::self(), SIGNAL ( signalMessage ( QString, int ) ), SLOT ( slotMessage ( QString, int ) ) );
	connect ( searchManager::self(), SIGNAL ( signalDone() ), SLOT ( slotSearchDone() ) );

	
	KAcceleratorManager::manage ( mainWidget );

	KConfigGroup config(kapp->config(), "Remote Database Search Options");
	QString option = config.readEntry("Search Source");
 	if(!option.isEmpty()) {
    		dataSource->setCurrentItem(option);
  	}
  	slotSourceSelected(dataSource->currentText());
	option = config.readEntry("Search Fields");
	QStringList searchFields = QStringList::split(";", option);
	QStringList::Iterator it;
	if (searchFields.count() >= 1){	
		QStringList::Iterator it = searchFields.at(0);
		if (!(*it).isEmpty() )
			searchKey1->setCurrentItem(*it);
	}
	if (searchFields.count() >= 2){	
		it = searchFields.at(1);
		if (!(*it).isEmpty() )
			searchKey2->setCurrentItem(*it);
	}
	if (searchFields.count() >= 3){	
		it = searchFields.at(2);
		if (!(*it).isEmpty() )
			searchKey3->setCurrentItem(*it);
	}

	option = config.readEntry("Search Operators");
	QStringList searchOperators = QStringList::split(";", option);	
	if (searchOperators.count() >=1){
		it = searchOperators.at(0);
		if (!(*it).isEmpty() )
			operator1->setCurrentItem(*it);
	}
	if (searchOperators.count() >=1){
		it = searchOperators.at(1);
		if (!(*it).isEmpty() )
			operator2->setCurrentItem(*it);
	}
	ignoreExistingSelect->setChecked(config.readBoolEntry("Ignore Existing", true) );
	createKeySelect->setChecked(config.readBoolEntry("Fix Key", true) );

	queryTab->setCurrentPage(config.readNumEntry("Search Method", 0));
}


KBibRemoteSearchDlg::~KBibRemoteSearchDlg()
{
	//delete Bib entry
	for ( QListViewItem* item_ = listView->firstChild(); item_; item_ = item_->nextSibling() )
	{
		KBibListViewItem *item = dynamic_cast<KBibListViewItem*> ( item_ );
		BibEntry *e =  item->getBibEntry();
		delete e;
	}
	//clear list view
	listView->clear();

	//Write dialog option
	KConfigGroup config(kapp->config(), "Remote Database Search Options");
 	config.writeEntry("Search Source", dataSource->currentText());
	config.writeEntry("Search Method", queryTab->currentPageIndex() );
	QStringList strList;
	strList << searchKey1->currentText() << searchKey2->currentText() << searchKey3->currentText();
	config.writeEntry("Search Fields", strList.join(";"));
	strList.clear();
	strList << operator1->currentText() << operator2->currentText();
	config.writeEntry("Search Operators", strList.join(";"));
	config.writeEntry("Ignore Existing", ignoreExistingSelect->isChecked());
	config.writeEntry("Fix Key", createKeySelect->isChecked());
	
}

void KBibRemoteSearchDlg::slotSourceSelected ( const QString& source )
{
	searchKey1->clear();
	searchKey2->clear();
	searchKey3->clear();
	searchKey1->insertStringList ( searchManager::self()->searchKeyList ( source ) );
	searchKey2->insertStringList ( searchManager::self()->searchKeyList ( source ) );
	searchKey3->insertStringList ( searchManager::self()->searchKeyList ( source ) );

	int maxSearchTerms = searchManager::self()->maxSearchTerms ( source );

	if ( maxSearchTerms < 3 )
	{
		searchKey3->setEnabled ( false );
		searchTerms3->setEnabled ( false );
		operator2->setEnabled ( false );
	}
	else
	{
		searchKey3->setEnabled ( true );
		searchTerms3->setEnabled ( true );
		operator2->setEnabled ( true );
	}

	if ( maxSearchTerms < 2 )
	{
		searchKey2->setEnabled ( false );
		searchTerms2->setEnabled ( false );
		operator1->setEnabled ( false );
	}
	else
	{
		searchKey2->setEnabled ( true );
		searchTerms2->setEnabled ( true );
		operator1->setEnabled ( true );
	}
	QString helpURL = searchManager::self()->helpURL( ( source ) );
	querySyntaxURLLab->setText(helpURL);
	querySyntaxURLLab->setURL(helpURL);
}

void KBibRemoteSearchDlg::stop()
{
	if ( m_started )
	{
		searchManager::self()->stop();
		slotSearchDone();
	}
}

void KBibRemoteSearchDlg::slotSearchClick()
{
	if ( m_started )
	{
		searchManager::self()->stop();
		slotSearchDone();
	}
	else
	{
		if (queryTab->currentPageIndex() == 0){
		
			QString value1 = searchTerms1->text().simplifyWhiteSpace();
			QString value2 = searchTerms2->text().simplifyWhiteSpace();
			QString value3 = searchTerms3->text().simplifyWhiteSpace();
			if ( !value1.isEmpty() || !value2.isEmpty() || !value3.isEmpty() )
			{
				m_started = true;
				searchButton->setGuiItem ( KGuiItem ( i18n ( "&STOP" ),
			                                      SmallIconSet ( QString::fromLatin1 ( "cancel" ) ) ) );
				QApplication::setOverrideCursor ( Qt::waitCursor );
				searchManager::self()->startSearch ( dataSource->currentText(), searchManager::self()->searchKey ( searchKey1->currentText() ), searchManager::self()->searchKey ( searchKey2->currentText() ), searchManager::self()->searchKey ( searchKey3->currentText() ), value1, value2, value3, operator1->currentItem(), operator2->currentItem() );
		
			}
		}
		else{
			QString queryString = queryStringEdit->text();
			queryString = queryString.stripWhiteSpace();
			if (!queryString.isEmpty()){
				m_started = true;
				searchButton->setGuiItem ( KGuiItem ( i18n ( "&STOP" ),
			                                      SmallIconSet ( QString::fromLatin1 ( "cancel" ) ) ) );
				QApplication::setOverrideCursor ( Qt::waitCursor );
				searchManager::self()->startSearch(dataSource->currentText(),queryString);	
			}
		}
	}
}


void KBibRemoteSearchDlg::slotResultFound ( BibEntry* bib )
{

	if ( bib )
	{
		KBibApp *win = ( KBibApp * ) ( this->parent() );
		KBibDoc *doc = win->getDocument();
		QStringList displayFields;
		displayFields << "author" << "year" << "title";
		KBibListViewItem * item = new KBibListViewItem ( listView, doc, new BibEntry ( *bib ), displayFields, 0 );
		delete bib;
		addAllButton->setEnabled ( true );
	}
}

void KBibRemoteSearchDlg::slotQueryResult ( unsigned int num )
{
	if ( num > 0 )
	{
		QApplication::restoreOverrideCursor();
		queryResultDlg *queryResult = new queryResultDlg ( num );
		if ( queryResult->exec() == QDialog::Accepted )
		{
			int start, end;
			start = queryResult->getStart();
			end = queryResult->getStop();
			if ( end < start )
				end = start;
			searchManager::self()->retrieveRange ( start, end );
			QApplication::setOverrideCursor ( Qt::waitCursor );
		}
		else
			searchManager::self()->retrieveRange ( 0, 0 );
		delete queryResult;
	}
}

void KBibRemoteSearchDlg::slotAddEntryClick()
{
	KBibApp *win = ( KBibApp * ) ( this->parent() );
	KBibDoc *doc = win->getDocument();

	for ( QListViewItem* item_ = listView->firstChild(); item_; item_ = item_->nextSibling() )
	{
		KBibListViewItem *item = dynamic_cast<KBibListViewItem*> ( item_ );
		if ( listView->isSelected ( item ) )
		{
			BibEntry *e =  item->getBibEntry();
			doc->addEntry ( new BibEntry ( *e ), ignoreExistingSelect->isChecked(), createKeySelect->isChecked() );
		}
	}
}

void KBibRemoteSearchDlg::slotAddAllEntryClick()
{
	KBibApp *win = ( KBibApp * ) ( this->parent() );
	KBibDoc *doc = win->getDocument();

	for ( QListViewItem* item_ = listView->firstChild(); item_; item_ = item_->nextSibling() )
	{
		KBibListViewItem *item = dynamic_cast<KBibListViewItem*> ( item_ );
		BibEntry *e =  item->getBibEntry();
		doc->addEntry ( new BibEntry ( *e ), ignoreExistingSelect->isChecked(), createKeySelect->isChecked() );
	}
}

void KBibRemoteSearchDlg::slotClearClick()
{
	//Remove bib pointers first

	for ( QListViewItem* item_ = listView->firstChild(); item_; item_ = item_->nextSibling() )
	{
		KBibListViewItem *item = dynamic_cast<KBibListViewItem*> ( item_ );
		BibEntry *e =  item->getBibEntry();
		delete e;
	}
	listView->clear();
	entryPreview->clear();
	searchTerms1->setFocus();
	slotSelectionChanged();
	addAllButton->setEnabled ( false );

}


void KBibRemoteSearchDlg::slotEntryClicked ( QListViewItem* item_ )
{
	if ( !item_ )
	{
		addButton->setEnabled ( false );
		entryPreview->clear();
		return;
	}


	addButton->setEnabled ( true );
	KBibListViewItem *item = dynamic_cast<KBibListViewItem*> ( item_ );

	BibEntry *entry = item->getBibEntry();

	KBibApp *win = ( KBibApp * ) ( this->parent() );
	KBibDoc *doc = win->getDocument();

	entryPreview->setText ( doc->getEntryList()->detailedEntry ( entry ) );


}

void KBibRemoteSearchDlg::slotEntryDoubleClicked ( QListViewItem * item_ )
{
	if ( !item_ )
		return;
	KBibApp *win = ( KBibApp * ) ( this->parent() );
	KBibDoc *doc = win->getDocument();
	KBibListViewItem *item = dynamic_cast<KBibListViewItem*> ( item_ );
	BibEntry *e =  item->getBibEntry();
	doc->addEntry ( new BibEntry ( *e ), ignoreExistingSelect->isChecked(), createKeySelect->isChecked() );
}

void KBibRemoteSearchDlg::slotSelectionChanged()
{

	QListViewItem *i =  listView->currentItem();
	if ( !i )
	{
		addButton->setEnabled ( false );
		return;
	}
	if ( !i->isSelected() )
	{
		addButton->setEnabled ( false );
		return;
	}
	slotEntryClicked ( i );


}



void KBibRemoteSearchDlg::slotMessage ( QString message, int type )
{
	QApplication::restoreOverrideCursor();
	if ( message.isEmpty() )
		return;
	if ( type == 0 )
	{	//error
		KMessageBox::sorry ( this, message );
	}
	else if ( type == 1 )
	{	//warning
		KMessageBox::information ( this, message );
	}

}

void KBibRemoteSearchDlg::slotSearchDone()
{
	QApplication::restoreOverrideCursor();
	m_started = false;
	searchButton->setGuiItem ( KGuiItem ( i18n ( "&Search" ),
	                                      SmallIconSet ( QString::fromLatin1 ( "find" ) ) ) );
}


void KBibRemoteSearchDlg::keyPressEvent ( QKeyEvent *e )
{

	if ( e->state() == 0 )
	{
		if (e->key() == Key_Return || e->key() == Key_Enter )
		{
			searchButton->animateClick();
			e->accept();
			return;
			

		}
	}
	
	//
	// Do the default action instead. 
	KDialogBase::keyPressEvent ( e );
}
#include "kbibremotesearchdlg.moc"
