/*
	Kopete Oscar Protocol
	connection.cpp - independent protocol encapsulation

	Copyright (c) 2004-2005 by Matt Rogers <mattr@kde.org>

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

	Kopete (c) 2002-2005 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 "connection.h"
#include "client.h"
#include "connector.h"
#include "oscarclientstream.h"
#include "rateclassmanager.h"
#include "task.h"
#include "transfer.h"
#include <tdeapplication.h>
#include <kdebug.h>

#include "oscartypeclasses.h"


class ConnectionPrivate
{
public:
	DWORD snacSequence;
	WORD flapSequence;

	TQValueList<int> familyList;
	RateClassManager* rateClassManager;

	ClientStream* clientStream;
	Connector* connector;
	Client* client;

	Task* root;
};



Connection::Connection( Connector* connector, ClientStream* cs, const char* name )
: TQObject( 0, name )
{
	d = new ConnectionPrivate();
	d->clientStream = cs;
	d->client = 0;
	d->connector = connector;
	d->rateClassManager = new RateClassManager( this );
	d->root = new Task( this, true /* isRoot */ );
	m_loggedIn = false;
	initSequence();

}

Connection::~Connection()
{

	delete d->rateClassManager;
	delete d->clientStream;
	delete d->connector;
	delete d->root;
	delete d;
}

void Connection::setClient( Client* c )
{
	d->client = c;
	connect( c, TQ_SIGNAL( loggedIn() ), this, TQ_SLOT( loggedIn() ) );
}

void Connection::connectToServer( const TQString& host, bool auth )
{
	connect( d->clientStream, TQ_SIGNAL( error( int ) ), this, TQ_SLOT( streamSocketError( int ) ) );
	connect( d->clientStream, TQ_SIGNAL( readyRead() ), this, TQ_SLOT( streamReadyRead() ) );
	connect( d->clientStream, TQ_SIGNAL( connected() ), this, TQ_SIGNAL( connected() ) );
	d->clientStream->connectToServer( host, auth );
}

void Connection::close()
{
	d->clientStream->close();
	reset();
}

bool Connection::isSupported( int family ) const
{
	return ( d->familyList.findIndex( family ) != -1 );
}

TQValueList<int> Connection::supportedFamilies() const
{
	return d->familyList;
}

void Connection::addToSupportedFamilies( const TQValueList<int>& familyList )
{
	d->familyList += familyList;
}

void Connection::addToSupportedFamilies( int family )
{
	d->familyList.append( family );
}

void Connection::taskError( const Oscar::SNAC& s, int errCode )
{
	d->client->notifyTaskError( s, errCode, false /*fatal*/ );
}

void Connection::fatalTaskError( const Oscar::SNAC& s, int errCode )
{
	d->client->notifyTaskError( s, errCode, true /* fatal */ );
}

Oscar::Settings* Connection::settings() const
{
	return d->client->clientSettings();
}

TQ_UINT16 Connection::flapSequence()
{
	d->flapSequence++;
	if ( d->flapSequence >= 0x8000 ) //the max flap sequence is 0x8000 ( HEX )
		d->flapSequence = 1;

	return d->flapSequence;
}

TQ_UINT32 Connection::snacSequence()
{
	d->snacSequence++;
	return d->snacSequence;
}

TQString Connection::userId() const
{
	return d->client->userId();
}

TQString Connection::password() const
{
	return d->client->password();
}

bool Connection::isIcq() const
{
	return d->client->isIcq();
}

Task* Connection::rootTask() const
{
	return d->root;
}

SSIManager* Connection::ssiManager() const
{
	return d->client->ssiManager();
}

const Oscar::ClientVersion* Connection::version() const
{
	return d->client->version();
}

bool Connection::isLoggedIn() const
{
	return m_loggedIn;
}

RateClassManager* Connection::rateManager() const
{
	return d->rateClassManager;
}

void Connection::send( Transfer* request ) const
{
	if( !d->clientStream )
	{
		kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "No stream to write on!" << endl;
		return;
	}
	d->rateClassManager->queue( request );

}

void Connection::forcedSend( Transfer* request ) const
{
	if ( !d->clientStream )
	{
		kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "No stream to write on" << endl;
		return;
	}
	d->clientStream->write( request );
}

void Connection::initSequence()
{
	d->snacSequence = ( TDEApplication::random() & 0xFFFF );
	d->flapSequence = ( TDEApplication::random() & 0xFFFF );
}

void Connection::distribute( Transfer * transfer ) const
{
	//d->rateClassManager->recalcRateLevels();
	if( !rootTask()->take( transfer ) )
		kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "root task refused transfer" << endl;

	delete transfer;
}

void Connection::reset()
{
	//clear the family list
	d->familyList.clear();
	d->rateClassManager->reset();
}

void Connection::streamReadyRead()
{
	// take the incoming transfer and distribute it to the task tree
	Transfer * transfer = d->clientStream->read();
	distribute( transfer );
}

void Connection::loggedIn()
{
	m_loggedIn = true;
}

void Connection::streamSocketError( int code )
{
	emit socketError( code, d->clientStream->errorText() );
}

#include "connection.moc"
