/***************************************************************************
              userlistmodel.cpp  -  User List Model implementation
                             -------------------
    begin                : Sun Nov 18 2007
    copyright            : (C) 2007 by Edward Sheldrake
    email                : ejs1920@yahoo.co.uk
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/

#include <QtAlgorithms>

/* need to convert shared bytes to size string */
#include <dclib/cutils.h>
#include "../dcconfig.h"

#include "userlistmodel.h"

/** Initialises values */
UserListItem::UserListItem()
{
	/* Everything is initialised in addUser(), no point doing it here */
	shared    = 0;
	index     = -1; //invalid
	sorttop   = FALSE;
	highlight = FALSE;
}

/** */
UserListItem::~UserListItem()
{

}


/** */
UserListModel::UserListModel() : QAbstractItemModel()
{
	sortColumn = COLUMN_NICK;
	sortOrder = Qt::AscendingOrder;
	stripper.setPattern("\\[.*\\]");
	stripper.setMinimal(TRUE);
}

/** delete all items in model */
UserListModel::~UserListModel()
{
	clear();
}

/** */
int UserListModel::rowCount( const QModelIndex & /* index */ ) const
{
	return itemList.size();
}

/** */
int UserListModel::columnCount( const QModelIndex & /* index */ ) const
{
	return 9;
}

/** */
QVariant UserListModel::data( const QModelIndex & index, int role ) const
{
	if ( !index.isValid() )
	{
		return QVariant();
	}
	
	UserListItem * item = itemList[index.row()];
	
	if ( item == 0 )
	{
		return QVariant();
	}
	
	if ( role == Qt::DisplayRole ) // text
	{
		switch ( index.column() )
		{
			case COLUMN_NICK:     return item->nick;
			case COLUMN_COMMENT:  return item->comment;
			case COLUMN_TAG:      return item->tag;
			case COLUMN_SPEED:    return item->speed;
			case COLUMN_EMAIL:    return item->email;
			case COLUMN_SHARE:    return QString( CUtils::GetSizeString( item->shared, g_pConfig->GetUnit() ).Data() );
			case COLUMN_IP:       return item->ip;
			case COLUMN_LOCKPK:   return item->lockpk;
			case COLUMN_SUPPORTS: return item->supports;
		}
	}
	else if ( role == Qt::DecorationRole ) // icon
	{
		if ( index.column() == COLUMN_NICK )
		{
			return item->pixmap;
		}
	}
	else if ( role == Qt::ToolTipRole ) // tool tip
	{
		if ( index.column() == COLUMN_SHARE )
		{
			return QString::number( item->shared );
		}
	}
	else if ( role == Qt::TextAlignmentRole ) // text alignment
	{
		if ( index.column() == COLUMN_SHARE )
		{
			return Qt::AlignRight;
		}
	}
	else if ( role == Qt::ForegroundRole) // text colour
	{
		if ( (index.column() == COLUMN_NICK) && (item->highlight) )
		{
			return QColor( 255, 0, 0 );
		}
	}
	
	return QVariant();
}

/** */
QVariant UserListModel::headerData( int section, Qt::Orientation orientation, int role ) const
{
	if ( (orientation == Qt::Horizontal) && (role == Qt::DisplayRole) )
	{
		switch ( section )
		{
			case COLUMN_NICK:     return tr("Nick");
			case COLUMN_COMMENT:  return tr("Comment");
			case COLUMN_TAG:      return tr("Tag");
			case COLUMN_SPEED:    return tr("Speed");
			case COLUMN_EMAIL:    return tr("Email");
			case COLUMN_SHARE:    return tr("Share");
			case COLUMN_IP:       return tr("IP");
			case COLUMN_LOCKPK:   return tr("Lock/PK");
			case COLUMN_SUPPORTS: return tr("Supports");
		}
	}
	
	return QVariant();
}

