#include <sstream>
#include <iostream>

#include <qcheckbox.h>
#include <qlayout.h>
#include <qlabel.h>
#include <QMainWindow>
#include <qmessagebox.h>
#include <qpoint.h>
#include <QAbstractItemView>
#include <QVBoxLayout>

//#include <ept/configuration/apt.h>
//#include <ept/cache/debtags/tagmap.h>

#include "debtagsplugin.h"

#include <helpers.h>
#include <exception.h>

// NPlugin
#include <packagenotfoundexception.h>
#include <iprovider.h>


// NUtil
#include "debtagshelper.h"



#include "selectioninputanddisplay.h"
#include "choosentagsdisplay.h"

// NTagModel
#include "vocabularymodel.h"

typedef std::string Package;
typedef std::string Tag;

using namespace std;

namespace NPlugin
{

const QString DebtagsPlugin::PLUGIN_NAME = "DebtagsPlugin";


/////////////////////////////////////////////////////
// Constructors/ Destructors
/////////////////////////////////////////////////////

DebtagsPlugin::DebtagsPlugin(const DebtagsPluginContainer& container) :
	_container(container)
{ 
	
	
	_pProvider = 0;
	_pTagSelection = 0;
	_pChooserWidget = 0;
	_isInactive = true;
}

DebtagsPlugin::~DebtagsPlugin() 
{ 
	delete _pChooserWidget;
	delete _pTagSelection;
}

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

void DebtagsPlugin::init(IProvider* pProvider)
{
	_pProvider = pProvider;

	// this will be garbage collected if the parent is deleted
	_pTagSelection = new NWidgets::SelectionInputAndDisplay(&_container, vocabularyModel(), this);

	// currently disabled as the exclude tag option is not too useful and wastes some space
	// assume that the vocabulary is not accessible if one of the pointers is not set
// 	bool debtagsEnabled = (_container.collection() != 0);
	connect(vocabularyModel(), SIGNAL(dataChanged(const QModelIndex&, const QModelIndex&)), SLOT(onTagSelectionChanged()));
	connect(vocabularyModel(), SIGNAL(modelReset()), SLOT(onTagSelectionChanged()));
	
}


QString DebtagsPlugin::title() const 
{ 
	return QString("Debtags Plugin"); 
}

QString DebtagsPlugin::briefDescription() const 
{ 
	return QString("Offers information and search using the debtags system"); 
}

QString DebtagsPlugin::description() const 
{ 
	return QString("This plugin shows the tags for a program in the detailed view.\n"
		"It also offers searching by tags that can be selected from a list."); 
}

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

QWidget* DebtagsPlugin::shortInputAndFeedbackWidget() const
{
	return _pTagSelection->tagDisplayWidget();
	
}

QWidget* DebtagsPlugin::inputWidget() const
{
	return _pTagSelection->tagSelectorWidget();
}	

const set<string>& DebtagsPlugin::searchResult() const
{ 
	return _searchResult; 
};

void DebtagsPlugin::clearSearch()
{
	vocabularyModel()->setAllUnselected();
}

/////////////////////////////////////////////////////
// Information Plugin Interface 
/////////////////////////////////////////////////////

QString DebtagsPlugin::informationText(const string& package)
{
	{	// add the tags of the package to the description
		set<string> tagset = NUtil::tagsForPackage(package, _pProvider->xapian());
		if (tagset.empty()) return _emptyString;
		QString detailsString = "<b>Tags:</b> ";
		for (set<string>::iterator it = tagset.begin(); ; )
		{
			detailsString += toQString( *it );
			if ( ++it == tagset.end() )
			{
				detailsString.append("\n");
				break;
			}
			detailsString += ", ";
		}
		return detailsString+"<br>";
	}
}

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

void DebtagsPlugin::showExcludeWidgets(bool )
{
	// TODO reimplement
/*	_pExcludeSelection->setShown(display);
	_pChooserWidget->_pExcludeInputLabel->setShown(display);*/
}


void DebtagsPlugin::evaluateSearch()
{
	_pProvider->reportBusy(this, tr("Performing tag search on package database"));
//	statusBar()->message(tr("Searching Package Database for tags"));
	_searchResult.clear();
	set<Tag> includeTags = vocabularyModel()->selectedTags();
	if (includeTags.empty())	// if nothing is selected, do not show anything
	{
		_isInactive = true;
	}
	else
	{
		_isInactive = false;
		
		Xapian::Enquire enq(_pProvider->xapian());
		set<string> terms;		
		for (set<Tag>::const_iterator it = includeTags.begin(); it != includeTags.end(); ++it)
		{
			terms.insert(string("XT")+*it);
		}

		Xapian::Query query(Xapian::Query::OP_AND, terms.begin(), terms.end());
		enq.set_query(query);
		Xapian::MSet match = enq.get_mset(0, 500000);
 		for (Xapian::MSet::const_iterator it = match.begin(); it != match.end(); ++it)
 			_searchResult.insert( it.get_document().get_data());
	}
	_pProvider->reportReady(this);
	emit searchChanged(this);
}


void DebtagsPlugin::setWidgetsEnabled(bool enabled)
{
	_pTagSelection->setEnabled(enabled);
}

void DebtagsPlugin::onTagSelectionChanged()
{
	evaluateSearch();
	if ( vocabularyModel()->selectedTags().size() == 0 )
		_pTagSelection->setSelectedTagDisplayShown(false);
	else
		_pTagSelection->setSelectedTagDisplayShown(true);
}


NTagModel::VocabularyModel* DebtagsPlugin::vocabularyModel()
{
	return _container.vocabularyModel();
}

}	// namespace NPlugin

#undef emit

