/*
* 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:  
*
*/





#include "mcestateconfirming.h"
#include "mcesipsession.h"
#include "mceactionset.h"
#include "mcefcactionset.h"
#include "mceclientserver.h"
#include "mcesipextensions.h"
#include "mcenatmacros.h"
#include <sipdialogassocbase.h>
#include <sipdialog.h>


// -----------------------------------------------------------------------------
// CMceStateConfirming::CMceStateConfirming
// -----------------------------------------------------------------------------
//
CMceStateConfirming::CMceStateConfirming()
    : CMceState( KMceStateConfirming )
	{
	}


// -----------------------------------------------------------------------------
// CMceStateConfirming::~CMceStateConfirming
// -----------------------------------------------------------------------------
//
CMceStateConfirming::~CMceStateConfirming()
	{
	}


// -----------------------------------------------------------------------------
// CMceStateConfirming::DoAcceptL
// -----------------------------------------------------------------------------
//
TBool CMceStateConfirming::DoAcceptL( TMceStateTransitionEvent& aEvent )
	{
	User::LeaveIfError( 	                 
       aEvent.Code() == EMceResponse ||
       aEvent.Code() == EMceProvisionalResponse ||
       aEvent.Code() == EMceRedirectionResponse ||
       aEvent.Code() == EMceErrorResponse ||
       aEvent.Code() == EMceItcCancel ||
       aEvent.Code() == EMceMediaUpdated ||      
       aEvent.Code() == EMceItcEnable ||
       aEvent.Code() == EMceItcDisable ||
       IsExtensionRequestEvent( aEvent )
       
       ? KErrNone : KErrTotalLossOfPrecision );
    
	return ETrue;
	}

// -----------------------------------------------------------------------------
// CMceStateConfirming::EntryL
// -----------------------------------------------------------------------------
//
void CMceStateConfirming::EntryL( TMceStateTransitionEvent& aEvent )
	{

	if ( IsExtensionRequestEvent( aEvent ))
		{
		HandleExtensionRequestEventL( aEvent );	
		}
	else
		{
		CMceSipSession& session = aEvent.Session();
	    switch ( aEvent.Code() )
	        {
	        case EMceResponse:
	            {
	            EntryResponseL( aEvent );
	            break;
	            }
	        case EMceProvisionalResponse:
	            {
	            EntryProvisionalResponseL( aEvent );
	            break;
	            }
	        case EMceRedirectionResponse:
	        case EMceErrorResponse:
	            {
	            EntryErrorResponseL( aEvent );
	            break;
	            }
	        case EMceItcCancel:
	            {
	            EntryCancelL( aEvent );
	            break;
	            }
	        case EMceMediaUpdated:
	            {
	            EntryMediaUpdatedL( aEvent );
	            break;
	            }
	        case EMceItcEnable:
	        case EMceItcDisable:
	            {
	            session.Actions().ControlMediaL( aEvent.ParamIDs(), 
	                                             (TMceItcFunctions)aEvent.Code() );
	            break;
	            }  
	        default:
	            {
	            // NOP
	            break;
	            }
	        }
		}
	}

// -----------------------------------------------------------------------------
// CMceStateConfirming::ExitL
// -----------------------------------------------------------------------------
//
void CMceStateConfirming::ExitL( TMceStateTransitionEvent& aEvent )
	{
	
	if ( IsExtensionRequestEvent( aEvent ))
		{
		//Do Nothing;
		}

	else
		{
	    CMceSipSession& session = aEvent.Session();
	    switch ( aEvent.Code() )
	        {
	        case EMceMediaUpdated:
	            {
	            ExitMediaUpdatedL( aEvent );
	            break;
	            }
	        case EMceItcCancel:
	            {
	            session.Actions().StateChanged( KMceStateCanceled );
	            session.Actions().ClientStateChanged( aEvent.ParamIDs(), 
	                                                  CMceSession::ECancelling );
	            break;
	            }
	        case EMceErrorResponse:
	        case EMceRedirectionResponse:
	            {
	            // session canceled
	            session.Actions().StateChanged( KMceStateCanceled );
	            session.Actions().ClientStateChangedL( CMceSession::ECancelling,
	                                                   session.Response() );
	                                                          
	            break;                                                   
	            }
	        default:
	            {
	            break;
	            }
	        }
		}
	}

