#include <cassert>

#include <qcheckbox.h>
#include <qlineedit.h>
#include <QMainWindow>
#include <qpushbutton.h>
#include <qstatusbar.h>
#include <qtimer.h>
#include <qwidget.h>
#include <QStringList>
#include <QTime>
#include <QDebug>

#include <helpers.h>

// NPlugin
#include <iprovider.h>

// NApt
#include "iaptsearch.h"
#include "ipackagedb.h"
#include "complexscorecalculationstrategy.h"

#include "aptsearchplugin.h"

#include "aptsearchpluginshortinputwidget.h"



namespace NPlugin
{

const QString AptSearchPlugin::PLUGIN_NAME = "AptSearchPlugin";


AptSearchPlugin::AptSearchPlugin(NApt::IAptSearch* pAptSearch, NApt::IPackageDB* pPackageDb) :
	_title(tr("Apt-Search Plugin")),
	_briefDescription(tr("Performs a full text search")),
	_description(tr("This plugin can be used to search the packages for expressions.")),
	_pAptSearch(pAptSearch),
	_pPackageDb(pPackageDb)
{
	_pShortInputWidget = 0;
	_pStatusBar = 0;
	
	_pDelayTimer = new QTimer(this);
	_pDelayTimer->setObjectName("delayTimer");
	_delayTime=1000;
	connect(_pDelayTimer, SIGNAL(timeout()), SLOT(evaluateSearch()));

	_pScoreCalculationStrategy = new NApt::ComplexScoreCalculationStrategy(_pPackageDb);
}

AptSearchPlugin::~AptSearchPlugin()
{
	delete _pShortInputWidget;
	delete _pDelayTimer;
	delete _pScoreCalculationStrategy;
}


/////////////////////////////////////////////////////
// Plugin Interface
/////////////////////////////////////////////////////

void AptSearchPlugin::init(IProvider* pProvider)
{
	_pProvider = pProvider;
	QMainWindow* pWindow = _pProvider->mainWindow();
	_pShortInputWidget = new AptSearchPluginShortInputWidget(pWindow, "AptSearchShortInputWIdget");
	_pShortInputWidget->setClearButton(
		pProvider->createClearButton(_pShortInputWidget, "AptClearButton"), 0);
	_pShortInputWidget->show();
	_pStatusBar = pWindow->statusBar();
	connect( _pShortInputWidget->_pClearButton, SIGNAL(clicked()), SLOT (onClearSearch()) );
	connect(
		_pShortInputWidget->_pAptSearchTextInput, 
		SIGNAL(textChanged(const QString&)),
		SLOT(onInputTextChanged(const QString&))
	);
	connect(
		_pShortInputWidget->_pAptSearchTextInput, 
		SIGNAL(returnPressed()),
		SLOT(evaluateSearch())
	);
	connect(
		_pShortInputWidget->_pSearchDescriptionsCheck,
		SIGNAL(toggled(bool)), 
		SLOT(evaluateSearch())
    );
    connect(
        _pShortInputWidget->_pWholeWords,
        SIGNAL(toggled(bool)),
        SLOT(evaluateSearch())
    );


}

/////////////////////////////////////////////////////
// Search Plugin Interface
/////////////////////////////////////////////////////

QWidget* AptSearchPlugin::shortInputAndFeedbackWidget() const
{
	return _pShortInputWidget;
}

void AptSearchPlugin::clearSearch()
{
	_pShortInputWidget->_pAptSearchTextInput->clear();
	_pDelayTimer->stop();
	evaluateSearch();
}


bool AptSearchPlugin::isInactive() const
{
    return _includePatterns.isEmpty();
}

/////////////////////////////////////////////////////
// ScorePlugin Interface
/////////////////////////////////////////////////////


map<string, float> AptSearchPlugin::getScore(const set<string>& packages) const
{
	assert(!_includePatterns.empty());
	_pScoreCalculationStrategy->clear();
	_pScoreCalculationStrategy->setIncludePatterns(_includePatterns);
	_pScoreCalculationStrategy->calculateScore(packages);
	return _pScoreCalculationStrategy->getScore();
}


/////////////////////////////////////////////////////
// Helper Methods
/////////////////////////////////////////////////////


void AptSearchPlugin::onInputTextChanged(const QString&)
{
	_pStatusBar->showMessage(tr("Delayed evaluation - waiting for further input"), _delayTime );
	_pDelayTimer->setSingleShot(true);
	_pDelayTimer->start(_delayTime);
}

void AptSearchPlugin::evaluateSearch()
{
	// stop the delay timer in case that this evaluateSearch() was triggered by
	// another event
	_pDelayTimer->stop();
 	_pProvider->reportBusy(this, tr("Performing full text search on package database"));
	_searchResult.clear();
	parseSearchExpression(_pShortInputWidget->_pAptSearchTextInput->text());
	if ( !isInactive() )	// if the search is not empty
	{
		QStringList patterns = this->searchPatterns();
		try {
			_pAptSearch->search(
                _searchResult,
                _includePatterns,
                _pShortInputWidget->_pSearchDescriptionsCheck->isChecked(),
                _pShortInputWidget->_pWholeWords->isChecked()
			);
		} catch (...) {
            qCritical("apt-search threw an exception -> expect corrupted results");
		}
	}
	_pProvider->reportReady(this);
	emit searchChanged(this);
}

QStringList AptSearchPlugin::searchPatterns()
{
	return _includePatterns;
}

void AptSearchPlugin::parseSearchExpression(const QString& expression)
{
    _includePatterns.clear();
    if (expression.isEmpty())
        return;
    _includePatterns = expression.split(' ', Qt::KeepEmptyParts);
}



}	// namespace NPlugin