/** */
bool UserListItemNickLessThan( const UserListItem * l, const UserListItem * r )
{
	if ( l->sorttop && !r->sorttop )
	{
		return TRUE;
	}
	else if ( !l->sorttop && r->sorttop )
	{
		return FALSE;
	}
	else
	{
		return l->nick_lc < r->nick_lc;
	}
}

/** */
bool UserListItemCommentLessThan( const UserListItem * l, const UserListItem * r )
{
	if ( l->sorttop && !r->sorttop )
	{
		return TRUE;
	}
	else if ( !l->sorttop && r->sorttop )
	{
		return FALSE;
	}
	else
	{
		return l->comment_lc < r->comment_lc;
	}
}

/** */
bool UserListItemTagLessThan( const UserListItem * l, const UserListItem * r )
{
	if ( l->sorttop && !r->sorttop )
	{
		return TRUE;
	}
	else if ( !l->sorttop && r->sorttop )
	{
		return FALSE;
	}
	else
	{
		return l->tag_lc < r->tag_lc;
	}
}

/** */
bool UserListItemSpeedLessThan( const UserListItem * l, const UserListItem * r )
{
	if ( l->sorttop && !r->sorttop )
	{
		return TRUE;
	}
	else if ( !l->sorttop && r->sorttop )
	{
		return FALSE;
	}
	else
	{
		return l->speed_lc < r->speed_lc;
	}
}

/** */
bool UserListItemEmailLessThan( const UserListItem * l, const UserListItem * r )
{
	if ( l->sorttop && !r->sorttop )
	{
		return TRUE;
	}
	else if ( !l->sorttop && r->sorttop )
	{
		return FALSE;
	}
	else
	{
		return l->email_lc < r->email_lc;
	}
}

/** */
bool UserListItemShareLessThan( const UserListItem * l, const UserListItem * r )
{
	if ( l->sorttop && !r->sorttop )
	{
		return TRUE;
	}
	else if ( !l->sorttop && r->sorttop )
	{
		return FALSE;
	}
	else
	{
		return l->shared < r->shared;
	}
}

/** */
bool UserListItemIPLessThan( const UserListItem * l, const UserListItem * r )
{
	if ( l->sorttop && !r->sorttop )
	{
		return TRUE;
	}
	else if ( !l->sorttop && r->sorttop )
	{
		return FALSE;
	}
	else
	{
		return l->ip < r->ip;
	}
}

/** */
bool UserListItemLockPKLessThan( const UserListItem * l, const UserListItem * r )
{
	if ( l->sorttop && !r->sorttop )
	{
		return TRUE;
	}
	else if ( !l->sorttop && r->sorttop )
	{
		return FALSE;
	}
	else
	{
		return l->lockpk < r->lockpk;
	}
}

/** */
bool UserListItemSupportsLessThan( const UserListItem * l, const UserListItem * r )
{
	if ( l->sorttop && !r->sorttop )
	{
		return TRUE;
	}
	else if ( !l->sorttop && r->sorttop )
	{
		return FALSE;
	}
	else
	{
		return l->supports < r->supports;
	}
}

/** */
bool UserListItemNickGreaterThan( const UserListItem * l, const UserListItem * r )
{
	if ( l->sorttop && !r->sorttop )
	{
		return FALSE;
	}
	else if ( !l->sorttop && r->sorttop )
	{
		return TRUE;
	}
	else
	{
		return l->nick_lc > r->nick_lc;
	}
}

/** */
bool UserListItemCommentGreaterThan( const UserListItem * l, const UserListItem * r )
{
	if ( l->sorttop && !r->sorttop )
	{
		return FALSE;
	}
	else if ( !l->sorttop && r->sorttop )
	{
		return TRUE;
	}
	else
	{
		return l->comment_lc > r->comment_lc;
	}
}

/** */
bool UserListItemTagGreaterThan( const UserListItem * l, const UserListItem * r )
{
	if ( l->sorttop && !r->sorttop )
	{
		return FALSE;
	}
	else if ( !l->sorttop && r->sorttop )
	{
		return TRUE;
	}
	else
	{
		return l->tag_lc > r->tag_lc;
	}
}

