/*
    msnchatsession.cpp - MSN Message Manager

    Copyright (c) 2002-2005 by Olivier Goffart        <ogoffart at kde.org>

    Kopete    (c) 2002-2005 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 "msnchatsession.h"

#include <tqlabel.h>
#include <tqimage.h>
#include <tqtooltip.h>
#include <tqfile.h>
#include <tqiconset.h>


#include <tdeconfig.h>
#include <kdebug.h>
#include <kinputdialog.h>
#include <tdelocale.h>
#include <tdemessagebox.h>
#include <tdepopupmenu.h>
#include <tdetempfile.h>
#include <tdemainwindow.h>
#include <tdetoolbar.h>
#include <krun.h>

#include "kopetecontactaction.h"
#include "kopetemetacontact.h"
#include "kopetecontactlist.h"
#include "kopetechatsessionmanager.h"
#include "kopeteuiglobal.h"
#include "kopeteglobal.h"
#include "kopeteview.h"

#include "msncontact.h"
#include "msnfiletransfersocket.h"
#include "msnaccount.h"
#include "msnswitchboardsocket.h"

#include "config.h"

#if !defined NDEBUG
#include "msndebugrawcmddlg.h"
#endif

MSNChatSession::MSNChatSession( Kopete::Protocol *protocol, const Kopete::Contact *user,
	Kopete::ContactPtrList others, const char *name )
: Kopete::ChatSession( user, others, protocol,  name )
{
	Kopete::ChatSessionManager::self()->registerChatSession( this );
	m_chatService = 0l;
	m_timeoutTimer =0L;
	m_newSession = true;
	m_connectionTry=0;

	setInstance(protocol->instance());

	connect( this, TQT_SIGNAL( messageSent( Kopete::Message&,
		Kopete::ChatSession* ) ),
		this, TQT_SLOT( slotMessageSent( Kopete::Message&,
		Kopete::ChatSession* ) ) );

	connect( this, TQT_SIGNAL( invitation(MSNInvitation*& ,  const TQString & , long unsigned int , MSNChatSession*  , MSNContact*  ) ) ,
		protocol,  TQT_SIGNAL( invitation(MSNInvitation*& ,  const TQString & , long unsigned int , MSNChatSession*  , MSNContact*  ) ) );


	m_actionInvite = new TDEActionMenu( i18n( "&Invite" ), "kontact_contacts", actionCollection(), "msnInvite" );
	connect ( m_actionInvite->popupMenu() , TQT_SIGNAL( aboutToShow() ) , this , TQT_SLOT(slotActionInviteAboutToShow() ) ) ;

	#if !defined NDEBUG
	new TDEAction( i18n( "Send Raw C&ommand..." ), 0, this, TQT_SLOT( slotDebugRawCommand() ), actionCollection(), "msnDebugRawCommand" ) ;
	#endif


	m_actionNudge=new TDEAction( i18n( "Send Nudge" ), "bell", 0, this, TQT_SLOT(slotSendNudge() ), actionCollection(), "msnSendNudge" ) ;
#if MSN_WEBCAM
	// Invite to receive webcam action
	m_actionWebcamReceive=new TDEAction( i18n( "View Contact's Webcam" ), "webcamreceive",  0, this, TQT_SLOT(slotWebcamReceive()), actionCollection(), "msnWebcamReceive" ) ;
	
	//Send webcam action
	m_actionWebcamSend=new TDEAction( i18n( "Send Webcam" ), "webcamsend",  0, this, TQT_SLOT(slotWebcamSend()), actionCollection(), "msnWebcamSend" ) ;
#endif
	
	new TDEAction( i18n( "Send File" ),"attach", 0, this, TQT_SLOT( slotSendFile() ), actionCollection(), "msnSendFile" );

	MSNContact *c = static_cast<MSNContact*>( others.first() );
	(new TDEAction( i18n( "Request Display Picture" ), "image", 0,  this, TQT_SLOT( slotRequestPicture() ), actionCollection(), "msnRequestDisplayPicture" ))->setEnabled(!c->object().isEmpty());

	if ( !c->object().isEmpty() )
	{
		
		connect( c, TQT_SIGNAL( displayPictureChanged() ), this, TQT_SLOT( slotDisplayPictureChanged() ) );
		m_image = new TQLabel( 0L, "kde toolbar widget" );
		new KWidgetAction( m_image, i18n( "MSN Display Picture" ), 0, this, TQT_SLOT( slotRequestPicture() ), actionCollection(), "msnDisplayPicture" );
		if(c->hasProperty(Kopete::Global::Properties::self()->photo().key())  )
		{
			//if the view doesn't exist yet, we will be unable to get the size of the toolbar
			// so when the view will exist, we will show the displaypicture.
			//How to know when a our view is created?  We can't.
			// but chances are the next created view will be for this KMM
			// And if it is not?  never mind. the icon will just be sized 22x22
			connect( Kopete::ChatSessionManager::self() , TQT_SIGNAL(viewActivated(KopeteView* )) , this, TQT_SLOT(slotDisplayPictureChanged()) );
			//it's viewActivated and not viewCreated because the view get his mainwindow only when it is shown.
		}
	}
	else
	{
		m_image = 0L;
	}

	setXMLFile("msnchatui.rc");
	
	setMayInvite( true );
}

MSNChatSession::~MSNChatSession()
{
	delete m_image;
	//force to disconnect the switchboard
	//not needed since the m_chatService has us as parent
	//	if(m_chatService)
	//		delete m_chatService;

	TQMap<unsigned long int, MSNInvitation*>::Iterator it;
	for( it = m_invitations.begin(); it != m_invitations.end() ; it = m_invitations.begin())
	{
		delete *it;
		m_invitations.remove( it );
	}
}

void MSNChatSession::createChat( const TQString &handle,
	const TQString &address, const TQString &auth, const TQString &ID )
{
	/* disabled because i don't want to reopen a chatwindow if we just closed it
	 * and the contact take much time to type his message
	 m_newSession= !(ID.isEmpty());
	*/
	
	if( m_chatService )
	{
		kdDebug(14140) << k_funcinfo << "Service already exists, disconnect them." << endl;
		delete m_chatService;
	}

