/*
* Copyright (c) 2005 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description:    The class provides the FC session information
*
*/




//  INCLUDES
#include <e32base.h>
#include <badesca.h>
#include <s32strm.h>

#include "fcsession.h"
#include "fcinterface.h"
#include "sdporiginfield.h"
#include "sdpconnectionfield.h"
#include "sdpmediafield.h"
#include "sdpfmtattributefield.h"
#include "sdpattributefield.h"
#include "sdpdocument.h"

// ============================ MEMBER FUNCTIONS ===============================

// -----------------------------------------------------------------------------
// CFCSession::NewL
// Two-phased constructor.
// -----------------------------------------------------------------------------
//
CFCSession* CFCSession::NewL( MFCPlugIn* aPlugIn, 
		                      TUint32 aIapId, 
		                      TUint32 aPort )
	{
	CFCSession* self = CFCSession::NewLC( aPlugIn, aIapId, aPort );
	CleanupStack::Pop(self);
	return self;
	}

// -----------------------------------------------------------------------------
// CFCSession::NewLC
// Two-phased constructor.
// -----------------------------------------------------------------------------
//
CFCSession* CFCSession::NewLC( MFCPlugIn* aPlugIn, 
		                       TUint32 aIapId, 
		                       TUint32 aPort )
	{
	CFCSession* self = new (ELeave) CFCSession( aPort );
	CleanupStack::PushL(self);
	self->ConstructL( aPlugIn, aIapId );
	return self;
	}

// -----------------------------------------------------------------------------
// CFCSession::ConstructL
// Symbian 2nd phase constructor.
// -----------------------------------------------------------------------------
//
void CFCSession::ConstructL( MFCPlugIn* aPlugIn, TUint32 aIapId )
	{
	User::LeaveIfNull( aPlugIn );
	
	iSdpFmtAttributeFields = 
	    new (ELeave) RPointerArray<CSdpFmtAttributeField>(1);
	
	iPlugIn = ( CFCInterface* ) aPlugIn;	    
	
	iPlugIn->SetIapId( aIapId );
	iPlugIn->SetLocalPort( iPort );
	}
	
// -----------------------------------------------------------------------------
// CFCSession::~CFCSession
// destructor.
// -----------------------------------------------------------------------------
//
CFCSession::~CFCSession()
	{		
	if (iSdpFmtAttributeFields)
		{
		iSdpFmtAttributeFields->ResetAndDestroy();
		iSdpFmtAttributeFields->Close();
		delete iSdpFmtAttributeFields;
		}
    delete iPlugIn;
	}

// -----------------------------------------------------------------------------
// CFCSession::Port
// 
// -----------------------------------------------------------------------------
//
TUint CFCSession::Port() const
	{
	return iPort;
	}

// -----------------------------------------------------------------------------
// CFCSession::SetPort
// 
// -----------------------------------------------------------------------------
//
void CFCSession::SetPort( const TUint aPort )
    {
    iPort = aPort;
	iPlugIn->SetLocalPort(aPort);
	iUpdateNeeded = ETrue;
    }

void CFCSession::Update( TUint32 aPort )
    {
    SetPort( aPort );
    iIsReceiver = ( iPort != KFCDefaultPort );
    }

// -----------------------------------------------------------------------------
// CFCSession::FormatAttributeFields
// Gets all SipMediaFmtAttribute params defined for the FCSession
// -----------------------------------------------------------------------------
//
RPointerArray<CSdpFmtAttributeField>& CFCSession::FormatAttributeFields()
	{
	return *iSdpFmtAttributeFields;
	}

// -----------------------------------------------------------------------------
// CFCSession::SetFormatAttributeFieldsL
// Setting all SipMediaFmtAttribute params defined for the FCSession
// -----------------------------------------------------------------------------
//	
void CFCSession::SetFormatAttributeFieldsL(
    RPointerArray<CSdpFmtAttributeField>* aAttributes )
	{
	DoSetFormatAttributeFieldsL( aAttributes );
	iUpdateNeeded = ETrue;
	}

// -----------------------------------------------------------------------------
// CFCSession::DoSetFormatAttributeFieldsL
// Setting all SipMediaFmtAttribute params defined for the FCSession
// -----------------------------------------------------------------------------
//	
void CFCSession::DoSetFormatAttributeFieldsL(
    RPointerArray<CSdpFmtAttributeField>* aAttributes )
	{
	if (iSdpFmtAttributeFields)
		{
		iSdpFmtAttributeFields->ResetAndDestroy();
		iSdpFmtAttributeFields->Close();
		delete iSdpFmtAttributeFields;	
		iSdpFmtAttributeFields = NULL;
		}
		
	if ( aAttributes )
	    {
	    iSdpFmtAttributeFields = aAttributes;    
	    }
	else
	    {
	    iSdpFmtAttributeFields = 
	        new (ELeave) RPointerArray<CSdpFmtAttributeField>(1);
		}
	}