/** */
bool UserListItemSpeedGreaterThan( const UserListItem * l, const UserListItem * r )
{
	if ( l->sorttop && !r->sorttop )
	{
		return FALSE;
	}
	else if ( !l->sorttop && r->sorttop )
	{
		return TRUE;
	}
	else
	{
		return l->speed_lc > r->speed_lc;
	}
}

/** */
bool UserListItemEmailGreaterThan( const UserListItem * l, const UserListItem * r )
{
	if ( l->sorttop && !r->sorttop )
	{
		return FALSE;
	}
	else if ( !l->sorttop && r->sorttop )
	{
		return TRUE;
	}
	else
	{
		return l->email_lc > r->email_lc;
	}
}

/** */
bool UserListItemShareGreaterThan( const UserListItem * l, const UserListItem * r )
{
	if ( l->sorttop && !r->sorttop )
	{
		return FALSE;
	}
	else if ( !l->sorttop && r->sorttop )
	{
		return TRUE;
	}
	else
	{
		return l->shared > r->shared;
	}
}

/** */
bool UserListItemIPGreaterThan( const UserListItem * l, const UserListItem * r )
{
	if ( l->sorttop && !r->sorttop )
	{
		return FALSE;
	}
	else if ( !l->sorttop && r->sorttop )
	{
		return TRUE;
	}
	else
	{
		return l->ip > r->ip;
	}
}

/** */
bool UserListItemLockPKGreaterThan( const UserListItem * l, const UserListItem * r )
{
	if ( l->sorttop && !r->sorttop )
	{
		return FALSE;
	}
	else if ( !l->sorttop && r->sorttop )
	{
		return TRUE;
	}
	else
	{
		return l->lockpk > r->lockpk;
	}
}

/** */
bool UserListItemSupportsGreaterThan( const UserListItem * l, const UserListItem * r )
{
	if ( l->sorttop && !r->sorttop )
	{
		return FALSE;
	}
	else if ( !l->sorttop && r->sorttop )
	{
		return TRUE;
	}
	else
	{
		return l->supports > r->supports;
	}
}

/** */
void UserListModel::sort( int column, Qt::SortOrder order )
{
	sortColumn = column;
	sortOrder = order;

	if ( column == -1 ) // sorting disabled
	{
		return;
	}

	emit layoutAboutToBeChanged();
	
	if ( order == Qt::AscendingOrder )
	{
		switch ( column )
		{
			case COLUMN_NICK:
				qSort( itemList.begin(), itemList.end(), UserListItemNickLessThan );
				break;
			case COLUMN_COMMENT:
				qSort( itemList.begin(), itemList.end(), UserListItemCommentLessThan );
				break;
			case COLUMN_TAG:
				qSort( itemList.begin(), itemList.end(), UserListItemTagLessThan );
				break;
			case COLUMN_SPEED:
				qSort( itemList.begin(), itemList.end(), UserListItemSpeedLessThan );
				break;
			case COLUMN_EMAIL:
				qSort( itemList.begin(), itemList.end(), UserListItemEmailLessThan );
				break;
			case COLUMN_SHARE:
				qSort( itemList.begin(), itemList.end(), UserListItemShareLessThan );
				break;
			case COLUMN_IP:
				qSort( itemList.begin(), itemList.end(), UserListItemIPLessThan );
				break;
			case COLUMN_LOCKPK:
				qSort( itemList.begin(), itemList.end(), UserListItemLockPKLessThan );
				break;
			case COLUMN_SUPPORTS:
				qSort( itemList.begin(), itemList.end(), UserListItemSupportsLessThan );
				break;
		}
	}
	else if ( order == Qt::DescendingOrder )
	{
		switch ( column )
		{
			case COLUMN_NICK:
				qSort( itemList.begin(), itemList.end(), UserListItemNickGreaterThan );
				break;
			case COLUMN_COMMENT:
				qSort( itemList.begin(), itemList.end(), UserListItemCommentGreaterThan );
				break;
			case COLUMN_TAG:
				qSort( itemList.begin(), itemList.end(), UserListItemTagGreaterThan );
				break;
			case COLUMN_SPEED:
				qSort( itemList.begin(), itemList.end(), UserListItemSpeedGreaterThan );
				break;
			case COLUMN_EMAIL:
				qSort( itemList.begin(), itemList.end(), UserListItemEmailGreaterThan );
				break;
			case COLUMN_SHARE:
				qSort( itemList.begin(), itemList.end(), UserListItemShareGreaterThan );
				break;
			case COLUMN_IP:
				qSort( itemList.begin(), itemList.end(), UserListItemIPGreaterThan );
				break;
			case COLUMN_LOCKPK:
				qSort( itemList.begin(), itemList.end(), UserListItemLockPKGreaterThan );
				break;
			case COLUMN_SUPPORTS:
				qSort( itemList.begin(), itemList.end(), UserListItemSupportsGreaterThan );
				break;
		}
	}
	
	for ( int i = 0; i < itemList.size(); i++ )
	{
		(itemList.at(i))->index = i;
	}
	
	emit layoutChanged();
}

