/*
    Kopete Groupwise Protocol
    conferencetask.cpp - Event Handling task responsible for all conference related events

    Copyright (c) 2004      SUSE Linux AG	 	 http://www.suse.com
    
    Based on Iris, Copyright (C) 2003  Justin Karneges

    Kopete (c) 2002-2004 by the Kopete developers <kopete-devel@kde.org>
 
    *************************************************************************
    *                                                                       *
    * This library is free software; you can redistribute it and/or         *
    * modify it under the terms of the GNU Lesser General Public            *
    * License as published by the Free Software Foundation; either          *
    * version 2 of the License, or (at your option) any later version.      *
    *                                                                       *
    *************************************************************************
*/

#include "client.h"
#include "userdetailsmanager.h"

#include "conferencetask.h"

ConferenceTask::ConferenceTask( Task* parent )
 : EventTask( parent )
{
	// register all the events that this task monitors
	registerEvent( GroupWise::ConferenceClosed );
	registerEvent( GroupWise::ConferenceJoined );
	registerEvent( GroupWise::ConferenceLeft );
	registerEvent( GroupWise::ReceiveMessage );
	registerEvent( GroupWise::UserTyping );
	registerEvent( GroupWise::UserNotTyping );
	registerEvent( GroupWise::ConferenceInvite );
	registerEvent( GroupWise::ConferenceInviteNotify );
	registerEvent( GroupWise::ConferenceReject );
	registerEvent( GroupWise::ReceiveAutoReply );
	// GW7
	registerEvent( GroupWise::ReceivedBroadcast );
	registerEvent( GroupWise::ReceivedSystemBroadcast );

	// listen to the UserDetailsManager telling us that user details are available
	connect( client()->userDetailsManager(), TQT_SIGNAL( gotContactDetails( const GroupWise::ContactDetails & ) ), 
		TQT_SLOT( slotReceiveUserDetails( const GroupWise::ContactDetails & ) ) );
}


ConferenceTask::~ConferenceTask()
{
}

void ConferenceTask::dumpConferenceEvent( ConferenceEvent & evt )
{
	client()->debug( TQString( "Conference Event - guid: %1 user: %2 timestamp: %3:%4:%5" ).arg
			( evt.guid ).arg( evt.user.ascii() ).arg( evt.timeStamp.time().hour() ).arg
			( evt.timeStamp.time().minute() ).arg( evt.timeStamp.time().second() ) ); 
 	client()->debug( TQString( "                  flags: %1" ).arg( evt.flags, 8 ) );
}