// -----------------------------------------------------------------------------
// CMceStateConfirming::EntryResponseL
// -----------------------------------------------------------------------------
//
void CMceStateConfirming::EntryResponseL( TMceStateTransitionEvent& aEvent )
    {
    CMceSipSession& session = aEvent.Session();
    RStringF trx = session.Response().Type();
    
    TMceReturnStatus status = KMceReady;
    CSIPClientTransaction& response = session.Response(); 
    TBool hasContent = MceSip::HasContent( response );
        
    if ( trx == SIPStrings::StringF( SipStrConsts::EInvite ) )
        {
        // 2xx to INVITE already, send ACK
        session.Actions().SendACKL( response );
        
        if ( hasContent )
            {
            // since the answer is already received, 
            // seize resending UPDATE/PRACK
            TBool interrupted = session.Actions().InterruptConfirming();
            User::LeaveIfError( interrupted ? 
                KErrNone : KErrTotalLossOfPrecision );
            
            // there is SDP, treat it as answer
            User::LeaveIfError( session.Actions().CreateSDP( response ) );
            session.Actions().DecodeL();
            status = session.Actions().UpdateL();
            if ( status == KMceReady )
                {
                if ( MCE_NEED_TO_SEND( session, NULL ) )
                    {
                    // send re-INVITE
                    session.Actions().EncodeL();
                    session.Actions().SendInviteL();
                    }
                aEvent.Code() = EMceMediaUpdated;
                }
            else if ( MCE_IS_ERROR( status ) )
                {
                User::Leave( status );
                }
            else // KMceAsync
                {
                // NOP
                }                
            }
        else
            {
            // TODO: IF ( answerNeeded ) 
            //       THEN wait until the PRACK/UPDATE generates a response.
            //       ELSE consider session established
            }
        }
    else if ( trx == SIPStrings::StringF( SipStrConsts::EUpdate ) ||
              trx == SIPStrings::StringF( SipStrConsts::EPrack ) )
        {
        // 2xx to PRACK/UPDATE
        
        if ( hasContent )
            {
            NAT_WAIT_NO_EXEC( session, (status = session.Actions().CreateSDP( response )));
            if ( !MCE_IS_ERROR( status ) && MCE_NEED_TO_SEND( session, NULL ) )
                {
                if ( session.ActiveBody().SecureSession() )
                	{
                	session.ActiveBody().SecureSession()->iLSReadyToBind = ETrue;
                	}
                status = session.Actions().DecodeL();
                if ( status == KMceSipPreconditionFailure )
                	{
                	User::Leave( status );
                	}
                else
                	{
                	status = session.Actions().UpdateL();
                	}
                }
            }
        
        if ( status == KMceReady )
            {
            if ( ( MCE_NEED_TO_SEND( session, NULL ) || 
               ( trx == SIPStrings::StringF( SipStrConsts::EPrack ) &&
                 session.Extensions().RemoteIMSRel5() )  )&&
                 session.ActiveBody().Modifier( KMceSecPreconditions )!=
                 	 KMcePreconditionsE2ESupported )
                 
                {
                
                if (!hasContent)
                    {
                        // Do nothing.
                    }
                else
                    {
                    status = session.Actions().UpdateL();
                    __ASSERT_ALWAYS( status == KMceReady, User::Leave( KErrArgument ) );
                    if ( session.ActiveBody().SecureSession() )
                    	{
                    	session.ActiveBody().SecureSession()->iLSReadyToBind = ETrue;
                    	}
                    NAT_WAIT_NO_EXEC( session, session.Actions().EncodeL() );
                    session.Actions().SendUpdateRequestL();
                    }
                }
            aEvent.Code() = EMceMediaUpdated;
            }
        else if ( MCE_IS_ERROR( status ) )
            {
            User::Leave( status );
            }
        else // KMceAsync
            {
            // NOP
            }
        aEvent.ParamStatus() = status;
        }
    else
        {
        User::Leave( KErrTotalLossOfPrecision );
        }
    }

// -----------------------------------------------------------------------------
// CMceStateConfirming::EntryProvisionalResponseL
// -----------------------------------------------------------------------------
//
void CMceStateConfirming::EntryProvisionalResponseL( 
                                        TMceStateTransitionEvent& /*aEvent*/ )
    {
    // IF retransmission THEN ignore
    // ELSE IF sent reliably THEN send PRACK
    // 
    // IF 180 ringing THEN give to application
    // TBD: What if 180 Ringing comes here?
    }