/** */
QModelIndex UserListModel::index( int row, int column, const QModelIndex & parent ) const
{
	if ( !hasIndex( row, column, parent ) )
	{
		return QModelIndex();
	}
	
	return createIndex( row, column );
}

/** */
QModelIndex UserListModel::parent( const QModelIndex & /* parent */ ) const
{
	return QModelIndex();
}

/** */
void UserListModel::clear()
{
	emit layoutAboutToBeChanged();
	
	for( int i = 0; i < itemList.size(); i++ )
	{
		delete itemList.at(i);
	}
	
	itemList.clear();
	itemHash.clear();
	
	emit layoutChanged();
}

/** */
bool UserListModel::hasNick( const QString & nick ) const
{
	return itemHash.contains( nick );
}

/** */
void UserListModel::removeUser( const QString & nick )
{
	UserListItem * item = itemHash.value( nick );
	
	if ( item == 0 )
	{
		return;
	}
	
	emit layoutAboutToBeChanged();
	
	itemHash.remove( nick );
	itemList.removeAt( item->index );
	
	// fix indexes
	for( int i = item->index; i < itemList.size(); i++ )
	{
		(itemList.at(i))->index--;
	}
	
	// destroy item
	delete item;
	
	emit layoutChanged();
}

/** */
void UserListModel::addUser( const QString nick,
			     const QPixmap icon,
			     const QString comment,
			     const QString tag,
			     const QString speed,
			     const QString email,
			     const ulonglong share,
			     const QString ip,
			     const QString lockpk,
			     const QString supports )
{
	UserListItem * item = 0;
	
	if ( itemHash.contains( nick ) )
	{
		item = itemHash.value( nick );
		
		item->pixmap   = icon;
		item->comment  = comment;
		item->tag      = tag;
		item->speed    = speed;
		item->email    = email;
		item->shared   = share;
		item->ip       = ip;
		item->lockpk   = lockpk;
		item->supports = supports;
		
		item->nick_lc    = nick.toLower();
		item->nick_stripped = nick.toLower().replace( stripper, "" );
		item->comment_lc = comment.toLower();
		item->tag_lc     = tag.toLower();
		item->speed_lc   = speed.toLower();
		item->email_lc   = email.toLower();
		
		QModelIndex topLeft = createIndex( item->index, COLUMN_NICK );
		QModelIndex bottomRight = createIndex( item->index, COLUMN_SUPPORTS );
		
		emit dataChanged( topLeft, bottomRight );
		
		if ( sortColumn != COLUMN_NICK )
		{
			sort( sortColumn, sortOrder );
		}
		
		return;
	}
	
	emit layoutAboutToBeChanged();
	
	item = new UserListItem();
	
	item->nick     = nick;
	item->pixmap   = icon;
	item->comment  = comment;
	item->tag      = tag;
	item->speed    = speed;
	item->email    = email;
	item->shared   = share;
	item->ip       = ip;
	item->lockpk   = lockpk;
	item->supports = supports;
	
	item->nick_lc    = nick.toLower();
	item->nick_stripped = nick.toLower().replace( stripper, "" );
	item->comment_lc = comment.toLower();
	item->tag_lc     = tag.toLower();
	item->speed_lc   = speed.toLower();
	item->email_lc   = email.toLower();
	
	itemHash[ nick ] = item;
	
	if ( sortColumn == -1 ) // if sorting disabled
	{
		item->index = itemList.size();
		itemList.append( item );
		
		emit layoutChanged();
		
		return; 
	}

	// find position in list for new item
	int i = 0;
	
	if ( sortOrder == Qt::AscendingOrder )
	{
		switch ( sortColumn )
		{
			case COLUMN_NICK:
				for ( ; i < itemList.size(); i++ )
				{
					if ( UserListItemNickLessThan( item, itemList.at(i) ) )
					{
						break;
					}
				}
				break;
			case COLUMN_COMMENT:
				for ( ; i < itemList.size(); i++ )
				{
					if ( UserListItemCommentLessThan( item, itemList.at(i) ) )
					{
						break;
					}
				}
				break;
			case COLUMN_TAG:
				for ( ; i < itemList.size(); i++ )
				{
					if ( UserListItemTagLessThan( item, itemList.at(i) ) )
					{
						break;
					}
				}
				break;
			case COLUMN_SPEED:
				for ( ; i < itemList.size(); i++ )
				{
					if ( UserListItemSpeedLessThan( item, itemList.at(i) ) )
					{
						break;
					}
				}
				break;
			case COLUMN_EMAIL:
				for ( ; i < itemList.size(); i++ )
				{
					if ( UserListItemEmailLessThan( item, itemList.at(i) ) )
					{
						break;
					}
				}
				break;
			case COLUMN_SHARE:
				for ( ; i < itemList.size(); i++ )
				{
					if ( UserListItemShareLessThan( item, itemList.at(i) ) )
					{
						break;
					}
				}
				break;
			case COLUMN_IP:
				for ( ; i < itemList.size(); i++ )
				{
					if ( UserListItemIPLessThan( item, itemList.at(i) ) )
					{
						break;
					}
				}
				break;
			case COLUMN_LOCKPK:
				for ( ; i < itemList.size(); i++ )
				{
					if ( UserListItemLockPKLessThan( item, itemList.at(i) ) )
					{
						break;
					}
				}
				break;
			case COLUMN_SUPPORTS:
				for ( ; i < itemList.size(); i++ )
				{
					if ( UserListItemSupportsLessThan( item, itemList.at(i) ) )
					{
						break;
					}
				}
				break;
		}
	}
	else if ( sortOrder == Qt::DescendingOrder )
	{
		switch ( sortColumn )
		{
			case COLUMN_NICK:
				for ( ; i < itemList.size(); i++ )
				{
					if ( UserListItemNickGreaterThan( item, itemList.at(i) ) )
					{
						break;
					}
				}
				break;
			case COLUMN_COMMENT:
				for ( ; i < itemList.size(); i++ )
				{
					if ( UserListItemCommentGreaterThan( item, itemList.at(i) ) )
					{
						break;
					}
				}
				break;
			case COLUMN_TAG:
				for ( ; i < itemList.size(); i++ )
				{
					if ( UserListItemTagGreaterThan( item, itemList.at(i) ) )
					{
						break;
					}
				}
				break;
			case COLUMN_SPEED:
				for ( ; i < itemList.size(); i++ )
				{
					if ( UserListItemSpeedGreaterThan( item, itemList.at(i) ) )
					{
						break;
					}
				}
				break;
			case COLUMN_EMAIL:
				for ( ; i < itemList.size(); i++ )
				{
					if ( UserListItemEmailGreaterThan( item, itemList.at(i) ) )
					{
						break;
					}
				}
				break;
			case COLUMN_SHARE:
				for ( ; i < itemList.size(); i++ )
				{
					if ( UserListItemShareGreaterThan( item, itemList.at(i) ) )
					{
						break;
					}
				}
				break;
			case COLUMN_IP:
				for ( ; i < itemList.size(); i++ )
				{
					if ( UserListItemIPGreaterThan( item, itemList.at(i) ) )
					{
						break;
					}
				}
				break;
			case COLUMN_LOCKPK:
				for ( ; i < itemList.size(); i++ )
				{
					if ( UserListItemLockPKGreaterThan( item, itemList.at(i) ) )
					{
						break;
					}
				}
				break;
			case COLUMN_SUPPORTS:
				for ( ; i < itemList.size(); i++ )
				{
					if ( UserListItemSupportsGreaterThan( item, itemList.at(i) ) )
					{
						break;
					}
				}
				break;
		}
	}
	
	item->index = i;
	
	itemList.insert( i, item );
	
	i++;
	
	// fix remaining indexes
	for ( ; i < itemList.size(); i++ )
	{
		(itemList.at(i))->index++;
	}
	
	emit layoutChanged();
}