bool ConferenceTask::take( Transfer * transfer )
{
	EventTransfer * incomingEvent;
	if ( forMe( transfer, incomingEvent ) )
	{
		client()->debug( "Got a conference event:" );
		ConferenceEvent event;
		event.type = (GroupWise::Event)( incomingEvent->eventType() );
		event.timeStamp = incomingEvent->timeStamp();
		event.user = incomingEvent->source();
		event.flags = 0;
		Q_ASSERT( incomingEvent->hasGuid() );
		event.guid = incomingEvent->guid();
		
		switch ( event.type )
		{
			case GroupWise::ConferenceClosed:
				// extra debug - we never see these events, against spec.
				client()->debug( "********************" );
				client()->debug( "* ConferenceClosed *" );
				client()->debug( "* ConferenceClosed *" );
				client()->debug( "* ConferenceClosed *" );
				client()->debug( "********************" );
				emit closed( event );
				break;
			case GroupWise::ConferenceJoined:
				Q_ASSERT( incomingEvent->hasFlags() );
				event.flags = incomingEvent->flags();
				client()->debug( "ConferenceJoined" );
				if ( !queueWhileAwaitingData( event ) )
					emit joined( event );
				break;
			case GroupWise::ConferenceLeft:
				Q_ASSERT( incomingEvent->hasFlags() );
				event.flags = incomingEvent->flags();
				client()->debug( "ConferenceLeft" );
				emit left( event );
				break;
			case GroupWise::ReceiveMessage:
				Q_ASSERT( incomingEvent->hasFlags() );
				event.flags = incomingEvent->flags();
				Q_ASSERT( incomingEvent->hasMessage() );
				event.message = incomingEvent->message();
				client()->debug( "ReceiveMessage" );
				client()->debug( TQString( "message: %1" ).arg( event.message ) );
				if ( !queueWhileAwaitingData( event ) )
					emit message( event );
				break;
			case GroupWise::UserTyping:
				client()->debug( "UserTyping" );
				emit typing( event );
				break;
			case GroupWise::UserNotTyping:
				client()->debug( "UserNotTyping" );
				emit notTyping( event );
				break;
			case GroupWise::ConferenceInvite:
				Q_ASSERT( incomingEvent->hasMessage() );
				event.message = incomingEvent->message();
				client()->debug( "ConferenceInvite" );
				client()->debug( TQString( "message: %1" ).arg( event.message ) );
				if ( !queueWhileAwaitingData( event ) )
					emit invited( event );
				break;
			case GroupWise::ConferenceInviteNotify:
				client()->debug( "ConferenceInviteNotify" );
				if ( !queueWhileAwaitingData( event ) )
					emit otherInvited( event );
				break;
			case GroupWise::ConferenceReject:
				client()->debug( "ConferenceReject" );
				if ( !queueWhileAwaitingData( event ) )
					emit invitationDeclined( event );
				break;
			case GroupWise::ReceiveAutoReply:
				Q_ASSERT( incomingEvent->hasFlags() );
				event.flags = incomingEvent->flags();
				Q_ASSERT( incomingEvent->hasMessage() );
				event.message = incomingEvent->message();
				client()->debug( "ReceiveAutoReply" );
				client()->debug( TQString( "message: %1" ).arg( event.message.ascii() ) );
				emit autoReply( event );
				break;
			case GroupWise::ReceivedBroadcast:
				Q_ASSERT( incomingEvent->hasMessage() );
				event.message = incomingEvent->message();
				client()->debug( "ReceivedBroadCast" );
				client()->debug( TQString( "message: %1" ).arg( event.message ) );
				if ( !queueWhileAwaitingData( event ) )
					emit broadcast( event );
				break;
			case GroupWise::ReceivedSystemBroadcast:
				Q_ASSERT( incomingEvent->hasMessage() );
				event.message = incomingEvent->message();
				client()->debug( "ReceivedSystemBroadCast" );
				client()->debug( TQString( "message: %1" ).arg( event.message ) );
				emit systemBroadcast( event );
				break;
			default:
				client()->debug( TQString( "WARNING: didn't handle registered event %1, on conference %2" ).arg( incomingEvent->eventType() ).arg( event.guid.ascii() ) );
		}
		dumpConferenceEvent( event );

		return true;
	}
	return false;
}

void ConferenceTask::slotReceiveUserDetails( const GroupWise::ContactDetails & details )
{
	client()->debug( "ConferenceTask::slotReceiveUserDetails()" );
	
	// dequeue any events which are deliverable now we have these details 
	TQValueListIterator< ConferenceEvent > end = m_pendingEvents.end();
	TQValueListIterator< ConferenceEvent > it = m_pendingEvents.begin();
	while ( it != end )
	{
		TQValueListIterator< ConferenceEvent > current = it;
		++it;
		// if the details relate to event, try again to handle it
		if ( details.dn == (*current).user )
		{
			client()->debug( TQString( " - got details for event involving %1" ).arg( (*current).user ) );
			switch ( (*current).type )
			{
				case GroupWise::ConferenceJoined:
					client()->debug( "ConferenceJoined" );
					emit joined( *current );
					break;
				case GroupWise::ReceiveMessage:
					client()->debug( "ReceiveMessage" );
					emit message( *current );
					break;
				case GroupWise::ConferenceInvite:
					client()->debug( "ConferenceInvite" );
					emit invited( *current );
					break;
				case GroupWise::ConferenceInviteNotify:
					client()->debug( "ConferenceInviteNotify" );
					emit otherInvited( *current );
					break;
				default:
					client()->debug( "Queued an event while waiting for more data, but didn't write a handler for the dequeue!" );
			}
			m_pendingEvents.remove( current );
			client()->debug( TQString( "Event handled - now %1 pending events" ).arg
			( (uint)m_pendingEvents.count() ) );
		}
	}
}


bool ConferenceTask::queueWhileAwaitingData( const ConferenceEvent & event )
{
	if ( client()->userDetailsManager()->known( event.user ) )
	{
		client()->debug( "ConferenceTask::queueWhileAwaitingData() - source is known!" );
		return false;
	}
	else
	{
		client()->debug( TQString( "ConferenceTask::queueWhileAwaitingData() - queueing event involving %1" ).arg( event.user ) );
		client()->userDetailsManager()->requestDetails( event.user );
		m_pendingEvents.append( event );
		return true;
	}
}

#include "conferencetask.moc"