// -----------------------------------------------------------------------------
// CMceStateConfirming::EntryErrorResponseL
// -----------------------------------------------------------------------------
//    
void CMceStateConfirming::EntryErrorResponseL( 
                                        TMceStateTransitionEvent& aEvent )
    {
    CMceSipSession& session = aEvent.Session();
    RStringF trx = session.Response().Type();
    TUint code = MceSip::ResponseCode( session.Response() );
    
    if ( trx == SIPStrings::StringF( SipStrConsts::EInvite ) )
        {
        if ( session.SubState() == CMceSipSession::EOffering )
            {
            session.Actions().StateChanged( KMceStateTerminated );
            session.Actions().ClientStateChangedL( CMceSession::ETerminated,
                                                   session.Response() );
            
            }
          
        else if ( session.SubState() == CMceSipSession::EUpdating ||
              session.SubState() == CMceSipSession::ERefreshing )
        	{
      		if ( code == KMceSipCallOrTransactionDoesNotExist ||
                 code == KMceSipRequestTimeout ) 
	            { 
    	        session.Actions().UpdateFailed();
	            session.Actions().SendBYEL();
                session.Actions().StopMedia();
                session.FCActions().ReleaseFC();
                session.Actions().StateChanged( KMceStateTerminated );
            	session.Actions().ClientStateChangedL( CMceSession::ETerminated,
                                               session.Response() );
                }
         	else
                {
    	        session.Actions().UpdateFailed(); 
  	        	session.Actions().StateChanged( KMceStateEstablished );
				session.Actions().ClientStateChangedL( CMceSession::EEstablished, 
                                               *session.Body(),
                                               session.Response(),
                                               KErrCancel );
                }
        	}
                
        }
    
    else if ( trx == SIPStrings::StringF( SipStrConsts::EUpdate ) ||
              trx == SIPStrings::StringF( SipStrConsts::EPrack ) )
        {
        EntryCancelL( aEvent );
        }
    else
        {
        User::Leave( KErrTotalLossOfPrecision );
        }
    }
    
// -----------------------------------------------------------------------------
// CMceStateConfirming::EntryCancelL
// -----------------------------------------------------------------------------
//    
void CMceStateConfirming::EntryCancelL( TMceStateTransitionEvent& aEvent )
    {
    CMceSipSession& session = aEvent.Session();
    CMceSipSession::TSubState subState = session.SubState();

    //(try) send CANCEL
    session.Actions().SendCancelL();

    if ( subState == CMceSipSession::EOffering )
        {
        session.Actions().StopMedia();
        session.FCActions().ReleaseFC();
        }
    else if ( subState == CMceSipSession::EUpdating )
        {
        session.Actions().UpdateFailed();
        }    
    }

// -----------------------------------------------------------------------------
// CMceStateConfirming::EntryMediaUpdatedL
// -----------------------------------------------------------------------------
//    
void CMceStateConfirming::EntryMediaUpdatedL( TMceStateTransitionEvent& aEvent )
    {
    CMceSipSession& session = aEvent.Session();
    
    if ( MCE_NEED_TO_SEND( session, NULL ) )
        {
        NAT_WAIT_NO_EXEC( session, session.Actions().EncodeL() );
        
        if ( session.Dialog()->Dialog().State() == CSIPDialog::EEarly )
            {
            session.Actions().SendUpdateRequestL();    
            }
        else
            {
            session.Actions().SendInviteL();
            }
        }    
    }

// -----------------------------------------------------------------------------
// CMceStateConfirming::ExitMediaUpdatedL
// -----------------------------------------------------------------------------
//    
void CMceStateConfirming::ExitMediaUpdatedL( TMceStateTransitionEvent& aEvent )
    {
    CMceSipSession& session = aEvent.Session();
    CSIPClientTransaction* update = session.PendingTransaction(
        SIPStrings::StringF( SipStrConsts::EUpdate ) );
    if ( update && !MceSip::TrxCompleted( *update ) )
        {
        // just sent UPDATE
        session.Actions().StateChanged( KMceStateConfirming );
        }
    else
        {
        CSIPClientTransaction* invite = session.PendingTransaction( 
                    SIPStrings::StringF( SipStrConsts::EInvite ) );
        User::LeaveIfError( invite ? KErrNone : 
            KErrTotalLossOfPrecision );

        if ( invite->StateL() == CSIPTransactionBase::ETerminated )
            {
            // Just go to established state
            session.Actions().ClientStateChangedL( 
                                    CMceSession::EEstablished,
                                    *session.Body(),
                                    session.Response() );
            session.Actions().StateChanged( KMceStateEstablished );
            }
        else
            {
            session.Actions().StateChanged( KMceStateOffering );
            }
        }    
    }
    
// End of file