/** */
void UserListModel::updateIcon( const QString & nick, const QPixmap icon )
{
	UserListItem * item = itemHash.value( nick );
	
	if ( item == 0 )
	{
		return;
	}
	
	item->pixmap = icon;
	
	QModelIndex position = createIndex( item->index, COLUMN_NICK );
	
	emit dataChanged( position, position );
}

/** */
void UserListModel::updateComment( const QString & nick, const QString comment )
{
	UserListItem * item = itemHash.value( nick );
	
	if ( item == 0 )
	{
		return;
	}
	
	item->comment = comment;
	item->comment_lc = comment.toLower();
	
	QModelIndex position = createIndex( item->index, COLUMN_COMMENT );
	
	emit dataChanged( position, position );
	
	if ( sortColumn == COLUMN_COMMENT )
	{
		sort( sortColumn, sortOrder );
	}
}

/** */
void UserListModel::updateTag( const QString & nick, const QString tag )
{
	UserListItem * item = itemHash.value( nick );
	
	if ( item == 0 )
	{
		return;
	}
	
	item->tag = tag;
	item->tag_lc = tag.toLower();
	
	QModelIndex position = createIndex( item->index, COLUMN_TAG );
	
	emit dataChanged( position, position );
	
	if ( sortColumn == COLUMN_TAG )
	{
		sort( sortColumn, sortOrder );
	}
}