// -----------------------------------------------------------------------------
// CFCSession::IsFmtAttributeValid
// validats all SipMediaFmtAttribute params defined for the FCSession
// -----------------------------------------------------------------------------
//	
TBool CFCSession::IsFmtAttributeValid()
	{
	TBool validate= EFalse;
	if (iSdpFmtAttributeFields)
		{
		TInt len=0;
		CSdpFmtAttributeField* fmtatt = NULL;
		for(TInt count=0; count < iSdpFmtAttributeFields->Count(); count++)
	        {
	        fmtatt = (*iSdpFmtAttributeFields)[count];
	        len = fmtatt->Value().Length();
	        if (len!=0)
	        	{
	            validate= ETrue;
	        	}
	        else
	        	{
        		validate = EFalse;
        		return validate;	
        		}
        	return validate;
        	}
		}
	return validate;
	}

// -----------------------------------------------------------------------------
// CFCSession::UpdateSDPL 
// Adds/modifies the FC media line in the offer.
// RStringPool should open before using this function
// -----------------------------------------------------------------------------
//
void CFCSession::UpdateSDPL( CSdpDocument& aSdpDocument )
    {
    __ASSERT_ALWAYS( iUpdateNeeded, User::Leave( KErrTotalLossOfPrecision ) );
    //m= application iPort udp NegotiatedPlugin()
    
    // Find the media field, and remove, if exists.
    RPointerArray< CSdpMediaField >& mediaFields = aSdpDocument.MediaFields();
    TInt ind = FindMediaField( aSdpDocument.MediaFields() );
    if ( ind != KErrNotFound )
        {
        delete mediaFields[ ind ];
        mediaFields.Remove( ind );
        }
    
    // create  and add new media field. 
	RStringF mediaType = SdpCodecStringPool::StringPoolL().StringF(
                            SdpCodecStringConstants::EMediaApplication, 
                            SdpCodecStringPool::StringTableL() );
    CleanupClosePushL( mediaType );
    
    RStringF protocol = SdpCodecStringPool::StringPoolL().StringF(
                    SdpCodecStringConstants::EProtocolUdp, 
                    SdpCodecStringPool::StringTableL() );
    CleanupClosePushL( protocol );
    
	CSdpMediaField* mediaField = CSdpMediaField::NewL( mediaType,
                                                       iPort,
                                                       protocol,
                                                       NegotiatedFCPlugIn() );
	CleanupStack::PushL( mediaField );            
    	
	if (IsFmtAttributeValid() )
    	{
    	for( TInt i = 0; i < iSdpFmtAttributeFields->Count(); i++ )
    		{
    		CSdpFmtAttributeField* newField = 
    		    ( ( *iSdpFmtAttributeFields )[i] )->CloneL();
    		CleanupStack::PushL( newField );
    		mediaField->FormatAttributeFields().AppendL( newField );
    		CleanupStack::Pop( newField );
    		}
    	}
    
    mediaFields.AppendL( mediaField);	
    
    iUpdateNeeded = EFalse; 
    
    CleanupStack::Pop( mediaField );  

    CleanupStack::PopAndDestroy( 2 ); // protocol, mediaType	
	}

// -----------------------------------------------------------------------------
// CFCSession::DecodeSDPMediaPort
// Get Port from the Sdpdoc
// -----------------------------------------------------------------------------
//
TUint CFCSession::DecodeSDPMediaPort( 
        const RPointerArray< CSdpMediaField >& aMediaFields ) const
	{
	TUint port = 0;
    
    TInt ind = FindMediaField( aMediaFields );
    
    if ( ind != KErrNotFound )
        {
        port = aMediaFields[ ind ]->Port();
        }
    
    return port;
    }

// -----------------------------------------------------------------------------
// CFCSession::DecodeConnectionAddrL
// Get Port from the Sdpdoc
// -----------------------------------------------------------------------------
//
HBufC* CFCSession::DecodeConnectionAddrL( 
                            const CSdpConnectionField* aConnectionField ) const 
	{
    HBufC* addr = NULL;
    // a connection field might not exist in session level
    // so do not leave here, if there is no c= in session level, return NULL
    if ( aConnectionField )
        {
        const TInetAddr* remoteAddr = aConnectionField->InetAddress();
        TBuf< KMaxAddressLength > addr16;
        remoteAddr->Output( addr16 );
        addr = addr16.AllocL();
        }
    return addr;
    }

// -----------------------------------------------------------------------------
// CFCSession::NegotiatedFCPlugIn
// Gets the negotiated floor control plugIn
// -----------------------------------------------------------------------------
//
const TDesC8& CFCSession::NegotiatedFCPlugIn() const
	{
	return iPlugIn->Name();
	}

