//
// C++ Implementation: scoredisplayplugin
//
// Description: 
//
//
// Author: Benjamin Mesing <bensmail@gmx.net>, (C) 2005
//
// Copyright: See COPYING file that comes with this distribution
//
//

#include <cassert>

#include <QtDebug>

#include "scoredisplayplugin.h"

// NPlugin
#include <packagenotfoundexception.h>
#include <plugin.h>
#include <scoreplugin.h>


namespace NPlugin {

const QString ScoreDisplayPlugin::PLUGIN_NAME = "ScoreDisplayPlugin";

ScoreDisplayPlugin::ScoreDisplayPlugin()
 : ShortInformationPlugin(),
 	_title(tr("Score Display Plugin")),
	_briefDescription(tr("Displays the package scores")),
	_description(tr("Displays the search scores of the packages returned by the current search.<br>\n"
	"The higher the scores, the better the packages matches to the search."))
{
}


ScoreDisplayPlugin::~ScoreDisplayPlugin()
{
}


/////////////////////////////////////////////////////
// ShortInformationPlugin Interface
/////////////////////////////////////////////////////

const QString ScoreDisplayPlugin::shortInformationText(const string& package)
{
	QString scores;
	ScoreMap::const_iterator it = _packageToScore.find(package);
	if (it == _packageToScore.end())
		throw PackageNotFoundException(package);
	scores.setNum(it->second, 'g', 3);
	return scores;
}


/////////////////////////////////////////////////////
// IPluginUser Interface
/////////////////////////////////////////////////////


void ScoreDisplayPlugin::addPlugin(Plugin* pPlugin)
{
	if (dynamic_cast<ScorePlugin*>(pPlugin) != 0)
	{
		// dynamic cast needed here because of virtual base class
		_scorePlugins.insert(dynamic_cast<ScorePlugin*>(pPlugin));
	}
}

void ScoreDisplayPlugin::removePlugin(Plugin* pPlugin)
{
	if (dynamic_cast<ScorePlugin*>(pPlugin) != 0)
	{
		// dynamic cast needed here because of virtual base class
		_scorePlugins.erase(dynamic_cast<ScorePlugin*>(pPlugin));
	}
}

/////////////////////////////////////////////////////
// Other functions
/////////////////////////////////////////////////////

void ScoreDisplayPlugin::updateScores(const set<string>& packages)
{
	qDebug("Updating scores");
	_packageToScore.clear();	
	ScorePluginContainer activeScorePlugins;
	for (ScorePluginContainer::const_iterator it = _scorePlugins.begin(); it != _scorePlugins.end(); ++it)
		if ((*it)->offersScore())
			activeScorePlugins.insert(*it);
	
	// if no plugins which offer scores are available simply add all package with a score of 1
	if (activeScorePlugins.empty())
	{
		for (std::set<string>::iterator it = packages.begin(); it != packages.end(); ++it)
			_packageToScore.insert(make_pair(*it, 1.0));
	}
	else
	{
		// maps the packages to the scores
		ScoreMap packageScores;
		// calculate scores for each plugin
		
		for (ScorePluginContainer::const_iterator it = activeScorePlugins.begin(); 
			it != activeScorePlugins.end(); ++it)
		{
			try {
				ScoreMap scores = (*it)->getScore(packages);
				// if this is the first score plugin
				if (_packageToScore.empty())
					swap(_packageToScore, scores);
				else
				{
					// multiply each score in the result scores with those in the packageScores
					for (ScoreMap::const_iterator jt = scores.begin(); jt != scores.end(); ++jt)
					{
						// must not happen, but somehow it does, so let's deal graciously with it
						if (_packageToScore.find(jt->first) == _packageToScore.end()) {
							qWarning() << "Found no score for package: %s" << jt->first.c_str();
							// each package should return the same map for which score are calculated
							//assert( _packageToScore.find(jt->first) != _packageToScore.end() );
							_packageToScore[jt->first] = jt->second * 0.5;
						}
						_packageToScore[jt->first] *= jt->second;
					}
				}
			}
			catch (std::exception& e) {
				qWarning() << "Plugin " << (*it)->name() << " failed to calculate scores\n"
						<< "e.what(): " << e.what();
			}
			catch (...) {
				qWarning() << "Plugin " << (*it)->name() << " failed to calculate scores (unknown exception thrown)";
			}
		}
	}
	qDebug("Finished updating scores");
}


}
