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

#include <map>

#include <QAbstractProxyModel>


// NTagModel
#include "vocabularymodelrole.h"
#include "vocabularymodel.h"

#include <cassert>

using namespace std;

namespace NTagModel
{

/** This proxy model limits the items to be viewed to the tags inside the facets.
  *
  * The tags are proxied to be in a simple list (i.e. no hierarchies will be considered).
  *
  * The proxy model expects a VocabularyModel as source model.
  */
class TagListProxyModel  : public QAbstractProxyModel
{
Q_OBJECT
	typedef std::string Tag;
	typedef std::string Facet;
	/** Maps the row to the tag with the given name. */
	map<int, Tag> _rowToTag;
	/** Maps the tag name to the row for the tag. */
	map<Tag, int> _tagToRow;

protected Q_SLOTS:
	/** Emits the dataChanged signal for the tags matching the given source indexes. */
	virtual void onVocabularyModelChanged(const QModelIndex & sourceTl, const QModelIndex & sourceBr)
	{
		emit(dataChanged(mapFromSource(sourceTl), mapFromSource(sourceBr)));
	}

	/** Emits the reset signal. */
	virtual void onModelReset()
	{
		emit(reset());
	}
	
public:
	TagListProxyModel(QObject * pParent)
	: QAbstractProxyModel(pParent)
	{
	}
	
	/** Determines the index by looking up the tag referred to by source index in _tagToRow. */
	virtual QModelIndex mapFromSource(const QModelIndex& sourceIndex) const
	{
		ItemData* pData = (ItemData*) sourceIndex.internalPointer();
		if (pData->isFacet())
		{
			return QModelIndex();
		}
		else
		{
			TagData* pTagData = pData->toTagData();
			int row = _tagToRow.find(pTagData->tag())->second;
			return index(row, sourceIndex.column());
		}
	}
	
	/** Determines the source index by querying VocabularyModel::indexForTag() for the tag
	  * referred to by <em>proxyIndex</em>. */
	virtual QModelIndex mapToSource(const QModelIndex& proxyIndex) const
	{
		std::map<int, NTagModel::TagListProxyModel::Tag >::const_iterator it = _rowToTag.find(proxyIndex.row());
		if (it == _rowToTag.end())
			return QModelIndex();
		Tag tag = it->second;
		return vocabularyModel()->indexForTag(tag, proxyIndex.column());
	}
	
	virtual QModelIndex index(int r, int c, const QModelIndex &ind=QModelIndex()) const
	{
		(void) ind;
		return createIndex(r,c);
	}
	
	/** Returns QModelIndex(). */
	virtual QModelIndex parent(const QModelIndex&) const 
	{
		return QModelIndex();
	}
	
	/** Returns the number of tags in this model. */
	virtual int rowCount(const QModelIndex& parent) const
	{
		if (!parent.isValid())
		{
			return _tagToRow.size();
		}
		else 
			return 0;
		
	}
	
	/** Forwards retrieving the column count to the source model. */
	virtual int columnCount(const QModelIndex &) const
	{
		return sourceModel()->columnCount();
	}

	/** Forwards retrieving the data to the source model. */
	virtual QVariant data(const QModelIndex &index, int role) const 
	{
		if (role == Qt::DisplayRole)
			return sourceModel()->data(mapToSource(index), FullDisplayRole);
		else
			return sourceModel()->data(mapToSource(index), role);
// 		qDebug("[SelectedTagView] Requesting data for row: %d, col: %d", index.row(), index.column());
	}
	
	virtual QVariant headerData(int, Qt::Orientation, int = Qt::DisplayRole ) 
	{ return QVariant(); }	
	/** Sets the source model and initialises _tagToRow and _rowToTag. 
	  *
	  * Emits modelReset().
	  */ 
	virtual void setSourceModel(VocabularyModel* pModel)
	{
		QAbstractProxyModel::setSourceModel(pModel);
		QModelIndex parent;
		int row = 0;
		for(int i = 0; i < pModel->rowCount(parent); ++i)
		{
			QModelIndex facetIndex = pModel->index(i, 0, parent);
			for(int j = 0; j < pModel->rowCount(facetIndex); ++j)
			{
				QModelIndex index = pModel->index(j, 0, facetIndex);
				ItemData* pData = (ItemData*) index.internalPointer();
				TagData* pTagData = pData->toTagData();
				_tagToRow[pTagData->tag()] = row;
				_rowToTag[row] = pTagData->tag();
				++row;
			}
		}
		qDebug("[TagListProxyModel.setSourceModel()] Added %d tags", row);
		connect(pModel, SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)), 
			SLOT(onVocabularyModelChanged(const QModelIndex &, const QModelIndex &)));
		connect(pModel, SIGNAL(modelReset()), SLOT(onModelReset()));
		reset();
	}
	/** @pre dynamic_cast<VocabularyModel*>(pModel) != 0 */
	virtual void setSourceModel(QAbstractItemModel* pModel)
	{
		assert(dynamic_cast<VocabularyModel*>(pModel));
		setSourceModel(static_cast<VocabularyModel*>(pModel));
	}
	
	/** Forwards setting the data to the source model. */
	virtual bool setData(const QModelIndex& index, 
		const QVariant & value, int role = Qt::EditRole)
	{
		return sourceModel()->setData(mapToSource(index), value, role);
	}
	
	/** Returns the source model casted to a VocabularyModel pointer. */
	VocabularyModel* vocabularyModel() const
	{
		return dynamic_cast<VocabularyModel*>(sourceModel());
	}
};


}
