/*
 *  Copyright (C) 2007-2008 CMM Sigma Andrzej Chmielowiec <cmmsigma@cmmsigma.eu>
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License version 3
 *  as published by the Free Software Foundation.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 */

#include <QtGui>

#include "TreeModel.h"
#include "TreeItem.h"
#include "STokenItem.h"

#include "crd_ut10xx.h"
#include "CRD_UT10XX_threads.h"

TreeModel::TreeModel(QObject *parent): QAbstractItemModel(parent)
{
	QMap<int, QVariant> rootData;
	rootData.insert(Qt::DisplayRole, tr("Available tokens"));
	mRootItem = new TreeItem(rootData);
	mRootItem->setModel(this);
	CRD_UT10XX_lib_init();
}

TreeModel::~TreeModel()
{
	CRD_UT10XX_lib_finish();
	delete mRootItem;
}

QVariant
TreeModel::data(const QModelIndex &index, int role) const
{
	if (!index.isValid())
		return QVariant();
	
	TreeItem *item = static_cast<TreeItem*>(index.internalPointer());
	
	return item->data(role);
}

Qt::ItemFlags
TreeModel::flags(const QModelIndex &index) const
{
	if (!index.isValid())
		return Qt::ItemIsEnabled;
	
	return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable;
}

QVariant
TreeModel::headerData(int section, Qt::Orientation orientation, int role) const
{
	if (section == 0 && orientation == Qt::Horizontal)
		return mRootItem->data(role);
	
	return QVariant();
}

QModelIndex
TreeModel::index(int row, int column, const QModelIndex &parent) const
{
	TreeItem *parentItem;
	
	if (!parent.isValid())
		parentItem = mRootItem;
	else
		parentItem = static_cast<TreeItem*>(parent.internalPointer());
	
	TreeItem *childItem = parentItem->child(row);
	
	if (childItem)
		return createIndex(row, column, childItem);
	else
		return QModelIndex();
}

QModelIndex
TreeModel::parent(const QModelIndex &index) const
{
	if (!index.isValid())
		return QModelIndex();
	
	TreeItem *childItem = static_cast<TreeItem*>(index.internalPointer());
	TreeItem *parentItem = childItem->parent();
	
	if (parentItem == mRootItem)
		return QModelIndex();
	
	return createIndex(parentItem->row(), 0, parentItem);
}

int
TreeModel::rowCount(const QModelIndex &parent) const
{
	TreeItem *parentItem;
	
	if (!parent.isValid())
		parentItem = mRootItem;
	else
		parentItem = static_cast<TreeItem*>(parent.internalPointer());
	
	return parentItem->rowCount();
}

int
TreeModel::columnCount(const QModelIndex &parent) const
{
	if (parent.isValid())
		return static_cast<TreeItem*>(parent.internalPointer())->columnCount();
	else
		return mRootItem->columnCount();
}

int
TreeModel::refresh()
{
	QList<int> presentList;
	CRD_UT10XX_t *ut;
	int i = 0;
	
	// Find new devices and actualize them.
	CRD_UT10XX_thread_lib_refresh libRefreshThread;
	libRefreshThread.execWithCursor(Qt::WaitCursor);
	
	// Delete tokens removed from host.
	while (i < mRootItem->childCount())
	{
		STokenItem *sToken = static_cast<STokenItem*>(mRootItem->child(i));
		int idx;
		
		if ((idx = sToken->libIndex()) < 0)
		{
			deleteChild(mRootItem, i);
		}
		else
		{
			presentList.append(idx);
			i++;
		}
	}
	
	// Append new tokens to list.
	for (i = 0; ; i++)
	{
		if ((ut = CRD_UT10XX_find_by_index(i)) == 0)
			break;
		
		if (!presentList.contains(i))
			appendChild(mRootItem, new STokenItem(ut));
	}
	
	// Refresh all tokns.
	for (i = 0; i < mRootItem->childCount(); i++)
	{
		static_cast<STokenItem*>(mRootItem->child(i))->refresh();
	}
	
	return (i);
}

void
TreeModel::setActive(const QModelIndex &index)
/*TreeModel::setActive(const QModelIndex &index, const QModelIndex &prev)*/
{
	QWidget *page;
	
	if (index.isValid())
	{
		page = static_cast<TreeItem*>(index.internalPointer())->page();
	}
	else
	{
		page = mRootItem->page();
	}
	
	emit pageActivated(page);
}

void
TreeModel::repaintItemData(TreeItem *item)
{
	QModelIndex index;
	
	if (item != mRootItem)
		index = createIndex(item->row(), 0, item);
	
	emit dataChanged(index, index);
}

void
TreeModel::appendChild(TreeItem *parent, TreeItem *child)
{
	QModelIndex parentIndex;
	
	if (parent != mRootItem)
		parentIndex = createIndex(parent->row(), 0, parent);
	
	beginInsertRows(parentIndex, parent->childCount(), parent->childCount());
	parent->appendChild(child);
	endInsertRows();
}

void
TreeModel::insertChild(TreeItem *parent, int idx, TreeItem *child)
{
	QModelIndex parentIndex;
	
	if (parent != mRootItem)
		parentIndex = createIndex(parent->row(), 0, parent);
	
	beginInsertRows(parentIndex, idx, idx);
	parent->insertChild(idx, child);
	endInsertRows();
}

void
TreeModel::deleteChild(TreeItem *parent, int idx)
{
	QModelIndex parentIndex;
	
	if (parent != mRootItem)
		parentIndex = createIndex(parent->row(), 0, parent);
	
	if (parent->childCount() > idx)
	{
		deleteAllChilds(parent->child(idx));
		emit pageDeleted(parent->child(idx)->page());
		beginRemoveRows(parentIndex, idx, idx);
		delete parent->childTakeAt(idx);
		endRemoveRows();
	}
}

void
TreeModel::deleteAllChilds(TreeItem *parent)
{
	while (parent->childCount() > 0)
		deleteChild(parent, 0);
}

void
TreeModel::execContextMenu(const QModelIndex &index)
{
	TreeItem *item = static_cast<TreeItem*>(index.internalPointer());
	if(item != 0)
		item->displayContextMenu(index);
}