//	uncomment this line if you don't want to the peer know when you close the window
//	setCanBeDeleted( false );

	m_chatService = new MSNSwitchBoardSocket( static_cast<MSNAccount*>( myself()->account() ) , this);
	m_chatService->setUseHttpMethod( static_cast<MSNAccount*>( myself()->account() )->useHttpMethod() );
	m_chatService->setHandle( myself()->account()->accountId() );
	m_chatService->setMsgHandle( handle );
	m_chatService->connectToSwitchBoard( ID, address, auth );

	connect( m_chatService, TQT_SIGNAL( userJoined(const TQString&,const TQString&,bool)),
		this, TQT_SLOT( slotUserJoined(const TQString&,const TQString&,bool) ) );
	connect( m_chatService, TQT_SIGNAL( userLeft(const TQString&,const TQString&)),
		this, TQT_SLOT( slotUserLeft(const TQString&,const TQString&) ) );
	connect( m_chatService, TQT_SIGNAL( msgReceived( Kopete::Message & ) ),
		this, TQT_SLOT( slotMessageReceived( Kopete::Message & ) ) );
	connect( m_chatService, TQT_SIGNAL( switchBoardClosed() ),
		this, TQT_SLOT( slotSwitchBoardClosed() ) );
	connect( m_chatService, TQT_SIGNAL( receivedTypingMsg( const TQString &, bool ) ),
		this, TQT_SLOT( receivedTypingMsg( const TQString &, bool ) ) );
	TDEConfig *config = TDEGlobal::config();
	config->setGroup( "MSN" );
	if(config->readBoolEntry( "SendTypingNotification" , true) )
	{
		connect( this, TQT_SIGNAL( myselfTyping( bool ) ),
			m_chatService, TQT_SLOT( sendTypingMsg( bool ) ) );
	}
	connect( m_chatService, TQT_SIGNAL( msgAcknowledgement(unsigned int, bool) ),
		this, TQT_SLOT( slotAcknowledgement(unsigned int, bool) ) );
	connect( m_chatService, TQT_SIGNAL( invitation( const TQString&, const TQString& ) ),
		this, TQT_SLOT( slotInvitation( const TQString&, const TQString& ) ) );
	connect( m_chatService, TQT_SIGNAL( nudgeReceived(const TQString&) ),
		this, TQT_SLOT( slotNudgeReceived(const TQString&) ) );
	connect( m_chatService, TQT_SIGNAL( errorMessage(int, const TQString& ) ), static_cast<MSNAccount *>(myself()->account()), TQT_SLOT( slotErrorMessageReceived(int, const TQString& ) ) );
	
	if(!m_timeoutTimer)
	{
		m_timeoutTimer=new TQTimer(this);
		connect( m_timeoutTimer , TQT_SIGNAL(timeout()), this , TQT_SLOT(slotConnectionTimeout() ) );
	}
	m_timeoutTimer->start(20000,true);
}