/** */
void UserListModel::updateSpeed( const QString & nick, const QString speed )
{
	UserListItem * item = itemHash.value( nick );
	
	if ( item == 0 )
	{
		return;
	}
	
	item->speed = speed;
	item->speed_lc = speed.toLower();
	
	QModelIndex position = createIndex( item->index, COLUMN_SPEED );
	
	emit dataChanged( position, position );
	
	if ( sortColumn == COLUMN_SPEED )
	{
		sort( sortColumn, sortOrder );
	}
}

/** */
void UserListModel::updateEmail( const QString & nick, const QString email )
{
	UserListItem * item = itemHash.value( nick );
	
	if ( item == 0 )
	{
		return;
	}
	
	item->email = email;
	item->email_lc = email.toLower();
	
	QModelIndex position = createIndex( item->index, COLUMN_EMAIL );
	
	emit dataChanged( position, position );
	
	if ( sortColumn == COLUMN_EMAIL )
	{
		sort( sortColumn, sortOrder );
	}
}

/** */
void UserListModel::updateShare( const QString & nick, const ulonglong share )
{
	UserListItem * item = itemHash.value( nick );
	
	if ( item == 0 )
	{
		return;
	}
	
	item->shared = share;
	
	QModelIndex position = createIndex( item->index, COLUMN_SHARE );
	
	emit dataChanged( position, position );
	
	if ( sortColumn == COLUMN_SHARE )
	{
		sort( sortColumn, sortOrder );
	}
}

