/*
* Copyright (c) 2002 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of the License "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: 
*      Implementation of class CHttpWapSession.   
*      
*
*/


// INCLUDE FILES

#include <HttpFilterCommonStringsExt.h>
#include "HttpWapSession.h"
#include "CodError.h"
#include "CodLogger.h"
#include "CodPanic.h"

/// WSP protocol name.
_LIT8( KCodWspProtocol, "WSP/WSP" );
/// Default WAP server port.
const TInt KCodWspRemotePort = 9201;

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

// ---------------------------------------------------------
// CHttpWapSession::NewL()
// ---------------------------------------------------------
//
CHttpWapSession* CHttpWapSession::NewL( const TDesC8& aGateway )
    {
    CHttpWapSession* sess = new( ELeave ) CHttpWapSession();
    CleanupStack::PushL( sess );
    sess->ConstructL( aGateway );
    CleanupStack::Pop( sess );
    return sess;
    }

// ---------------------------------------------------------
// CHttpWapSession::~CHttpWapSession()
// ---------------------------------------------------------
//
CHttpWapSession::~CHttpWapSession()
    {
    CLOG(( EWapConn, 2, _L("-> CHttpWapSession::~CHttpWapSession") ));
    Disconnect();
    if ( iGatewayOpen )
        {
        iGateway.Close();
        }
    iSess.Close();
    delete iWait;
    CLOG(( EWapConn, 2, _L("<- CHttpWapSession::~CHttpWapSession") ));
    }

// ---------------------------------------------------------
// CHttpWapSession::ConnectL()
// ---------------------------------------------------------
//
void CHttpWapSession::ConnectL( TRequestStatus* aStatus )
    {
    CLOG(( EWapConn, 2, _L("-> CHttpWapSession::ConnectL") ));
    CLOG(( EWapConn, 3, _L8("  iGateway <%S> port(%d)"),\
        &(iGateway.DesC()), KCodWspRemotePort ));

    // Misuse asserts.
    __ASSERT_ALWAYS( aStatus, CodPanic( ECodInvalidArguments ) );
    __ASSERT_ALWAYS( iState == EInit, CodPanic( ECodOffState ) );
    // Internal asserts.
    __ASSERT_DEBUG( !iParentStatus, CodPanic( ECodInternal ) );

    RHTTPConnectionInfo connInfo = iSess.ConnectionInfo();
    connInfo.SetPropertyL
        ( StringF( HTTP::EWspProxyAddress ), THTTPHdrVal( iGateway ) );
    connInfo.SetPropertyL
        ( StringF( HTTP::EWspRemotePort ), THTTPHdrVal( KCodWspRemotePort ) );
    // Connect to WAP gateway.
    iSess.SetSessionEventCallback( this );
    iSess.ConnectL();

    iState = EConnecting;

    iParentStatus = aStatus;
    *iParentStatus = KRequestPending;

    CLOG(( EWapConn, 2, _L("<- CHttpWapSession::ConnectL") ));
    }

// ---------------------------------------------------------
// CHttpWapSession::Disconnect()
// ---------------------------------------------------------
//
void CHttpWapSession::Disconnect()
    {
    CLOG(( EWapConn, 2, _L("-> CHttpWapSession::Disconnect iState(%d)"), \
        iState ));
    switch ( iState )
        {
        case EConnecting:
        case EConnected:
            {
            TRAPD( err, iSess.DisconnectL() );
            if ( err )
                {
                // Nothing we can do about this failure!
                CLOG(( EConn, 3, _L("  failed(%d)"), err ));
                }
            else
                {
                iState = EDisconnecting;
                CLOG(( EConn, 3, _L("  starting wait") ));
                iWait->Start();
                }
            break;
            }

        case EInit:
        case EDisconnecting:
        default:
            {
            CLOG(( EConn, 3, _L("  nothing to do") ));
            // EInit state: no need to do anything.
            // EDisconnecting: we can't do anything.
            break;
            }
        }
    CLOG(( EWapConn, 2, _L("<- CHttpWapSession::Disconnect") ));
    }

// ---------------------------------------------------------
// CHttpWapSession::CHttpWapSession()
// ---------------------------------------------------------
//
CHttpWapSession::CHttpWapSession()
: CHttpSessionBase(),
  iState( EInit ),
  iGatewayOpen( EFalse )
    {
    CLOG(( EWapConn, 2, _L("CHttpWapSession::CHttpWapSession") ));
    }