void MSNChatSession::slotUserJoined( const TQString &handle, const TQString &publicName, bool IRO )
{
	delete m_timeoutTimer;
	m_timeoutTimer=0L;
	
	if( !account()->contacts()[ handle ] )
		account()->addContact( handle, TQString(), 0L, Kopete::Account::Temporary);

	MSNContact *c = static_cast<MSNContact*>( account()->contacts()[ handle ] );

	c->setProperty( Kopete::Global::Properties::self()->nickName() , publicName);
	
	if(c->clientFlags() & MSNProtocol::MSNC4 )
	{
		m_actionNudge->setEnabled(true);
	}
#if MSN_WEBCAM
	if(c->clientFlags() & MSNProtocol::SupportWebcam )
	{
		m_actionWebcamReceive->setEnabled(true);
	}
#endif

	addContact(c , IRO); // don't show notificaions when we join wesalef
	if(!m_messagesQueue.empty() || !m_invitations.isEmpty())
		sendMessageQueue();

	TDEConfig *config = TDEGlobal::config();
	config->setGroup( "MSN" );
	if ( members().count()==1 && config->readNumEntry( "DownloadPicture", 1 ) >= 1 && !c->object().isEmpty() && !c->hasProperty(Kopete::Global::Properties::self()->photo().key()))
		slotRequestPicture();
}

void MSNChatSession::slotUserLeft( const TQString &handle, const TQString& reason )
{
	MSNContact *c = static_cast<MSNContact*>( myself()->account()->contacts()[ handle ] );
	if(c)
		removeContact(c, reason );
}



void MSNChatSession::slotSwitchBoardClosed()
{
	//kdDebug(14140) << "MSNChatSession::slotSwitchBoardClosed"  << endl;
	m_chatService->deleteLater();
	m_chatService=0l;

	cleanMessageQueue( i18n("Connection closed") );

	if(m_invitations.isEmpty())
		setCanBeDeleted( true );
}

void MSNChatSession::slotMessageSent(Kopete::Message &message,Kopete::ChatSession *)
{
	m_newSession=false;
 	if(m_chatService)
	{
		int id = m_chatService->sendMsg(message);
		if(id == -1)
		{
			m_messagesQueue.append(message);
			kdDebug(14140) << k_funcinfo << "Message added to the queue" <<endl;
		}
		else if( id== -2 ) //the message has not been sent
		{
			//FIXME:  tell the what window the message has been processed. but we havent't sent it 
			messageSucceeded();  //that should stop the blonking icon.
		}
		else if( id == -3) //the message has been sent as an immge
		{
			appendMessage(message); 
			messageSucceeded();
		}
		else
		{
			m_messagesSent.insert( id, message );
			message.setBg(TQColor()); // clear the bgColor
			message.setBody(message.plainBody() , Kopete::Message::PlainText ); //clear every custom tag which are not sent
			appendMessage(message); // send the own msg to chat window
		}
	}
	else // There's no switchboard available, so we must create a new one!
	{
		startChatSession();
		m_messagesQueue.append(message);
//		sendMessageQueue();
		//m_msgQueued=new Kopete::Message(message);
	}
}

void MSNChatSession::slotMessageReceived( Kopete::Message &msg )
{
	m_newSession=false;
	if( msg.plainBody().startsWith( "AutoMessage: " ) )
	{
		//FIXME: HardCodded color are not so good
		msg.setFg( TQColor( "SlateGray3" ) );
		TQFont f;
		f.setItalic( true );
		msg.setFont( f );
	}
	appendMessage( msg );
}