/** */
void UserListModel::updateIP( const QString & nick, const QString ip )
{
	UserListItem * item = itemHash.value( nick );
	
	if ( item == 0 )
	{
		return;
	}
	
	item->ip = ip;
	
	QModelIndex position = createIndex( item->index, COLUMN_IP );
	
	emit dataChanged( position, position );
	
	if ( sortColumn == COLUMN_IP )
	{
		sort( sortColumn, sortOrder );
	}
}

/** */
void UserListModel::updateLockPK( const QString & nick, const QString lockpk )
{
	UserListItem * item = itemHash.value( nick );
	
	if ( item == 0 )
	{
		return;
	}
	
	item->lockpk = lockpk;
	
	QModelIndex position = createIndex( item->index, COLUMN_LOCKPK );
	
	emit dataChanged( position, position );
	
	if ( sortColumn == COLUMN_LOCKPK )
	{
		sort( sortColumn, sortOrder );
	}
}

/** */
void UserListModel::updateSupports( const QString & nick, const QString supports )
{
	UserListItem * item = itemHash.value( nick );
	
	if ( item == 0 )
	{
		return;
	}
	
	item->supports = supports;
	
	QModelIndex position = createIndex( item->index, COLUMN_SUPPORTS );
	
	emit dataChanged( position, position );
	
	if ( sortColumn == COLUMN_SUPPORTS )
	{
		sort( sortColumn, sortOrder );
	}
}

/** */
void UserListModel::setSortTop( const QString & nick, const bool top )
{
	UserListItem * item = itemHash.value( nick );
	
	if ( item == 0 )
	{
		return;
	}
	
	if ( item->sorttop == top )
	{
		return;
	}
	
	item->sorttop = top;
	
	sort( sortColumn, sortOrder );
}

/** */
void UserListModel::setHighlight( const QString & nick, const bool highlight )
{
	UserListItem * item = itemHash.value( nick );
	
	if ( item == 0 )
	{
		return;
	}
	
	item->highlight = highlight;
	
	QModelIndex position = createIndex( item->index, COLUMN_NICK );
	
	emit dataChanged( position, position );
}

/** */
QModelIndex UserListModel::indexForNick( const QString & nick ) const
{
	UserListItem * item = itemHash.value( nick );
	
	if ( item == 0 )
	{
		return QModelIndex();
	}
	
	return createIndex( item->index, COLUMN_NICK );
}

/** */
QStringList UserListModel::matchNicksContaining( const QString & part, bool stripTags ) const
{
	QStringList matches;
	UserListItem * item;
	
	if ( part == "" )
	{
		return matches;
	}
	
	if ( stripTags )
	{
		for ( int i = 0; i < itemList.size(); i++ )
		{
			item = itemList.at(i);
			if ( item->nick_stripped.contains(part) )
			{
				matches << item->nick;
			}
		}
	}
	else
	{
		for ( int i = 0; i < itemList.size(); i++ )
		{
			item = itemList.at(i);
			if ( item->nick_lc.contains(part) )
			{
				matches << item->nick;
			}
		}
	}
	
	return matches;
}

/** */
QStringList UserListModel::matchNicksStartingWith( const QString & part, bool stripTags ) const
{
	QStringList matches;
	UserListItem * item;
	
	if ( part == "" )
	{
		return matches;
	}
	
	if ( stripTags )
	{
		for ( int i = 0; i < itemList.size(); i++ )
		{
			item = itemList.at(i);
			if ( item->nick_stripped.startsWith(part) )
			{
				matches << item->nick;
			}
		}	
	}
	else
	{
		for ( int i = 0; i < itemList.size(); i++ )
		{
			item = itemList.at(i);
			if ( item->nick_lc.startsWith(part) )
			{
				matches << item->nick;
			}
		}
	}
	
	return matches;
}
