/*
    chatmemberslistwidget.cpp - Chat Members List Widget

    Copyright (c) 2004      by Richard Smith         <kde@metafoo.co.uk>

    Kopete    (c) 2002-2004 by the Kopete developers <kopete-devel@kde.org>

    *************************************************************************
    *                                                                       *
    * 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 "chatmemberslistwidget.h"

#include "kopetechatsession.h"
#include "kopetecontact.h"
#include "kopeteonlinestatus.h"
#include "kopeteglobal.h"
#include "kopeteprotocol.h"
#include "kopeteaccount.h"
#include "kopetemetacontact.h"

#include <tdeabc/stdaddressbook.h>
#include <tdeabc/addressee.h>
#include <tdeabc/vcardconverter.h>
#include <kdebug.h>
#include <tdemultipledrag.h>
#include <tdepopupmenu.h>

#include <tqheader.h>
#include <tqtooltip.h>

//BEGIN ChatMembersListWidget::ToolTip

class ChatMembersListWidget::ToolTip : public TQToolTip
{
public:
	ToolTip( TDEListView *parent )
		: TQToolTip( parent->viewport() ), m_listView ( parent )
	{
	}

	virtual ~ToolTip()
	{
		remove( m_listView->viewport() );
	}

	void maybeTip( const TQPoint &pos )
	{
		if( TQListViewItem *item = m_listView->itemAt( pos ) )
		{
			TQRect itemRect = m_listView->itemRect( item );
			if( itemRect.contains( pos ) )
				tip( itemRect, static_cast<ContactItem*>( item )->contact()->toolTip() );
		}
	}

private:
	TDEListView *m_listView;
};

//END ChatMembersListWidget::ToolTip


//BEGIN ChatMembersListWidget::ContactItem

ChatMembersListWidget::ContactItem::ContactItem( ChatMembersListWidget *parent, Kopete::Contact *contact )
	: TDEListViewItem( parent ), m_contact( contact )
{
	TQString nick = m_contact->property(Kopete::Global::Properties::self()->nickName().key()).value().toString();
	if ( nick.isEmpty() )
		nick = m_contact->contactId();
	setText( 0, nick );
	setDragEnabled(true);

	connect( m_contact, TQ_SIGNAL( propertyChanged( Kopete::Contact *, const TQString &, const TQVariant &, const TQVariant & ) ),
	         this, TQ_SLOT( slotPropertyChanged( Kopete::Contact *, const TQString &, const TQVariant &, const TQVariant & ) ) ) ;

	setStatus( parent->session()->contactOnlineStatus(m_contact) );
	reposition();
}

void ChatMembersListWidget::ContactItem::slotPropertyChanged( Kopete::Contact*,
	const TQString &key, const TQVariant&, const TQVariant &newValue  )
{
	if ( key == Kopete::Global::Properties::self()->nickName().key() )
	{
		setText( 0, newValue.toString() );
		reposition();
	}
}

void ChatMembersListWidget::ContactItem::setStatus( const Kopete::OnlineStatus &status )
{
	setPixmap( 0, status.iconFor( m_contact ) );
	reposition();
}

void ChatMembersListWidget::ContactItem::reposition()
{
	// TQt's listview sorting is pathetic - it's impossible to reposition a single item
	// when its key changes, without re-sorting the whole list. Plus, the whole list gets
	// re-sorted whenever an item is added/removed. So, we do manual sorting.
	// In particular, this makes adding N items O(N^2) not O(N^2 log N).
	Kopete::ChatSession *session = static_cast<ChatMembersListWidget*>( listView() )->session();
	int ourWeight = session->contactOnlineStatus(m_contact).weight();
	TQListViewItem *after = 0;

	for ( TQListViewItem *it = TDEListViewItem::listView()->firstChild(); it; it = it->nextSibling() )
	{
		ChatMembersListWidget::ContactItem *item = static_cast<ChatMembersListWidget::ContactItem*>(it);
		int theirWeight = session->contactOnlineStatus(item->m_contact).weight();

		if( theirWeight < ourWeight ||
			(theirWeight == ourWeight && item->text(0).localeAwareCompare( text(0) ) > 0 ) )
		{
			break;
		}

		after = it;
	}

	moveItem( after );
}

//END ChatMembersListWidget::ContactItem


//BEGIN ChatMembersListWidget

ChatMembersListWidget::ChatMembersListWidget( Kopete::ChatSession *session, TQWidget *parent, const char *name )
	 : TDEListView( parent, name ), m_session( session )
{
	// use our own custom tooltips
	setShowToolTips( false );
	m_toolTip = new ToolTip( this );

	// set up display: no header
	setAllColumnsShowFocus( true );
	addColumn( TQString(), -1 );
	header()->setStretchEnabled( true, 0 );
	header()->hide();

	// list is sorted by us, not by TQt
	setSorting( -1 );

	// add chat members
	slotContactAdded( session->myself() );
	for ( TQPtrListIterator<Kopete::Contact> it( session->members() ); it.current(); ++it )
		slotContactAdded( *it );

	connect( this, TQ_SIGNAL( contextMenu( TDEListView*, TQListViewItem *, const TQPoint &) ),
	         TQ_SLOT( slotContextMenu(TDEListView*, TQListViewItem *, const TQPoint & ) ) );
	connect( this, TQ_SIGNAL( executed( TQListViewItem* ) ),
	         TQ_SLOT( slotExecute( TQListViewItem * ) ) );

	connect( session, TQ_SIGNAL( contactAdded(const Kopete::Contact*, bool) ),
	         this, TQ_SLOT( slotContactAdded(const Kopete::Contact*) ) );
	connect( session, TQ_SIGNAL( contactRemoved(const Kopete::Contact*, const TQString&, Kopete::Message::MessageFormat, bool) ),
	         this, TQ_SLOT( slotContactRemoved(const Kopete::Contact*) ) );
	connect( session, TQ_SIGNAL( onlineStatusChanged( Kopete::Contact *, const Kopete::OnlineStatus & , const Kopete::OnlineStatus &) ),
	         this, TQ_SLOT( slotContactStatusChanged( Kopete::Contact *, const Kopete::OnlineStatus & ) ) );
}

ChatMembersListWidget::~ChatMembersListWidget()
{
}

void ChatMembersListWidget::slotContextMenu( TDEListView*, TQListViewItem *item, const TQPoint &point )
{
	if ( ContactItem *contactItem = dynamic_cast<ContactItem*>(item) )
	{
		TDEPopupMenu *p = contactItem->contact()->popupMenu( session() );
		connect( p, TQ_SIGNAL( aboutToHide() ), p, TQ_SLOT( deleteLater() ) );
		p->popup( point );
	}
}

void ChatMembersListWidget::slotContactAdded( const Kopete::Contact *contact )
{
	if ( !m_members.contains( contact ) )
		m_members.insert( contact, new ContactItem( this, const_cast<Kopete::Contact*>( contact ) ) );
}

void ChatMembersListWidget::slotContactRemoved( const Kopete::Contact *contact )
{
	kdDebug(14000) << k_funcinfo << endl;
	if ( m_members.contains( contact ) && contact != session()->myself() )
	{
		delete m_members[ contact ];
		m_members.remove( contact );
	}
}

void ChatMembersListWidget::slotContactStatusChanged( Kopete::Contact *contact, const Kopete::OnlineStatus &status )
{
	if ( m_members.contains( contact ) )
		m_members[contact]->setStatus( status );
}

void ChatMembersListWidget::slotExecute( TQListViewItem *item )
{
	if ( ContactItem *contactItem = dynamic_cast<ContactItem*>(item ) )
	{
		Kopete::Contact *contact=contactItem->contact();

		if(!contact || contact == contact->account()->myself())
			return;
				
		contact->execute();
	}
}

TQDragObject *ChatMembersListWidget::dragObject()
{
	TQListViewItem *currentLVI = currentItem();
	if( !currentLVI )
		return 0L;

	ContactItem *lvi = dynamic_cast<ContactItem*>( currentLVI );
	if( !lvi )
		return 0L;

	Kopete::Contact *c = lvi->contact();
	KMultipleDrag *drag = new KMultipleDrag( this );
	drag->addDragObject( new TQStoredDrag("application/x-qlistviewitem", 0L ) );

	TQStoredDrag *d = new TQStoredDrag("kopete/x-contact", 0L );
	d->setEncodedData( TQString( c->protocol()->pluginId()+TQChar( 0xE000 )+c->account()->accountId()+TQChar( 0xE000 )+ c->contactId() ).utf8() );
	drag->addDragObject( d );

	TDEABC::Addressee address = TDEABC::StdAddressBook::self()->findByUid(c->metaContact()->metaContactId());

	if( !address.isEmpty() )
	{
		drag->addDragObject( new TQTextDrag( address.fullEmail(), 0L ) );
		TDEABC::VCardConverter converter;
		TQString vcard = converter.createVCard( address );
		if( !vcard.isNull() )
		{
			TQStoredDrag *vcardDrag = new TQStoredDrag("text/x-vcard", 0L );
			vcardDrag->setEncodedData( vcard.utf8() );
			drag->addDragObject( vcardDrag );
		}
	}

	drag->setPixmap( c->onlineStatus().iconFor(c, 12) );

	return drag;
}


//END ChatMembersListWidget

#include "chatmemberslistwidget.moc"