void MSNChatSession::slotActionInviteAboutToShow()
{
	// We can't simply insert  TDEAction in this menu bebause we don't know when to delete them.
	//  items inserted with insert items are automatically deleted when we call clear

	m_inviteactions.setAutoDelete(true);
	m_inviteactions.clear();

	m_actionInvite->popupMenu()->clear();

	
	TQDictIterator<Kopete::Contact> it( account()->contacts() );
	for( ; it.current(); ++it )
	{
		if( !members().contains( it.current() ) && it.current()->isOnline() && it.current() != myself() )
		{
			TDEAction *a=new KopeteContactAction( it.current(), this,
				TQT_SLOT( slotInviteContact( Kopete::Contact * ) ), m_actionInvite );
			m_actionInvite->insert( a );
			m_inviteactions.append( a ) ;
		}
	}
	TDEAction *b=new TDEAction( i18n ("Other..."), 0, this, TQT_SLOT( slotInviteOtherContact() ), m_actionInvite, "actionOther" );
	m_actionInvite->insert( b );
	m_inviteactions.append( b ) ;
}

void MSNChatSession::slotCloseSession()
{
	kdDebug(14140) << k_funcinfo  << m_chatService <<endl;
	if(m_chatService)
		m_chatService->slotCloseSession();
}

void MSNChatSession::slotInviteContact( Kopete::Contact *contact )
{
	if(contact)
		inviteContact( contact->contactId() );
}

void MSNChatSession::inviteContact(const TQString &contactId)
{
	if( m_chatService )
		m_chatService->slotInviteContact( contactId );
	else
		startChatSession();
}

void MSNChatSession::slotInviteOtherContact()
{
	bool ok;
	TQString handle = KInputDialog::getText(i18n( "MSN Plugin" ),
			i18n( "Please enter the email address of the person you want to invite:" ),
			TQString(), &ok );
	if( !ok )
		return;

	if( handle.contains('@') != 1 || handle.contains('.') <1)
	{
			KMessageBox::queuedMessageBox( Kopete::UI::Global::mainWidget(), KMessageBox::Sorry,
					i18n("<qt>You must enter a valid email address.</qt>"), i18n("MSN Plugin"));
			return;
	}

	inviteContact(handle);
}


void MSNChatSession::sendMessageQueue()
{
	if(!m_chatService)
	{
		kdDebug(14140) <<k_funcinfo << "Service doesn't exist" <<endl;
		return;
	}
//	kdDebug(14140) << "MSNChatSession::sendMessageQueue: " << m_messagesQueue.count() <<endl;
	for ( TQValueList<Kopete::Message>::iterator it = m_messagesQueue.begin(); it!=m_messagesQueue.end(); it = m_messagesQueue.begin() )
	{
		//m_chatService->sendMsg( *it)  ;
		slotMessageSent(*it , this);
		m_messagesQueue.remove(it);
	}


	TQMap<unsigned long int, MSNInvitation*>::Iterator it;
	for( it = m_invitations.begin(); it != m_invitations.end() ; ++it)
	{
		if(! (*it)->incoming() && (*it)->state()<MSNInvitation::Invited)
		{
			m_chatService->sendCommand( "MSG" , "N", true, (*it)->invitationHead().utf8() );
			(*it)->setState(MSNInvitation::Invited);
		}
	}
}

void MSNChatSession::slotAcknowledgement(unsigned int id, bool ack)
{
	if ( !m_messagesSent.contains( id ) )
	{
		// This is maybe a ACK/NAK for a non-messaging message
		return;
	}

	if ( !ack )
	{
		Kopete::Message m = m_messagesSent[ id ];
		TQString body = i18n( "The following message has not been sent correctly:\n%1" ).arg( m.plainBody() );
		Kopete::Message msg = Kopete::Message( m.to().first(), members(), body, Kopete::Message::Internal, Kopete::Message::PlainText );
		appendMessage( msg );
		//stop the stupid animation
		messageSucceeded();  
	}
	else
	{
		messageSucceeded();
	}

	m_messagesSent.remove( id );
}