// ----------------------------------------------------------------------------
// CFCPlugInEngine::StoreInfoL
// Store the information
// ----------------------------------------------------------------------------
//
void CFCSession::StoreInfoL( const CSdpDocument& aSdpDocument )
	{
	//Resolve the remote port and addr	   
	HBufC* addr= DecodeConnectionAddrL( aSdpDocument.ConnectionField() );

	RPointerArray<CSdpMediaField>& mediaDescriptions = 
	    ( const_cast< CSdpDocument* >( &aSdpDocument ) )->MediaFields();
	       
	if ( addr )
    	{
    	CleanupStack::PushL( addr );
    
	    TUint port = DecodeSDPMediaPort( mediaDescriptions );
	
    	//Set the remote address for the specific plugin ex TBCP
    	iPlugIn->SetAddressL( *addr, port );
    	CleanupStack::PopAndDestroy( addr );    
    	}
	
	//Store the fmt attributes
	RPointerArray<CSdpFmtAttributeField> *fmtFields =
		new (ELeave) RPointerArray<CSdpFmtAttributeField>(1);
		
    CleanupStack::PushL( TCleanupItem( ArrayCleanupAndDelete, fmtFields ) );
    		
	TInt ind = FindMediaField( mediaDescriptions );
	if ( ind != KErrNotFound )
	    {
	    CSdpMediaField* mediaAnnouncement = mediaDescriptions[ ind ];
	    	    
    	RPointerArray<CSdpFmtAttributeField>& attributes = 
            mediaAnnouncement->FormatAttributeFields();
        		    
        for( TInt fmtCount = 0; fmtCount < attributes.Count(); fmtCount++ )
            {
            CSdpFmtAttributeField* fmtatt = attributes[ fmtCount ];
			if ( iPlugIn->Name().Compare( fmtatt->Format() ) == 0)
		        {
		        CSdpFmtAttributeField* newField = fmtatt->CloneL();
		        CleanupStack::PushL( newField );
				fmtFields->AppendL( newField );
				CleanupStack::Pop( newField );
				}
			}
	    }
	DoSetFormatAttributeFieldsL( fmtFields );
	CleanupStack::Pop(); // cleanup item
    }

// -----------------------------------------------------------------------------
// CFCSession::CFCSession
// -----------------------------------------------------------------------------
//
void CFCSession::ReleaseSession()
	{
	iPort=0;
	//Stop the sending and reciving and socketserver. Socket is not close yet
	iPlugIn->Stop();
	}
	
// -----------------------------------------------------------------------------
// CFCSession::ConnectionReadyL
// -----------------------------------------------------------------------------
//
void CFCSession::ConnectionReadyL()
	{
	iPlugIn->ConnectL( iIsReceiver );
	}

// -----------------------------------------------------------------------------
// CFCSession::SendToNetL
// -----------------------------------------------------------------------------
//
void CFCSession::SendToNetL(HBufC8* aData)
	{
	iPlugIn->SendToNetL(aData);
	}

// -----------------------------------------------------------------------------
// CFCSession::CFCSession
// -----------------------------------------------------------------------------
//
CFCSession::CFCSession( TUint32 aPort ) : 
		iPort( aPort ),
		iUpdateNeeded( ETrue )
    {
	iIsReceiver = ( iPort != KFCDefaultPort );
	}

// -----------------------------------------------------------------------------
// CFCSession::PlugIn
// -----------------------------------------------------------------------------
//
MFCPlugIn* CFCSession::PlugIn() const
    {
    return iPlugIn;
    }

// -----------------------------------------------------------------------------
// CFCSession::IsReceiver
// -----------------------------------------------------------------------------
//
TBool CFCSession::IsReceiver()
    {
    return iIsReceiver;
    }

// -----------------------------------------------------------------------------
// CFCSession::FindMediaField
// Search is done comparing media format to plugin name
// -----------------------------------------------------------------------------
//
TInt CFCSession::FindMediaField( 
                    const RPointerArray<CSdpMediaField>& aMediaFields ) const   
    {
	TInt ind = KErrNotFound;
	for ( TInt i = 0; ind == KErrNotFound && i < aMediaFields.Count(); i++ )
	    {
	    if ( aMediaFields[ i ]->FormatList().Compare( iPlugIn->Name() ) == 0 )
	        {
	        ind = i;
	        }
	    }
	return ind;	        
    }
		    
// -----------------------------------------------------------------------------
// CFCSession::ArrayCleanup
// -----------------------------------------------------------------------------
//
void CFCSession::ArrayCleanup(TAny* aArray)
	{
    RPointerArray< CSdpFmtAttributeField >*  array = 
        reinterpret_cast< RPointerArray< CSdpFmtAttributeField >* >( aArray );
    if (array)
        {
        array->ResetAndDestroy();
        }
	}
	

// -----------------------------------------------------------------------------
// CFCSession::ArrayCleanupAndDelete
// -----------------------------------------------------------------------------
//
void CFCSession::ArrayCleanupAndDelete(TAny* aArray)
	{
    RPointerArray< CSdpFmtAttributeField >*  array = 
        reinterpret_cast< RPointerArray< CSdpFmtAttributeField >* >( aArray );
    if (array)
        {
        array->ResetAndDestroy();
        delete array;
        }
	}	

// -----------------------------------------------------------------------------
// CFCSession::UpdateNeeded
// -----------------------------------------------------------------------------
//
TBool CFCSession::UpdateNeeded()
    {
    return iUpdateNeeded;
    }
    	
//  End of File