// ---------------------------------------------------------
// CHttpWapSession::ConstructL()
// ---------------------------------------------------------
//
void CHttpWapSession::ConstructL( const TDesC8& aGateway ) 
    {
    __ASSERT_ALWAYS( aGateway.Length(), CodPanic(  ECodInvalidArguments ) );
    iSess.OpenL( KCodWspProtocol );
    iSess.StringPool().OpenL( HttpFilterCommonStringsExt::GetTable() );
    iGateway = iSess.StringPool().OpenFStringL( aGateway );
    // Track whether open - cannot close unopened RStringF.
    iGatewayOpen = ETrue;
    iWait = new (ELeave) CActiveSchedulerWait;
    }

// ---------------------------------------------------------
// CHttpWapSession::MHFSessionRunL()
// ---------------------------------------------------------
//
void CHttpWapSession::MHFSessionRunL( const THTTPSessionEvent& aEvent )
    {
    CLOG(( EWapConn, 0, _L("-> CHttpWapSession::MHFSessionRunL event(%d)"), \
                                                            aEvent.iStatus ));

    switch ( aEvent.iStatus )
        {
        case THTTPSessionEvent::EConnectedOK:
        case THTTPSessionEvent::EConnectedWithReducedCapabilities:
            {
            CLOG(( EWapConn, 3, _L("  EConnected...") ));
            if ( iState == EConnecting )
                {
                // Connecting: we are done.
                iState = EConnected;
                Done( KErrNone );
                }
            else if ( iState == EDisconnecting )
                {
                // Connecting was interrupted with a Disconnect call but it
                // seems we have already connected by that time. Now we are
                // not Done() yet: wait more for the disconnect to finish.
                CLOG(( EWapConn, 3, \
                    _L("  late connect event, keep waiting for disconnect") ));
                iState = EConnected;
                }
            else
                {
                // Unexpected state for these events.
                CLOG(( EWapConn, 0, \
                    _L("  connect event in unexpected state") ));
                CodPanic( ECodOffState );
                }
            break;
            }

        case THTTPSessionEvent::EDisconnected:
            {
            CLOG(( EWapConn, 3, _L("  EDisconnected") ));
            iState = EInit;
            Done( KErrCodWapConnectionDropped );
            break;
            }

        case THTTPSessionEvent::EConnectionTimedOut:
            {
            CLOG(( EWapConn, 3, _L("  EConnectionTimedOut") ));
            iState = EInit;
            Done( KErrCodHttpTimedOut );
            break;
            }

        default:
            {
            if( aEvent.iStatus < 0 )
                {
                // Negative value indicates error.
                iState = EInit;
                Done( KErrCodWapConnectionDropped );
                }
            break;
            }
        }
    CLOG(( EWapConn, 0, _L("<- CHttpWapSession::MHFSessionRunL") ));
    }

// ---------------------------------------------------------
// CHttpWapSession::MHFSessionRunError()
// ---------------------------------------------------------
//
TInt CHttpWapSession::MHFSessionRunError
( TInt LOG_ONLY( aError ), const THTTPSessionEvent& /*aEvent*/ )
    {
    CLOG(( EWapConn, 2, \
        _L("CHttpWapSession::MHFSessionRunError (%d)"), aError ));
    // This method should never be called - MHFSessionRunL does not leave.
    CodPanic( ECodInternal );
    return KErrNone;
    }

// ---------------------------------------------------------
// CHttpWapSession::Done()
// ---------------------------------------------------------
//
void CHttpWapSession::Done( TInt aResult )
    {
    CLOG(( EConn, 2, _L("CHttpWapSession::Done aResult(%d)"), aResult ));
    if ( iWait->IsStarted() )
        {
        // This must be Disconnect: we are waiting for it.
        CLOG(( EConn, 3, _L("  stopping wait") ));
        iWait->AsyncStop();
        }
    if ( iParentStatus )
        {
        // This must be ConnectL: parent is waiting for it.
        CLOG(( EConn, 3, _L("  completing parent") ));
        User::RequestComplete( iParentStatus, aResult );
        iParentStatus = NULL;
        }
    }