void MSNChatSession::slotInvitation(const TQString &handle, const TQString &msg)
{
	//FIXME! a contact from another account can send a file
	MSNContact *c = static_cast<MSNContact*>( myself()->account()->contacts()[ handle ] );
	if(!c)
		return;

	TQRegExp rx("Invitation-Cookie: ([0-9]*)");
	rx.search(msg);
	long unsigned int cookie=rx.cap(1).toUInt();

	if(m_invitations.contains(cookie))
	{
		MSNInvitation *msnI=m_invitations[cookie];
		msnI->parseInvitation(msg);
	}
	else if( msg.contains("Invitation-Command: INVITE") )
	{
		if( msg.contains(MSNFileTransferSocket::applicationID()) )
		{
			MSNFileTransferSocket *MFTS=new MSNFileTransferSocket(myself()->account()->accountId(),c,true,this);
			connect(MFTS, TQT_SIGNAL( done(MSNInvitation*) ) , this , TQT_SLOT( invitationDone(MSNInvitation*) ));
			m_invitations.insert( cookie  , MFTS);
			MFTS->parseInvitation(msg);
			setCanBeDeleted(false);
		}
		else
		{
			MSNInvitation *i=0l;
			emit invitation( i , msg, cookie, this, c );
			if(i)
			{
				m_invitations.insert( cookie  , i );
				//don't delete this if all invitation are not done
				setCanBeDeleted(false);
			}
			else
			{
				rx=TQRegExp("Application-Name: ([^\\r\\n]*)");
				rx.search(msg);
				TQString inviteName = rx.cap( 1 );

				TQString body = i18n(
					"%1 has sent an unimplemented invitation, the invitation was rejected.\n"
					"The invitation was: %2" )
						.arg( c->property( Kopete::Global::Properties::self()->nickName()).value().toString(), inviteName );
				Kopete::Message tmpMsg = Kopete::Message( c , members() , body , Kopete::Message::Internal, Kopete::Message::PlainText);
				appendMessage(tmpMsg);

				m_chatService->sendCommand( "MSG" , "N", true, MSNInvitation::unimplemented(cookie) );
			}
		}
	}
}

void MSNChatSession::invitationDone(MSNInvitation* MFTS)
{
	kdDebug(14140) << k_funcinfo <<endl;
	m_invitations.remove(MFTS->cookie());
//	MFTS->deleteLater();
	delete MFTS;
	if(!m_chatService && m_invitations.isEmpty())
		setCanBeDeleted(true);
}

void MSNChatSession::sendFile(const TQString &fileLocation, const TQString &/*fileName*/,
	long unsigned int fileSize)
{
	// TODO create a switchboard to send the file is one is not available.
	if(m_chatService && members().getFirst())
	{
		m_chatService->PeerDispatcher()->sendFile(fileLocation, (TQ_INT64)fileSize, members().getFirst()->contactId());
	}
}

void MSNChatSession::initInvitation(MSNInvitation* invitation)
{
	connect(invitation->object(), TQT_SIGNAL( done(MSNInvitation*) ) , this , TQT_SLOT( invitationDone(MSNInvitation*) ));
	m_invitations.insert( invitation->cookie() , invitation);

	if(m_chatService)
	{
		m_chatService->sendCommand( "MSG" , "N", true, invitation->invitationHead().utf8() );
		invitation->setState(MSNInvitation::Invited);
	}
	else
	{
		startChatSession();
	}
}

void MSNChatSession::slotRequestPicture()
{
	TQPtrList<Kopete::Contact> mb=members();
	MSNContact *c = static_cast<MSNContact*>( mb.first() );
	if(!c)
	 return;
	
	if( !c->hasProperty(Kopete::Global::Properties::self()->photo().key()))
	{
		if(m_chatService)
		{
			if( !c->object().isEmpty() )
				m_chatService->requestDisplayPicture();
		}
		else if(myself()->onlineStatus().isDefinitelyOnline()  && myself()->onlineStatus().status() != Kopete::OnlineStatus::Invisible )
			startChatSession();
	}
	else
	{ //we already have the picture, just show it.
		KRun::runURL( KURL::fromPathOrURL( c->property(Kopete::Global::Properties::self()->photo()).value().toString() ), "image/png" );
	}

}

void MSNChatSession::slotDisplayPictureChanged()
{
	TQPtrList<Kopete::Contact> mb=members();
	MSNContact *c = static_cast<MSNContact *>( mb.first() );
	if ( c && m_image )
	{
		if(c->hasProperty(Kopete::Global::Properties::self()->photo().key()))
		{
			int sz=22;
			// get the size of the toolbar were the aciton is plugged.
			//  if you know a better way to get the toolbar, let me know
			TDEMainWindow *w= view(false) ? dynamic_cast<TDEMainWindow*>( view(false)->mainWidget()->topLevelWidget() ) : 0L;
			if(w)
			{
				//We connected that in the constructor.  we don't need to keep this slot active.
				disconnect( Kopete::ChatSessionManager::self() , TQT_SIGNAL(viewActivated(KopeteView* )) , this, TQT_SLOT(slotDisplayPictureChanged()) );
			
				TQPtrListIterator<TDEToolBar>  it=w->toolBarIterator() ;
				TDEAction *imgAction=actionCollection()->action("msnDisplayPicture");
				if(imgAction)  while(it)
				{
					TDEToolBar *tb=*it;
					if(imgAction->isPlugged(tb))
					{
						sz=tb->iconSize();
						//ipdate if the size of the toolbar change.
						disconnect(tb, TQT_SIGNAL(modechange()), this, TQT_SLOT(slotDisplayPictureChanged()));
						connect(tb, TQT_SIGNAL(modechange()), this, TQT_SLOT(slotDisplayPictureChanged()));
						break;
					}
					++it;
				}
			}
			TQString imgURL=c->property(Kopete::Global::Properties::self()->photo()).value().toString();
			TQImage scaledImg = TQPixmap( imgURL ).convertToImage().smoothScale( sz, sz );
			if(!scaledImg.isNull())
				m_image->setPixmap( scaledImg );
			else
			{ //the image has maybe not been transfered correctly..  force to download again
				c->removeProperty(Kopete::Global::Properties::self()->photo());
				//slotDisplayPictureChanged(); //don't do that or we might end in a infinite loop
			}
			TQToolTip::add( m_image, "<qt><img src=\"" + imgURL + "\"></qt>" );
			
		}
		else 
		{
			TDEConfig *config = TDEGlobal::config();
			config->setGroup( "MSN" );
			if ( config->readNumEntry( "DownloadPicture", 1 ) >= 1 && !c->object().isEmpty() )
				slotRequestPicture();
		}
	}
}

void MSNChatSession::slotDebugRawCommand()
{
#if !defined NDEBUG
	if ( !m_chatService )
		return;

	MSNDebugRawCmdDlg *dlg = new MSNDebugRawCmdDlg( 0L );
	int result = dlg->exec();
	if( result == TQDialog::Accepted && m_chatService )
	{
		m_chatService->sendCommand( dlg->command(), dlg->params(),
					dlg->addId(), dlg->msg().replace("\n","\r\n").utf8() );
	}
	delete dlg;
#endif
}


void MSNChatSession::receivedTypingMsg( const TQString &contactId, bool b )
{
	MSNContact *c = dynamic_cast<MSNContact *>( account()->contacts()[ contactId ] );
	if(c && m_newSession &&  !view(false))
	{
		//this was originaly in MSNAccount::slotCreateChat
		TDEGlobal::config()->setGroup( "MSN" );
		bool notifyNewChat = TDEGlobal::config()->readBoolEntry( "NotifyNewChat", false );
		if (  notifyNewChat  )
		{
			// this internal message should open the window if they not exist
			TQString body = i18n( "%1 has started a chat with you" ).arg( c->metaContact()->displayName() );
			Kopete::Message tmpMsg = Kopete::Message( c, members(), body, Kopete::Message::Internal, Kopete::Message::PlainText );
			appendMessage( tmpMsg );
		}
	}
	m_newSession=false;
	if(c)
		Kopete::ChatSession::receivedTypingMsg(c,b);
}

void MSNChatSession::slotSendNudge()
{
	if(m_chatService)
	{
		m_chatService->sendNudge();
		Kopete::Message msg = Kopete::Message( myself(), members() , i18n ( "has sent a nudge" ),  Kopete::Message::Outbound, 
											   Kopete::Message::PlainText, TQString(), Kopete::Message::TypeAction );
		appendMessage( msg );

	}
}


void MSNChatSession::slotNudgeReceived(const TQString& handle)
{
	Kopete::Contact *c = account()->contacts()[ handle ] ;
	if(!c)
		c=members().getFirst();
	Kopete::Message msg = Kopete::Message(c, myself(), i18n ( "has sent you a nudge" ), Kopete::Message::Inbound, 
										  Kopete::Message::PlainText, TQString(), Kopete::Message::TypeAction );
	appendMessage( msg );
	// Emit the nudge/buzz notification (configured by user).
	emitNudgeNotification();
}


void MSNChatSession::slotWebcamReceive()
{
#if MSN_WEBCAM
	if(m_chatService && members().getFirst())
	{
		m_chatService->PeerDispatcher()->startWebcam(myself()->contactId() , members().getFirst()->contactId() , true);
	}
#endif
}

void MSNChatSession::slotWebcamSend()
{
#if MSN_WEBCAM
	kdDebug(14140) << k_funcinfo << endl;
	if(m_chatService && members().getFirst())
	{
		m_chatService->PeerDispatcher()->startWebcam(myself()->contactId() , members().getFirst()->contactId() , false);
	}
#endif
}


void MSNChatSession::slotSendFile()
      {
              TQPtrList<Kopete::Contact>contacts = members();
              static_cast<MSNContact *>(contacts.first())->sendFile();
      }

void MSNChatSession::startChatSession()
{
	TQPtrList<Kopete::Contact> mb=members();
	static_cast<MSNAccount*>( account() )->slotStartChatSession( mb.first()->contactId() );
	
	if(!m_timeoutTimer)
	{
		m_timeoutTimer=new TQTimer(this);
		connect( m_timeoutTimer , TQT_SIGNAL(timeout()), this , TQT_SLOT(slotConnectionTimeout() ) );
	}
	m_timeoutTimer->start(20000, true);
}


void MSNChatSession::cleanMessageQueue( const TQString & reason )
{
	delete m_timeoutTimer;
	m_timeoutTimer=0L;

	uint nb=m_messagesQueue.count()+m_messagesSent.count();
	if(nb==0)
		return;
	else if(nb==1)
	{
		Kopete::Message m;
		if(m_messagesQueue.count() == 1)
			m=m_messagesQueue.first();
		else
			m=m_messagesSent.begin().data();
		
		TQString body=i18n("The following message has not been sent correctly  (%1): \n%2").arg(reason, m.plainBody());
		Kopete::Message msg = Kopete::Message(m.to().first() , members() , body , Kopete::Message::Internal, Kopete::Message::PlainText);
		appendMessage(msg);
	}
	else
	{
		Kopete::Message m;
		TQString body=i18n("These messages have not been sent correctly (%1): <br /><ul>").arg(reason);
		for ( TQMap<unsigned int , Kopete::Message>::iterator it = m_messagesSent.begin(); it!=m_messagesSent.end(); it = m_messagesSent.begin() )
		{
			m=it.data();
			body+= "<li>"+m.escapedBody()+"</li>";
			m_messagesSent.remove(it);
		}
		for ( TQValueList<Kopete::Message>::iterator it = m_messagesQueue.begin(); it!=m_messagesQueue.end(); it = m_messagesQueue.begin() )
		{
			m=(*it);
			body+= "<li>"+m.escapedBody()+"</li>";
			m_messagesQueue.remove(it);
		}
		body+="</ul>";
		Kopete::Message msg = Kopete::Message(m.to().first() , members() , body , Kopete::Message::Internal, Kopete::Message::RichText);
		appendMessage(msg);

	}
	m_messagesQueue.clear();
	m_messagesSent.clear();
	messageSucceeded(); //stop stupid animation
}

void MSNChatSession::slotConnectionTimeout()
{
	m_connectionTry++;
	if(m_chatService)
	{
		disconnect(m_chatService , 0 , this , 0 );
		m_chatService->deleteLater();
		m_chatService=0L;
	}
	
	if( m_connectionTry > 3 )
	{
		cleanMessageQueue( i18n("Impossible to establish the connection") );
		delete m_timeoutTimer;
		m_timeoutTimer=0L;
		return;
	}
	startChatSession();

}




#include "msnchatsession.moc"
