/*
* Copyright (c) 2006 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 <badesca.h>
#include <s32mem.h>

#include "ncdloadrootnodeoperationimpl.h"
#include "ncdoperationfunctionids.h"
#include "catalogsbasemessage.h"
#include "catalogshttpsession.h"
#include "catalogshttpoperation.h"
#include "catalogshttpconfig.h"
#include "catalogsbigdes.h"
#include "catalogsaccesspointmanagerimpl.h"
#include "ncdrequestgenerator.h"

#include "ncdrequestbase.h"
#include "ncdrequestbrowsesearch.h"
#include "ncdrequestconfiguration.h"
#include "ncd_pp_itemref.h"
#include "ncd_pp_folderref.h"
#include "ncd_pp_dataentity.h"
#include "ncd_cp_query.h"
#include "ncd_cp_queryelement.h"
#include "ncd_cp_queryoption.h"

#include "ncdprotocolutils.h"
#include "ncdprotocol.h"
#include "ncdprotocolimpl.h"
#include "ncdparser.h"
#include "ncdnodemanager.h"
#include "ncdproviderdefines.h"
#include "ncdnodeidentifier.h"
#include "ncdnodeclassids.h"
#include "ncdnodefolder.h"
#include "ncdrootnode.h"
#include "ncdbundlefolder.h"
#include "ncdloadnodeoperationimpl.h"
#include "ncd_cp_detail.h"
#include "ncd_cp_clientconfiguration.h"
#include "ncd_cp_error.h"
#include "catalogscontext.h"
#include "ncd_cp_serverdetails.h"
#include "ncdqueryimpl.h"
#include "ncdnodelink.h"
#include "ncd_cp_queryresponseimpl.h"
#include "catalogsutils.h"
#include "ncderrors.h"
#include "ncdconfigurationmanager.h"
#include "ncdoperationremovehandler.h"
#include "ncdnodemetadataimpl.h"
#include "ncdnodeiconimpl.h"
#include "ncdsessionhandler.h"
#include "ncd_pp_error.h"
#include "ncdconfigurationkeys.h"
#include "ncdutils.h"
#include "ncdnodeidentifiereditor.h"
#include "ncdnodeidentifier.h"
#include "ncdchildentity.h"
#include "ncdprotocolstrings.h"
#include "ncdnodeseeninfo.h"
#include "ncdchildentitymap.h"
#include "ncdproviderutils.h"
#include "ncdhttputils.h"
#include "ncdgeneralmanager.h"

#include "catalogsdebug.h"

// ---------------------------------------------------------------------------
// ?description_if_needed
// ---------------------------------------------------------------------------
//
CNcdLoadRootNodeOperation* CNcdLoadRootNodeOperation::NewL(
    TInt aClientUid,
    CNcdGeneralManager& aGeneralManager,
    MCatalogsHttpSession& aHttpSession,
    MNcdOperationRemoveHandler* aRemoveHandler,
    MCatalogsSession& aSession )
    {
    CNcdLoadRootNodeOperation* self = CNcdLoadRootNodeOperation::NewLC(
        aClientUid,
        aGeneralManager,
        aHttpSession,
        aRemoveHandler,
        aSession );
    CleanupStack::Pop( self );
    return self;
    }


// ---------------------------------------------------------------------------
// ?description_if_needed
// ---------------------------------------------------------------------------
//
CNcdLoadRootNodeOperation* CNcdLoadRootNodeOperation::NewLC(
    TInt aClientUid,
    CNcdGeneralManager& aGeneralManager,
    MCatalogsHttpSession& aHttpSession,
    MNcdOperationRemoveHandler* aRemoveHandler,
    MCatalogsSession& aSession )
    {
    CNcdLoadRootNodeOperation* self =
        new( ELeave ) CNcdLoadRootNodeOperation( 
            aClientUid, 
            aGeneralManager,
            aHttpSession,
            aRemoveHandler, 
            aSession );
    CleanupClosePushL( *self );
    self->ConstructL();
    return self;
    }

// ---------------------------------------------------------------------------
// ?description_if_needed
// ---------------------------------------------------------------------------
//
CNcdLoadRootNodeOperation::~CNcdLoadRootNodeOperation()
    {
    DLTRACEIN((""));
    DASSERT( !iNodeDbLocked );
    iConfigManager.RemoveObserver( *this );
    
    iLoadedNodes.ResetAndDestroy();
    
    DLTRACE(("Delete id, buffer"));
    delete iRootNodeIdentifier;
    
    DLTRACE(("Delete parser"));
    delete iParser;
    if ( iTransaction )
        {
        DLTRACE(("Releasing transaction"));
        iTransaction->Release();
        }
    DLTRACE(("Delete loaded nodes"));
    iLoadedNodes.ResetAndDestroy();
        
    DLTRACE(("Closing suboperations"));
    // Close operations
    for ( TInt i = 0; i < iSubOps.Count(); ++i )
        {
        iSubOps[i]->Close();        
        }
    DLTRACE(("Suboperations closed"));
    iSubOps.Reset();
    iFailedSubOps.Reset();
    iCompletedSubOps.Reset();
    
    DLTRACE(("Deleting content sources"));
    delete iContentSourceMap;
    
    DLTRACE(("Delete conf response buffer"));
    delete iConfigResponseBuf;
    
    if( iConfQuery )
        {
        iConfQuery->InternalRelease();
        }
    
    iSubOpQuerys.Close();
    
    delete iServerUri;
    
    iChildEntityMaps.ResetAndDestroy();
    
    DLTRACEOUT((""));
    }

const CNcdNodeIdentifier& CNcdLoadRootNodeOperation::NodeIdentifier() const
    {
    return *iRootNodeIdentifier;
    }

// ---------------------------------------------------------------------------
// ?implementation_description
// ---------------------------------------------------------------------------
//
void CNcdLoadRootNodeOperation::HandleCancelMessage( MCatalogsBaseMessage* aMessage ) 
    {
    DLTRACEIN((""));
    Cancel();
    CNcdBaseOperation::HandleCancelMessage( aMessage );
    }
    
// ---------------------------------------------------------------------------
// ?implementation_description
// ---------------------------------------------------------------------------
//
void CNcdLoadRootNodeOperation::Cancel()
    {
    DLTRACEIN( ( "" ) );
    if ( iTransaction )
        {
        iTransaction->Cancel();        
        iTransaction = NULL;
        }

    if ( iParser )
        {
        iParser->CancelParsing();
        }    

    for ( TInt i = 0 ; i < iSubOps.Count() ; i++ )
        {
        iSubOps[i]->Cancel();
        iSubOps[i]->Close();
        }
    iSubOps.Reset();
    if ( iNodeDbLocked ) 
        {        
        iNodeManager->UnlockNodeDb( TUid::Uid( iClientUid ) );
        iNodeDbLocked = EFalse;
        TRAP_IGNORE( iNodeManager->RevertNodeCacheL( *iRootNodeIdentifier ) );
        }
    }

// ---------------------------------------------------------------------------
// ?implementation_description
// ---------------------------------------------------------------------------
//
void CNcdLoadRootNodeOperation::HandleHttpEventL( 
        MCatalogsHttpOperation& aOperation, 
        TCatalogsHttpEvent aEvent )
    {
    DLTRACEIN((""));
    DASSERT( &aOperation == iTransaction );
    DASSERT( aOperation.OperationType() == ECatalogsHttpTransaction );

    TCatalogsTransportProgress progress( iTransaction->Progress() );
    
    // Are state and id needed?
    iProgress = TNcdSendableProgress( iRootNodeState,
        iTransaction->OperationId().Id(), progress.iProgress,
        progress.iMaxProgress );

    switch( aEvent.iOperationState ) 
        {
        // Handle completed operation
        case ECatalogsHttpOpCompleted:
            {
            
            iTransaction->Release();
            iTransaction = NULL;
            // Inform parser that no more data will be sent
            iParser->EndL();
            break;
            }     
               
        // Handle operation in progress
        case ECatalogsHttpOpInProgress:
            {
            if( aEvent.iProgressState == ECatalogsHttpResponseBodyReceived )
                {
                // If config response, append the contents to the buffer.
                if ( iRootNodeState == EReceiveConf ) 
                    {
                    iConfigResponseBuf->InsertL(
                        iConfigResponseBuf->Size(), aOperation.Body() );                        
                    }               

                // send received data to parser
                iParser->ParseL( aOperation.Body() );
                }
            break;
            }
                    
        default:
            {
            break;
            }
        }
    }
    
    
TBool CNcdLoadRootNodeOperation::HandleHttpError( 
    MCatalogsHttpOperation& aOperation, 
    TCatalogsHttpError aError )    
    {
    DLTRACEIN(("Error type: %d, code: %d", aError.iType, aError.iError ));    
    DASSERT( &aOperation == iTransaction );
    
    aOperation.Release();
    iTransaction = NULL;

    if ( iMasterServerRedirectionState == ERedirecting ) 
        {
        // Return back to original master server uri.
        iConfigManager.RemoveObserver( *this );
        TRAPD(err, iConfigManager.ResetMasterServerAddressL(
            iPendingMessage->Session().Context() ));
        if( err != KErrNone )
            {
            iError = err;
            iRootNodeState = EFailed;
            }
        else
            {
            iMasterServerRedirectionState = EReverted;
            iRootNodeState = EConfRequest;
            }
        }
    else
        {
        iError = aError.iError;
        iRootNodeState = EFailed;
        }
    RunOperation();
    return ETrue;
    }

void CNcdLoadRootNodeOperation::ParseError( TInt aErrorCode )
    {
    DLTRACEIN(("error:%d", aErrorCode ));
    
    // Handle error only if not handling an error already
    // (cancellation of parsing may cause an unnecessary call to this function).
    if ( iError == KErrNone )
        {
        if ( iMasterServerRedirectionState == ERedirecting ) 
            {
            // Return back to original master server uri.
            iConfigManager.RemoveObserver( *this );
            TRAPD(err, iConfigManager.ResetMasterServerAddressL(
                iPendingMessage->Session().Context() ));
            if( err != KErrNone )
                {
                iError = err;
                iRootNodeState = EFailed;
                }
            else
                {
                iMasterServerRedirectionState = EReverted;
                iRootNodeState = EConfRequest;
                }
            }
        else 
            {            
            iRootNodeState = EFailed;
            iError = aErrorCode;
            }
            
        if ( iTransaction )
            {
            iTransaction->Cancel();
            iTransaction = NULL;
            }
        if ( iParser )
            {
            iParser->CancelParsing();
            }
        
        RunOperation();
        }
    }

// ---------------------------------------------------------------------------
// ?implementation_description
// ---------------------------------------------------------------------------
//
void CNcdLoadRootNodeOperation::ParseCompleteL( TInt aError )
    {
    DLTRACEIN((_L("error:%d"), aError ));
    
    if ( iParser )
        {
        delete iParser;
        iParser = NULL;
        }
    if ( aError != KErrNone )
        {
        DLTRACE(("Parsing error, stop operation!"))
        iError = aError;
        iRootNodeState = EFailed;
        RunOperation();
        }
    else
        {
        DASSERT( iRootNodeState == EReceiveConf || iRootNodeState == EConfRequest );
        if ( iConfQuery )
            {
            DLTRACE(("Query received, let base op handle it"));
            iRootNodeState = EConfQuery;
            // let base op handle the query
            TRAPD( err, CNcdBaseOperation::QueryReceivedL( iConfQuery ) );
            if ( err != KErrNone ) 
                {
                iError = err;
                iRootNodeState = EFailed;
                RunOperation();
                }
            }
        else if ( iRootNodeState == EConfRequest ) 
            {
            DASSERT( iMasterServerRedirectionState == ERedirecting );
            RunOperation();
            }
        else if ( iContentSourceMap->ContentSourceCount() < 1 &&
                  iContentSourceMap->BundleFolderCount() < 1 )
            {
            iError = KNcdErrorNoContentSources;
            iRootNodeState = EFailed;
            DLINFO(("No content sources received, stop operation!"))
            RunOperation();
            }
        else
            {            
            iRootNodeState = EBrowseRequest;
            RunOperation();
            }
        }
    DLTRACEOUT((""));
    }

void CNcdLoadRootNodeOperation::ConfigurationBeginL( const TDesC& aVersion, 
                                                     TInt aExpirationDelta )
    {
    DLTRACEIN((""));
    // set expiration delta for root node
    // No need to set metadata value for root, because it does not have one.
    iNodeManager->RootNodeL( iRootNodeIdentifier->ClientUid() ).
        CreateAndSetLinkL().SetValidUntilDelta( aExpirationDelta );
	// Pass to default observer.
	DASSERT( iDefaultConfigurationProtocolObserver != NULL );
    iDefaultConfigurationProtocolObserver->ConfigurationBeginL( aVersion, aExpirationDelta );
    
    DLTRACEOUT((""));
    }
    
void CNcdLoadRootNodeOperation::ConfigurationQueryL(
    MNcdConfigurationProtocolQuery* aQuery )
    {
    DLTRACEIN((""));
    DASSERT( !iConfQuery );
    CleanupDeletePushL( aQuery );
    // create a query object form the protocol entity
    iConfQuery = CNcdQuery::NewL( *aQuery, IsHttpsUri( *iServerUri ) );
    CleanupStack::Pop( aQuery );    
    
	// Pass ownership to default observer.
	DASSERT( iDefaultConfigurationProtocolObserver != NULL );
    iDefaultConfigurationProtocolObserver->ConfigurationQueryL( aQuery );
    DLTRACEOUT((""));
    }

void CNcdLoadRootNodeOperation::ClientConfigurationL(
    MNcdConfigurationProtocolClientConfiguration* aConfiguration )
    {
    DLTRACEIN((""));
        
    CleanupDeletePushL( aConfiguration );
    if ( !iNodeDbLocked )
        {        
        iNodeManager->LockNodeDbL( TUid::Uid( iClientUid ) );        
        iNodeDbLocked = ETrue;
        }
    DLINFO(("detail count:%d", aConfiguration->DetailCount()));

    // Parse access point data from client configuration response.
    iAccessPointManager.ParseAccessPointDataFromClientConfL(
        *aConfiguration, iPendingMessage->Session().Context().FamilyId() );
        
    iBundleInsertIndex = 0;
    
    for( TInt i = 0 ; i < aConfiguration->DetailCount() ; i++ )
        {
        const MNcdConfigurationProtocolDetail& detail = aConfiguration->DetailL( i );
        DLINFO((_L("detail: id=%S value=%S"), &detail.Id(), &detail.Value() ));
        
        if ( detail.Id() != KContentSources )
            {
            continue;
            }
        const RPointerArray<MNcdConfigurationProtocolDetail>& csDetails =
            detail.Details();
        DLINFO(("csDetails count=%d", csDetails.Count()));
        for ( TInt j = 0 ; j < csDetails.Count() ; j++ )
            {            
            MNcdConfigurationProtocolDetail* csDetail = csDetails[j];
            DLINFO((_L("csDetail: id=%S value=%S"), &csDetail->Id(), &csDetail->Value() ));
            if ( csDetail->Id() != KNameSpace )
                {
                continue;
                }
            
            if ( csDetail->GroupId() == KCatalogBundle ) 
                {
                ParseCatalogBundleL( *csDetail );
                continue;
                }
            
            // create a content source
            // The parameter is the parent node identifier.
            CNcdContentSource* contentSource =
                CNcdContentSource::NewLC( *iRootNodeIdentifier );
            contentSource->SetNameSpaceL( csDetail->Value() );
            
            // get details
            const RPointerArray<MNcdConfigurationProtocolDetail>& nsDetails =
                csDetail->Details();
            DLINFO(("nsDetails count=%d", nsDetails.Count()));
            for ( TInt k = 0 ; k < nsDetails.Count() ; k++ )
                {
                MNcdConfigurationProtocolDetail* nsDetail = nsDetails[k];
                DLINFO((_L("nsDetail: id=%S value=%S"), &nsDetail->Id(), &nsDetail->Value() ));
                if ( nsDetail->Id() == KUri )
                    {
                    contentSource->SetUriL( nsDetail->Value() );
                    }
                }
                
            // get contents
            const RPointerArray<MNcdConfigurationProtocolContent>& nsContents =
                csDetail->Contents();
            DLINFO(("nsContents count=%d", nsContents.Count()));
            for ( TInt l = 0 ; l < nsContents.Count() ; l++ )
                {
                MNcdConfigurationProtocolContent* nsContent = nsContents[l];
                DLINFO((_L("nsContent: key=%S value=%S"), &nsContent->Key(), &nsContent->Value() ));
                if ( nsContent->Key() == KProvider )
                    {
                    contentSource->SetProviderL( nsContent->Value() );
                    }
                else if ( nsContent->Key() == KId )
                    {
                    // Notice that the the content source ids should be node identifiers.
                    // Not the actual metadata identifiers. So, append the root info
                    // in front of the value gotten from the server.
                    CNcdNodeIdentifier* contentIdentifier =
                        CNcdNodeIdentifier::NewLC( contentSource->NameSpace(),
                                                   nsContent->Value(),
                                                   iRootNodeIdentifier->ClientUid() );                        
                    CNcdNodeIdentifier* actualNodeIdentifier =
                        NcdNodeIdentifierEditor::CreateNodeIdentifierLC( *iRootNodeIdentifier, 
                                                                         *contentIdentifier );
                    DLINFO((_L("Actual nodeidentifier for content source: %S"), 
                            &actualNodeIdentifier->NodeId()));
                    contentSource->SetNodeIdL( actualNodeIdentifier->NodeId() );
                    CleanupStack::PopAndDestroy( actualNodeIdentifier );
                    CleanupStack::PopAndDestroy( contentIdentifier );
                    }
                else if ( nsContent->Key() == KAlwaysVisible ) 
                    {
                    TBool visible = EFalse;
                    NcdProtocolUtils::DesToBool( visible, nsContent->Value() );
                    contentSource->SetAlwaysVisible( visible );
                    }
                else if ( nsContent->Key() == KTransparent ) 
                    {
                    TBool transparent = EFalse;
                    NcdProtocolUtils::DesToBool( transparent, nsContent->Value() );
                    contentSource->SetTransparent( transparent );
                    }
                }
            
            DLINFO((_L("content source: namespace=%S, uri=%S, provider=%S, nodeid=%S"),
                &contentSource->NameSpace(),
                &contentSource->Uri(),
                &contentSource->Provider(),
                &contentSource->NodeId()));
            iContentSourceMap->AppendContentSourceL( contentSource );
            CleanupStack::Pop( contentSource );
            iBundleInsertIndex++;
            }           
        }

    CleanupStack::Pop( aConfiguration );
    // Pass ownership to default observer.
	DASSERT( iDefaultConfigurationProtocolObserver != NULL );
    iDefaultConfigurationProtocolObserver->ClientConfigurationL( aConfiguration );
    DLTRACEOUT((""));
    }
    
void CNcdLoadRootNodeOperation::ConfigurationDetailsL(
    CArrayPtr<MNcdConfigurationProtocolDetail>* aDetails )
    {
    DLTRACEIN((""));
    
    // Pass ownership to default observer.
	DASSERT( iDefaultConfigurationProtocolObserver != NULL );
	iDefaultConfigurationProtocolObserver->ConfigurationDetailsL( aDetails );
	
	DLTRACEOUT((""));
    }
    
void CNcdLoadRootNodeOperation::ConfigurationActionRequestL(
    MNcdConfigurationProtocolActionRequest* aActionRequest )
    {
    DLTRACEIN((""));
	// Pass ownership to default observer.
	DASSERT( iDefaultConfigurationProtocolObserver != NULL );
    iDefaultConfigurationProtocolObserver->ConfigurationActionRequestL( aActionRequest );
    DLTRACEOUT((""));
    }

void CNcdLoadRootNodeOperation::ConfigurationServerDetailsL( MNcdConfigurationProtocolServerDetails* aServerDetails )
    {
    DLTRACEIN((""));
	// Pass ownership to default observer.
	DASSERT( iDefaultConfigurationProtocolObserver != NULL );
    iDefaultConfigurationProtocolObserver->ConfigurationServerDetailsL( aServerDetails );
    DLTRACEOUT((""));
    }

void CNcdLoadRootNodeOperation::ConfigurationErrorL( MNcdConfigurationProtocolError* aError )
    {
    DLTRACEIN((""));
    iRootNodeState = EFailed;
    iError = aError->Code();

	// Pass ownership to default observer.
	DASSERT( iDefaultConfigurationProtocolObserver != NULL );
	// Operation already failed, ignore possible error here
    TRAP_IGNORE(iDefaultConfigurationProtocolObserver->ConfigurationErrorL( aError ));
   
    RunOperation();

    DLTRACEOUT((""));
    }
    
void CNcdLoadRootNodeOperation::ConfigurationEndL()
    {
    DLTRACEIN((""));
	// Pass to default observer.
	DASSERT( iDefaultConfigurationProtocolObserver != NULL );
    iDefaultConfigurationProtocolObserver->ConfigurationEndL();
    DLTRACEOUT((""));
    }


void CNcdLoadRootNodeOperation::Progress( CNcdBaseOperation& aOperation )
    {
    (void) aOperation; // suppresses compiler warning
    DASSERT( iRootNodeState == EReceiveBrowse )
    DASSERT( aOperation.Type() == ELoadNodeOperation )
    //CNcdLoadNodeOperationImpl& loadOp =
    //    static_cast<CNcdLoadNodeOperationImpl&>( aOperation );
    
    /*for ( TInt i = 0 ; i < loadOp.LoadedNodes().Count() ; i++ )
        {
        iLoadedNodes.AppendL( loadOp.LoadedNodes()[i] );
        }*/
    }
    
void CNcdLoadRootNodeOperation::QueryReceived( CNcdBaseOperation& /*aOperation*/,
    CNcdQuery* aQuery )
    {
    DASSERT( iRootNodeState == EReceiveBrowse )
    TRAPD( err, iSubOpQuerys.AppendL( aQuery ) );
    aQuery->InternalAddRef();
    if( err != KErrNone )
        {
        iError = err;
        iRootNodeState = EFailed;
        }
    RunOperation();
    }
    
void CNcdLoadRootNodeOperation::OperationComplete( CNcdBaseOperation* aOperation,
                                                   TInt aError )
    {
    DLTRACEIN(("error=%d", aError));
    DLINFO((("iRootNodeState = %d"), iRootNodeState ));
    (void) aError; // suppresses compiler warning

    DASSERT( iRootNodeState == EReceiveBrowse || 
             iRootNodeState == EBrowseRequest )
    DASSERT( aOperation->Type() == ELoadNodeOperation )
    
    DLINFO(("subop count: failed:%d completed:%d total:%d",
                iFailedSubOps.Count(), iCompletedSubOps.Count(), iSubOps.Count() ));
    
    TRAPD(err, 
    CNcdLoadNodeOperationImpl* loadOp =
        static_cast<CNcdLoadNodeOperationImpl*>( aOperation );
    DASSERT( loadOp->State() == CNcdLoadNodeOperationImpl::EFailed ||
        loadOp->State() == CNcdLoadNodeOperationImpl::EComplete )
    if ( loadOp->State() == CNcdLoadNodeOperationImpl::EFailed )
        {
        iFailedSubOps.AppendL( loadOp );
        }
    else if ( loadOp->State() == CNcdLoadNodeOperationImpl::EComplete )
        {
        iCompletedSubOps.AppendL( loadOp );
        const RPointerArray<CNcdNodeIdentifier>& loadedNodes = loadOp->LoadedNodes();
        CNcdRootNode& rootNode = 
            iNodeManager->RootNodeL( iRootNodeIdentifier->ClientUid() );
        CNcdNodeLink& rootLink = rootNode.NodeLinkL();
        TTime currentTime;
        currentTime.HomeTime();

        // add loaded nodes from child op to our own array
        for ( TInt i = 0 ; i < loadedNodes.Count() ; i++ )
            {
            CNcdNodeIdentifier* id = CNcdNodeIdentifier::NewLC( *loadedNodes[i] );
            iLoadedNodes.AppendL( id );
            CleanupStack::Pop( id );
            }
        }
    
    if ( iRootNodeState ==  EReceiveBrowse )
        {
        // call RunOperation only in this state,
        // otherwise RunOperation could call itself immediately
        // after starting a sub op
        // (sub-op start -> error -> complete callback -> run op )
        RunOperation();
        }); //TRAPD    
    if ( err != KErrNone )
        {
        iError = err;
        iRootNodeState = EFailed;
        RunOperation();
        }
    }
    
void CNcdLoadRootNodeOperation::ConfigurationChangedL() 
    {
    DLTRACEIN((( "iRootNodeState: %d"), iRootNodeState ));
    DASSERT( iRootNodeState == EReceiveConf )    
    // Master server address changed. Restart operation.
    iRootNodeState = EConfRequest;
    iMasterServerRedirectionState = ERedirecting;    
    }
    
void CNcdLoadRootNodeOperation::ReceiveMessage(
    MCatalogsBaseMessage* aMessage,
    TInt aFunctionNumber ) 
    {    
    DLTRACEIN((_L("Handle: %i, aFunctionNumber=%d"), aMessage->Handle(),
    aFunctionNumber));

    switch ( aFunctionNumber ) 
        {
        case ENCDOperationFunctionGetData:
            {
            HandleConfigurationDataRequestMessage( *aMessage );
            break;
            }
        default:
            {
            CNcdBaseOperation::ReceiveMessage( aMessage, aFunctionNumber );
            break;
            }
        }
    }

void CNcdLoadRootNodeOperation::ErrorL( MNcdPreminetProtocolError* aData )
    {
    DLTRACEIN((""));    
    // Default observer deletes aData
    iParser->DefaultObserver().ErrorL( aData );
    }

// ---------------------------------------------------------------------------
// ?description_if_needed
// ---------------------------------------------------------------------------
//
CNcdLoadRootNodeOperation::CNcdLoadRootNodeOperation( 
    TInt aClientUid,
    CNcdGeneralManager& aGeneralManager,     
    MCatalogsHttpSession& aHttpSession,      
    MNcdOperationRemoveHandler* aRemoveHandler,
    MCatalogsSession& aSession )
    : CNcdBaseOperation( aGeneralManager, aRemoveHandler, ELoadRootNodeOperation,
        aSession ), 
      iAccessPointManager( aGeneralManager.AccessPointManager() ),
      iHttpSession( aHttpSession ),
      iProtocol( aGeneralManager.ProtocolManager() ),
      iConfigManager( aGeneralManager.ConfigurationManager() ),
      iClientUid( aClientUid ),
      iNodeDbLocked( EFalse )
    {
    iRootNodeState = EConfRequest;
    iMasterServerRedirectionState = EBegin;
    iProgress.iState = 0;
    iProgress.iOperationId = 0;
    iProgress.iProgress = 0;
    iProgress.iMaxProgress = 100;
    }


// ---------------------------------------------------------------------------
// ?description_if_needed
// ---------------------------------------------------------------------------
//
void CNcdLoadRootNodeOperation::ConstructL()
    {
    DLTRACEIN((""));
    CNcdBaseOperation::ConstructL();
    
    iConfigResponseBuf = CBufFlat::NewL( 100 );
    }

// ---------------------------------------------------------------------------
// ?implementation_description
// ---------------------------------------------------------------------------
//
HBufC8* CNcdLoadRootNodeOperation::CreateConfRequestLC( CNcdQuery* aQuery )
    {
    DLTRACEIN((""));
    CNcdRequestConfiguration* req =
        NcdRequestGenerator::CreateConfigurationRequestLC();
    
    if( aQuery )
        {
        DASSERT(( aQuery->Response() == MNcdQuery::EAccepted ));
        
        MNcdConfigurationProtocolQueryResponse* queryResponse =
            CreateResponseL( *aQuery );
        CleanupStack::PushL( queryResponse );
        req->AddQueryResponseL( queryResponse );
        CleanupStack::Pop( queryResponse );
        }
    
    HBufC8* data = iProtocol.ProcessConfigurationRequestL(
        iPendingMessage->Session().Context(), *req );
    CleanupStack::PopAndDestroy( req );
    CleanupStack::PushL( data );    
    return data;
    }


void CNcdLoadRootNodeOperation::RevertNodesOfBrokenSourcesToCacheL() 
    {
    DLTRACEIN((""));
    // Revert the nodes from broken content sources
    CNcdRootNode& rootNode = 
        iNodeManager->RootNodeL( iRootNodeIdentifier->ClientUid() );
    CNcdContentSourceMap& oldContentSourceMap = rootNode.ContentSourceMap();
    DLINFO(("old content source count=%d", oldContentSourceMap.ContentSourceCount() ));
    for ( TInt i = 0; i < oldContentSourceMap.ContentSourceCount(); i++ ) 
        {
        CNcdContentSource& oldSource = oldContentSourceMap.ContentSource( i );

        // Note that the content sources contain node identifiers, 
        // not metadata identifiers.        
        RPointerArray<CNcdNodeIdentifier>& oldNodes = 
            oldContentSourceMap.NodesL( oldSource );
            
        if ( iContentSourceMap->HasContentSource( oldSource ) )
            {           
            DLINFO(("same content source")); 
            CNcdContentSource& source = 
                iContentSourceMap->ContentSourceL( oldSource );
            if ( source.IsBroken() ) 
                {
                // Broken content source, revert the nodes belonging to this source
                DLINFO(("Source was broken, revert %d nodes", oldNodes.Count()));      
                for ( TInt i = 0; i < oldNodes.Count(); i++ ) 
                    {
                    RevertNodeL( *oldNodes[i], source );
                    // Add the node to the new content source map also since the root node's old
                    // content source map is replaced with the new one.
                    CNcdNodeIdentifier* identifier = CNcdNodeIdentifier::NewLC( *oldNodes[i] );
                    iContentSourceMap->AddNodeToContentSourceL( identifier, source );
                    CleanupStack::Pop( identifier );
                    }
                    
                                    
                }
            }
        }
    }
        
    
void CNcdLoadRootNodeOperation::RevertNodeL(
    const CNcdNodeIdentifier& aNodeIdentifier,
    const CNcdContentSource& aContentSource ) 
    {
    DLTRACEIN((_L("node ns: %S, id: %S"), 
        &aNodeIdentifier.NodeNameSpace(), 
        &aNodeIdentifier.NodeId() ));
        
    iNodeManager->RevertNodeFromTempCacheL( aNodeIdentifier );
    CNcdNode* node = iNodeManager->NodePtrL( aNodeIdentifier );
    DASSERT( node );
    
    // The node is root's child, it must be added as a child since it was removed from the 
    // child list as it was moved to temp cache.
    CNcdNodeIdentifier* parentId = NcdNodeIdentifierEditor::ParentOfLC( aNodeIdentifier );
    if ( parentId->Equals( *iRootNodeIdentifier ) ) 
        {
        DLINFO(("Child of root"));
        CNcdRootNode& rootNode = 
            iNodeManager->RootNodeL( iRootNodeIdentifier->ClientUid() );
        CNcdNodeIdentifier* metaOfChild = 
            NcdNodeIdentifierEditor::CreateMetaDataIdentifierLC( aNodeIdentifier );
        iNodeManager->AddToParentL(
            *parentId, *metaOfChild, CNcdNodeFactory::ENcdNodeRoot, CNcdNodeFactory::ENcdNormalNode,
            CNcdNodeFactory::NodePurposeL( *node ), CNcdNodeManager::EInsert,
            iContentSourceMap->GetInsertIndexL( aContentSource, *parentId ) );
        CleanupStack::PopAndDestroy( metaOfChild );
        }
    CleanupStack::PopAndDestroy( parentId );        
    }

    
void CNcdLoadRootNodeOperation::AddNodesToDifferentParentsL() 
    {
    DLTRACEIN((""));

    // Move nodes from iBundleFolders to iLoadedNodes to update the bundle folders in proxy
    // side.
    User::LeaveIfError( 
        iLoadedNodes.Reserve( iLoadedNodes.Count() + iContentSourceMap->BundleFolderCount() ) );
        
    for ( TInt i = 0; i < iContentSourceMap->BundleFolderCount(); i++ ) 
        {
        // Append node ids to the loaded nodes list. These identifiers are
        // returned to the proxy side when the operation is completed.
        // Note that the content sources contain node identifiers, 
        // not metadata identifiers.
        CNcdNodeIdentifier* bundle = CNcdNodeIdentifier::NewLC(
            iContentSourceMap->BundleFolder( i ) );

        DLINFO((_L("Root Bundle ns: %S, id_: %S"), 
                &bundle->NodeNameSpace(),
                &bundle->NodeId()));

        iLoadedNodes.AppendL( bundle );

        // Do not delete because array takes ownership.
        CleanupStack::Pop( bundle );
        }
        
    DLTRACEOUT(("Ok"));        
    }
    
void CNcdLoadRootNodeOperation::SetAlwaysVisibleFlagsL() 
    {
    DLTRACEIN((""));
    for ( TInt i = 0; i < iContentSourceMap->ContentSourceCount(); i++ ) 
        {
        CNcdContentSource& contentSource = iContentSourceMap->ContentSource( i );
        if ( !contentSource.AlwaysVisible() ) 
            {
            continue;
            }
        // Get the reference. So, no need to close this array.
        RPointerArray<CNcdNodeIdentifier>& nodes = iContentSourceMap->NodesL( contentSource );
        TRAPD( err, 
            {            
            for ( TInt i = 0; i < nodes.Count(); i++ ) 
                {
                // Because content sources use node id 
                CNcdNodeIdentifier* nodeId = nodes[i];
                
                // Check whether the node is loaded completely
                for ( TInt i = 0; i < iLoadedNodes.Count(); i++ ) 
                    {
                    if ( iLoadedNodes[i]->Equals( *nodeId ) ) 
                        {                        
                        CNcdNode& node = iNodeManager->NodeL( *nodeId );
                        CNcdNodeMetaData& metadata = node.NodeMetaDataL();                
                        metadata.SetAlwaysVisible( ETrue );

                        // DLMAIN-523, "Always visible information is not 
                        // persisted to disk"
                        iNodeManager->DbSaveNodeMetaDataL( metadata );
                        break;
                        }
                    }
                }
            }); // TRAP


        if ( err == KErrNotFound ) 
            {
            DASSERT( EFalse );
            }
        else if ( err != KErrNone )
            {
            User::Leave( err );
            }

        }
    DLTRACEOUT(("Ok."));
    }       

     
void CNcdLoadRootNodeOperation::ParseCatalogBundleL(
    const MNcdConfigurationProtocolDetail& aDetail ) 
    {  
    DLTRACEIN((""));
    DASSERT( aDetail.GroupId() == KCatalogBundle );
    DASSERT( aDetail.Id() == KNameSpace );
    
    const RPointerArray<MNcdConfigurationProtocolContent>& bundleContents = 
        aDetail.Contents();
        
    const TDesC* bundleId = NULL;    
    for ( TInt i = 0; i < bundleContents.Count(); i++ ) 
        {
        const MNcdConfigurationProtocolContent* content = bundleContents[i];
        if ( content->Key() == KId ) 
            {
            bundleId = &content->Value();
            break;
            }
        }
        
    // Create folder for catalog bundle.
    DASSERT( bundleId );
    
    CNcdNodeIdentifier* metaDataId = CNcdNodeIdentifier::NewLC(
        aDetail.Value(), *bundleId, iPendingMessage->Session().Context().FamilyId() );
    DLINFO((_L("Bundle metaid ns: %S, id: %S"), 
            &metaDataId->NodeNameSpace(),
            &metaDataId->NodeId()));

    // The id has been gotten from the net server. So, it is same as
    // the metadata id that should be used here. Note that the creation of bundle requires the
    // metadataid (instead actual nodeid) for the parameter, and that we have here :)
    // Because the bundle folder is always the child of the root, the function can automatically
    // create the correct node id for the folder. 
    CNcdNodeFolder& bundleFolder = 
        iNodeManager->CreateBundleFolderL( *metaDataId );
        
    // Create the link for the bundle
    CNcdNodeLink& link = bundleFolder.CreateAndSetLinkL();
    
    // Also, notice that it is essential to insert the metadata identifier into the
    // link info. So, the right metadata will be found when the bundle is opened
    // from the database. For example when application has been started.
    link.SetMetaDataIdentifierL( *metaDataId );
    
    // Create meta data for bundle folder.
    CNcdNodeMetaData& bundleMetaData = 
        iNodeManager->CreateNodeMetaDataL( *metaDataId, CNcdNodeFactory::ENcdNodeFolder );

    for ( TInt i = 0; i < bundleContents.Count(); i++ )
        {
        const MNcdConfigurationProtocolContent* content = bundleContents[i];
        if ( content->Key() == KName ) 
            {
            bundleMetaData.SetNodeNameL( content->Value() );
            }
        else if ( content->Key() == KDescription ) 
            {
            bundleMetaData.SetDescriptionL( content->Value() );
            }
        else if ( content->Key() == KValidUntil ) 
            {
            link.SetValidUntilDelta(
                NcdProtocolUtils::DesDecToIntL( content->Value() ) );
            }
        else if ( content->Key() == KViewType ) 
            {
            static_cast<CNcdBundleFolder&>( bundleFolder ).SetViewTypeL( 
                content->Value() );
            }
        }
            
    const RPointerArray<MNcdConfigurationProtocolDetail>& subCatalogs = 
        aDetail.Details();

    // Parse icon data.
    for ( TInt i = 0; i < subCatalogs.Count(); i++ ) 
        {
        MNcdConfigurationProtocolDetail* detail = subCatalogs[i];
        if ( detail->Id() != KIcon ) 
            {
            continue;
            }
        const RPointerArray<MNcdConfigurationProtocolContent> iconContents = 
            detail->Contents();
        CNcdNodeIcon* icon = CNcdNodeIcon::NewL( *iNodeManager, bundleMetaData );
        bundleMetaData.SetIcon( icon );
        
        for ( TInt i = 0; i < iconContents.Count(); i++ ) 
            {
            MNcdConfigurationProtocolContent* content = iconContents[i];
            if ( content->Key() == KId ) 
                {
                icon->SetIconIdL( content->Value() );
                }
            else if ( content->Key() == KData ) 
                {
                const TDesC& iconData = content->Content();
                HBufC8* iconData8 = HBufC8::NewLC( iconData.Length() );
                iconData8->Des().Copy( iconData );
                HBufC8* decodedData = 
                    NcdProtocolUtils::DecodeBase64LC( *iconData8 );
                
                // Save the icon data to database.
                CNcdNodeIdentifier* iconId = CNcdNodeIdentifier::NewLC(
                    metaDataId->NodeNameSpace(), icon->IconId(), 
                    icon->Uri(), metaDataId->ClientUid() );
                iNodeManager->DbSaveIconDataL( *iconId, *decodedData );
                CleanupStack::PopAndDestroy( iconId );
                CleanupStack::PopAndDestroy( decodedData );
                CleanupStack::PopAndDestroy( iconData8 );
                }
            else if ( content->Key() == KUri && content->Value() != KNullDesC )
                {
                DLTRACE((_L("Setting bundle icon uri: %S"), &content->Value() ));
                icon->SetUriL( content->Value() );
                }
            }
        }
        
    iNodeManager->DbSaveNodeMetaDataL( bundleMetaData );          

    // Set the metadata to the bundle folder because it was not set during creation.
    bundleFolder.SetNodeMetaDataL( bundleMetaData );

    // Set the bundle folder as child of root node.
    // Bundle folders are always children of the root.
    iNodeManager->AddToParentL( *iRootNodeIdentifier, *metaDataId, 
                                CNcdNodeFactory::ENcdNodeRoot,
                                CNcdNodeFactory::ENcdNormalNode,
                                CNcdNodeFactory::ENcdBundleNode,
                                CNcdNodeManager::EReplace, iBundleInsertIndex );
    CleanupStack::PopAndDestroy( metaDataId );
    metaDataId = NULL;

    // Because AddToParentL only saves the parent information after child is added to it
    // we should always save the bundle node here. So, it will be usable after client is
    // restarted.
    iNodeManager->DbSaveNodeL( bundleFolder );        

    // Disabled bundle handling temporarily because of NCDALTCI-667
    // Bundles are now loaded explicitly with CNcdLoadBundleNodeOperation because
    // otherwise transparent folders are not refreshed when they are supposed to
/*
    // Parse sub catalogs.            
    for ( TInt i = 0; i < subCatalogs.Count(); i++ ) 
        {
        MNcdConfigurationProtocolDetail* subCatalog = subCatalogs[i];
        if ( subCatalog->GroupId() != KSubCatalogs ) 
            {
            continue;
            }
        
        // Get namespace
        DASSERT( subCatalog->Id() == KNameSpace );
        const TDesC& nameSpace = subCatalog->Value();
        DLINFO((_L("Bundle subcatalog ns(/value): %S"), 
                &subCatalog->Value()));
        
        //Get uri
        const TDesC* uri = NULL;
        const RPointerArray<MNcdConfigurationProtocolDetail>& subCatalogDetails =
            subCatalog->Details();
        for ( TInt i = 0; i < subCatalogDetails.Count(); i++ ) 
            {
            const MNcdConfigurationProtocolDetail* detail = subCatalogDetails[i];
            if ( detail->Id() == KUri )
                {
                uri = &detail->Value();
                DLINFO((_L("Bundle subcatalog detail uri(/value): %S"), 
                        &detail->Value()));
                }
            }
        if( uri == NULL )
            {
            DLTRACE(("Uri not found -> incomplete, skip"));
            continue;
            }
        
        CNcdNodeIdentifier* subCatalogIdentifier = NULL;
        const TDesC* provider = NULL;
        TBool transparent = EFalse;
        const RPointerArray<MNcdConfigurationProtocolContent>& subCatalogContents =
            subCatalog->Contents();
        for ( TInt i = 0; i < subCatalogContents.Count(); i++ ) 
            {
            const MNcdConfigurationProtocolContent* content = subCatalogContents[i];
            if ( content->Key() == KId ) 
                {
                // Notice that the the content source ids should be node identifiers.
                // Not the actual metadata identifiers. So, append the root info
                // in front of the value gotten from the server.
                CNcdNodeIdentifier* contentIdentifier =
                    CNcdNodeIdentifier::NewLC( nameSpace,
                                               content->Value(),
                                               *uri,
                                               bundleFolder.Identifier().ClientUid() );

                subCatalogIdentifier =
                    NcdNodeIdentifierEditor::CreateNodeIdentifierLC( bundleFolder.Identifier(),
                                                                      *contentIdentifier );
                CleanupStack::Pop( subCatalogIdentifier );
                CleanupStack::PopAndDestroy( contentIdentifier );
                CleanupStack::PushL( subCatalogIdentifier );
                DLINFO((_L("Bundle subcatalog content set node id(/value): %S"), 
                        &subCatalogIdentifier->NodeId()));
                }
            else if ( content->Key() == KProvider ) 
                {
                provider = &content->Value();
                DLINFO((_L("Bundle subcatalog content set provider (/value): %S"), 
                        provider));
                }
            else if ( content->Key() == KTransparent ) 
                {
                NcdProtocolUtils::DesToBool( transparent, content->Value() );
                }
            }
            
        if( subCatalogIdentifier == NULL )
            {
            DLTRACE(("Id not found -> incomplete, skip"));
            continue;
            }
        
        // Create the actual child folder
        CNcdNodeFolder* bundleChild = NULL;
        if( transparent )
            {
            bundleChild = &iNodeManager->CreateNodeFolderL(
                CNcdNodeFactory::ENcdTransparentNode, *subCatalogIdentifier );
            }
        else
            {
            bundleChild = &iNodeManager->CreateNodeFolderL(
                CNcdNodeFactory::ENcdNormalNode, *subCatalogIdentifier );
            }
        CleanupStack::PopAndDestroy( subCatalogIdentifier );
                    
        // Create a link for the child
        CNcdNodeLink& bundleChildLink = bundleChild->CreateAndSetLinkL();
        
        if ( provider )
            {
            bundleChildLink.SetCatalogsSourceNameL( *provider );
            }
        
        // Also, notice that it is essential to insert the metadata identifier into the
        // link info. So, the right metadata will be found when the node is opened
        // from the database. For example when application has been started.
        CNcdNodeIdentifier* bundleChildMeta =
            NcdNodeIdentifierEditor::CreateMetaDataIdentifierLC( bundleChild->Identifier() );
        bundleChildLink.SetMetaDataIdentifierL( *bundleChildMeta );
        CleanupStack::PopAndDestroy( bundleChildMeta );
        
        // Set uri for the child
        bundleChildLink.SetServerUriL( *uri );
        
        // Add the child to the bundle.
        if ( transparent )
            {
            iNodeManager->AddToParentL( bundleFolder.Identifier(),
                                    bundleChildLink.MetaDataIdentifier(), 
                                    CNcdNodeFactory::ENcdNodeFolder,
                                    CNcdNodeFactory::ENcdBundleNode,
                                    CNcdNodeFactory::ENcdTransparentNode,
                                    CNcdNodeManager::EAppend, 
                                    0,
                                    transparent );
            }
        else
            {
            iNodeManager->AddToParentL( bundleFolder.Identifier(),
                                    bundleChildLink.MetaDataIdentifier(), 
                                    CNcdNodeFactory::ENcdNodeFolder,
                                    CNcdNodeFactory::ENcdBundleNode,
                                    CNcdNodeFactory::ENcdNormalNode,
                                    CNcdNodeManager::EAppend, 
                                    0,
                                    transparent );
            }
        iNodeManager->DbSaveNodeL( *bundleChild );
        }
    */
    iContentSourceMap->AppendFolderL( bundleFolder.Identifier(), iBundleInsertIndex );
    
    // increment insert index for next bundle
    iBundleInsertIndex++;
    
    // Because AddToParentL only saves the parent information after child is added to it
    // we should always save the bundle node here. So, it will be usable after client is
    // restarted.
    
    // Unnecessary while bundle handling is disabled
    //iNodeManager->DbSaveNodeL( bundleFolder );
    }
    
    
TBool CNcdLoadRootNodeOperation::ContainsNode(
    const RPointerArray<CNcdNodeIdentifier>& aNodes,
    const CNcdNodeIdentifier& aNode) 
    {
    for ( TInt i = 0; i < aNodes.Count(); i++ ) 
        {
        CNcdNodeIdentifier* nodeId = aNodes[i];
        DASSERT( nodeId->ClientUid() == aNode.ClientUid() );
        if ( nodeId->Equals( aNode ) ) 
            {
            return ETrue;
            }
        }
    return EFalse;
    }
            
    
void CNcdLoadRootNodeOperation::HandleConfigurationDataRequestMessage(
    MCatalogsBaseMessage& aMessage ) 
    {
    DLTRACEIN((""));
    TPtr8 data = iConfigResponseBuf->Ptr( 0 );
    
    TRAPD( err, aMessage.CompleteAndReleaseL( data, KErrNone ) );
    if ( err != KErrNone ) 
        {
        aMessage.CompleteAndRelease( err );
        }        
    }    
// ---------------------------------------------------------------------------
// From class CNcdBaseOperation.
// ?implementation_description
// ---------------------------------------------------------------------------
//
TInt CNcdLoadRootNodeOperation::RunOperation()
    {
    DLTRACEIN((("this-ptr: %x"), this ));
  
    TInt err( KErrNone );
    TRAP( err, DoRunOperationL() );
     
     if ( err != KErrNone )
        {
        DLTRACE(("error: %d", err));
        Cancel();
        iRootNodeState = EFailed;
        iError = err;
        if ( iPendingMessage )
            {
            // ignoring error because operation already failed
            CNcdBaseOperation::CompleteMessage( iPendingMessage,
                ENCDOperationMessageCompletionError, iError );
            }
        }

    DLTRACEOUT(("err: %d", err));
    return err;    
    }

    
void CNcdLoadRootNodeOperation::DoRunOperationL()
    {
    DLTRACEIN((""));
    switch ( iRootNodeState )
        {
        case EConfRequest:
            {            
            DLTRACE((_L("->EConfRequest")));
            DASSERT ( iPendingMessage );
                        
            CNcdRootNode& root = 
                iNodeManager->CreateRootL( iPendingMessage->Session().Context() );
            root.CreateAndSetLinkL();
            
            if ( !iRootNodeIdentifier )
                {
                // create identifier for root node
                iRootNodeIdentifier = CNcdNodeIdentifier::NewL( root.Identifier() );

                // Store previous list only if some children have been previously loaded.
                if( root.ChildrenPreviouslyLoaded() )
                    {
                    root.StoreChildrenToPreviousListL();
                    }

                // Create previous lists of children for new checking.
                iChildEntityMaps.ResetAndDestroy();
                iNodeManager->SeenInfo().CreatePreviousListsForChildrenL( root, iChildEntityMaps );                    
                    
                iNodeManager->BackupAndClearCacheL( *iRootNodeIdentifier );
                iNodeManager->LockNodeDbL( TUid::Uid( iClientUid ) );
                iNodeDbLocked = ETrue;                  
                }
                            
            // remove old content sources
            delete iContentSourceMap;
            iContentSourceMap = NULL;
            iContentSourceMap = CNcdContentSourceMap::NewL();
                                    
            delete iServerUri;
            iServerUri = NULL;
            iServerUri = iConfigManager.MasterServerAddressL(
                iPendingMessage->Session().Context() ).AllocL();
            
            HBufC8* request = CreateConfRequestLC( iConfQuery );
            
            if ( iConfQuery )
                {
                iConfQuery->InternalRelease();
                iConfQuery = NULL;
                }
                        
            DLINFO(( "request= %S", request ));
            
            // create transaction
            iGeneralManager.HttpUtils().CreateTransactionL( 
                iHttpSession,
                iTransaction,
                *iServerUri,
                *this,
                *request );
                
            
            // create parser
            delete iParser;
            iParser = NULL;
            iParser = iProtocol.CreateParserL( 
                iPendingMessage->Session().Context(), *iServerUri );
            MNcdParserObserverBundle& observers = iParser->Observers();
            observers.SetParserObserver( this );
            iDefaultConfigurationProtocolObserver =
                observers.ConfigurationProtocolObserver();
            observers.SetConfigurationProtocolObserver( this );
            observers.SetInformationObserver( this );
            
            iConfigManager.AddObserverL( *this, iPendingMessage->Session().Context() );
            
            iParser->BeginAsyncL();
  
            // start transaction
            User::LeaveIfError( iTransaction->Start() );            
            CleanupStack::PopAndDestroy( request );
            
            
            iRootNodeState = EReceiveConf;
            DLTRACE(( "->EConfRequest done" ));
            break;
            }
            
        case EReceiveConf:
            {
            DLTRACE((_L("->EReceiveConf")));
            // Should send progress only if progress is made
            
            if ( iPendingMessage && iSendProgress )
                {
                User::LeaveIfError( CNcdBaseOperation::CompleteMessage( iPendingMessage,
                    ENCDOperationMessageCompletionProgress,
                    iProgress, KErrNone ) );
                iSendProgress = EFalse;
                }
            DLTRACE((_L("->EReceiveConf done")));
            break;
            }
            
        case EConfQuery:
            {
            DLTRACE(("->EConfQuery"));
            DASSERT( iConfQuery );
            DASSERT( iConfQuery->Response() == MNcdQuery::EAccepted ||
                iConfQuery->Response() == MNcdQuery::ERejected )
            if ( iConfQuery->Response() == MNcdQuery::EAccepted)
                {
                DLTRACE(("Query accepted"));
                if ( iConfQuery->ItemCount() == 0 )
                    {
                    // SPECIAL CASE:
                    // querys with no items don't need responding to
                    // e.g. a server message
                    if( iContentSourceMap->ContentSourceCount() > 0 )
                        {
                        // content sources received in the earlier response,
                        // start loading them
                        iRootNodeState = EBrowseRequest;
                        }
                    else if ( iMasterServerRedirectionState == ERedirecting )
                        {
                        // Redirect. Delete conf query since it does not need
                        // responding to new master server.
                        DLINFO(("Redirect"));
                        iConfQuery->InternalRelease();
                        iConfQuery = NULL;                       
                        iRootNodeState = EConfRequest;
                        }
                    else
                        {
                        // no content sources received
                        // e.g. server didn't give any content sources 
                        // with the set provisioning, only a 
                        // "service not available..." message is received
                        iRootNodeState = EComplete;
                        }                                
                    }
                else
                    {
                    // NORMAL CASE:
                    // Respond to the query in a new request
                    iRootNodeState = EConfRequest;
                    }            
                }            
            else
                {
                DLTRACE(("Query rejected"));
                if ( iConfQuery->IsOptional() )
                    {
                    DLTRACE(("Query is optional"));
                    if( iContentSourceMap->ContentSourceCount() > 0 )
                        {
                        DLTRACE(("Content sources received previously, start loading"));
                        // content sources received in the earlier response,
                        // start loading them
                        iRootNodeState = EBrowseRequest;
                        }
                    else if ( iMasterServerRedirectionState == ERedirecting )
                        {
                        // Redirect. Delete conf query since it does not need
                        // responding to new master server.
                        DLINFO(("Redirect"));
                        iConfQuery->InternalRelease();
                        iConfQuery = NULL;                       
                        iRootNodeState = EConfRequest;
                        }                        
                    else
                        {
                        DLTRACE(("No sources received!"));
                        // no content sources received with an optional query
                        // this should never happen!                        
                        iError = KNcdErrorNoContentSources;
                        iRootNodeState = EFailed;
                        }                            
                    }
                else
                    {
                    DLTRACE(("Query not optional, operation will stop!"));
                    iRootNodeState = EComplete;
                    }
                }
                            
            RunOperation();            
            DLTRACE(("->EConfQuery done"));
            break;
            }
            
        case EBrowseRequest:
            {
            DLTRACE((_L("->EBrowseRequest")));
            
            iSubOps.ResetAndDestroy();

            // Create load node op for each content source.
            DLINFO((("Content source count=%d"), iContentSourceMap->ContentSourceCount()));
            for ( TInt i = 0 ; i < iContentSourceMap->ContentSourceCount() ; i++ )
                {
                CNcdContentSource& contentSource =
                    iContentSourceMap->ContentSource( i );
                DLINFO((_L("content source: namespace=%S, uri=%S, id=%S"),
                    &contentSource.NameSpace(), &contentSource.Uri(), &contentSource.NodeId()));
                
                // The parent identifier should be root here.
                // So, no need to change that parent identifier info. It does not
                // differ from the metadataid because root does not have metadata.
                CNcdLoadNodeOperationImpl* loadOp =
                    CNcdLoadNodeOperationImpl::NewLC(
                        contentSource,
                        iContentSourceMap,
                        contentSource.ParentIdentifier(),
                        iGeneralManager,                        
                        iHttpSession,                        
                        iRemoveHandler,
                        iSession );
                
                loadOp->AddObserverL( this );
                iSubOps.AppendL( loadOp );
                CleanupStack::Pop( loadOp );
                // error code ignored, errors handled via callback
                loadOp->Start();
                }
            
            iRootNodeState = EReceiveBrowse;
            DLINFO(("subop count: failed:%d completed:%d total:%d",
                iFailedSubOps.Count(), iCompletedSubOps.Count(), iSubOps.Count() ));
            if ( iFailedSubOps.Count() + iCompletedSubOps.Count() ==
                 iSubOps.Count() )
                {
                // all sub ops have either completed or failed
                // -> this operation is now complete
                iRootNodeState = EComplete;
                if ( iFailedSubOps.Count() > 0 ) 
                    {
                    DLINFO(("Some catalogs failed to load"));
                    iError = KNcdErrorSomeCatalogsFailedToLoad;
                    }
                RunOperation();
                }
                
            DLTRACE((_L("->EBrowseRequest done")));
            
            break;
            }
            
        case EReceiveBrowse:
            {
            DLTRACE((_L("->EReceiveBrowse")));
            if( iSubOpQuerys.Count() > 0 )
                {
                // send sub op query to proxy
                CNcdBaseOperation::QueryReceivedL( iSubOpQuerys[0] );
                // release own reference and remove
                iSubOpQuerys[0]->InternalRelease();
                iSubOpQuerys.Remove( 0 );
                }                
            else if ( iPendingMessage && iLoadedNodes.Count() > 0 )
                {
                SetAlwaysVisibleFlagsL();
                
                // send updated nodes identifiers to proxy
                User::LeaveIfError( CompleteMessage( iPendingMessage,
                    ENCDOperationMessageCompletionNodesUpdated,
                    iProgress,
                    iLoadedNodes,
                    KErrNone ) );
                
                iLoadedNodes.ResetAndDestroy();
                }
            else if ( iFailedSubOps.Count() + iCompletedSubOps.Count() ==
                 iSubOps.Count() )
                {
                // all sub ops have either completed or failed
                // -> this operation is now complete
                iRootNodeState = EComplete;
                if ( iFailedSubOps.Count() > 0 ) 
                    {
                    DLINFO(("Some catalogs failed to load"));
                    iError = KNcdErrorSomeCatalogsFailedToLoad;
                    }
                RunOperation();
                }
                
            DLTRACE((_L("->EReceiveBrowse done")));
            break;
            }
            
        case EComplete:
            {
            DLTRACE((_L("->EComplete")));
            
            CNcdRootNode& rootNode = 
                        iNodeManager->RootNodeL( iRootNodeIdentifier->ClientUid() ); 
            // Compare the ContentSourceMaps of previous root node load and this
            // load and delete the nodes that were removed from server.
            if ( iContentSourceMap && ( iContentSourceMap->ContentSourceCount() > 0 || 
                iContentSourceMap->BundleFolderCount() > 0 ) ) 
                {
                DLINFO(("Content source map count"));
                RevertNodesOfBrokenSourcesToCacheL();                                            
                AddNodesToDifferentParentsL();
                SetAlwaysVisibleFlagsL();

                // Give the new content source map to root node to be used in the next
                // root node load
                rootNode.SetContentSourceMap( iContentSourceMap );
                // Root node takes the ownership. 
                // So, set NULL here. So this class will not delete this.
                iContentSourceMap = NULL;
                // Now the RAM node cache should be updated correctly, save it to database.
                iNodeManager->UnlockNodeDb( TUid::Uid( iClientUid ) );
                iNodeDbLocked = EFalse;
                iNodeManager->DbSaveNodesL( *iRootNodeIdentifier );                                
                }
                
            if( iNodeDbLocked )
                {
                iNodeManager->UnlockNodeDb( TUid::Uid( iClientUid ) );
                iNodeDbLocked = EFalse;
                }
            
            iNodeManager->ClearTempCacheL( *iRootNodeIdentifier );
            
            // Set the children loaded flag so that next refresh stores
            // previous child list (needed for new checking)
            if( rootNode.ChildCount() )
                {
                rootNode.SetChildrenPreviouslyLoaded();
                iNodeManager->DbSaveNodeL( rootNode );
                }
            // Check new status
            iNodeManager->SeenInfo().StorePreviousListsToExistingChildrenL(
                rootNode,
                iChildEntityMaps );
                
            iChildEntityMaps.ResetAndDestroy();
            
            // Check new status for transparent folders (transparent folders are
            // loaded during root op so they need to be checked here)
            iNodeManager->SeenInfo().DoNewCheckForTransparentChildrenL(
                            rootNode );
                            
            iNodeManager->SeenInfo().RefreshFolderSeenStatusL( *iRootNodeIdentifier );
            
            if ( iPendingMessage && iLoadedNodes.Count() > 0 )
                {
                DLINFO(("Pending message loaded nodes"));
                // send updated nodes identifiers to proxy
                User::LeaveIfError( CompleteMessage( iPendingMessage,
                    ENCDOperationMessageCompletionNodesUpdated,
                    iProgress,
                    iLoadedNodes,
                    KErrNone ) );
                 
                iLoadedNodes.ResetAndDestroy();
                }
            else if ( iPendingMessage )
                {
                DLINFO(("Pending message"));
                if ( iError == KErrNone ) 
                    {
                    // Send complete message to proxy.
                    User::LeaveIfError( CNcdBaseOperation::CompleteMessage( iPendingMessage,
                        ENCDOperationMessageCompletionComplete,
                        iProgress,
                        KErrNone ) );
                    
                    iOperationState = EStateComplete;
                    }
                else 
                    {
                    iRootNodeState = EFailed;
                    RunOperation();
                    }
                }
            DLTRACE((_L("->EComplete done")));
            break;
            }
            
        case EFailed:
            {
            DLTRACE((_L("->EFailed")));
            Cancel();
            // Send error message in case didn't have any pending
            // messages when the operation actually failed
            if( iPendingMessage )
                {
                DLINFO(("Pending"));
                // ignoring error because operation already failed
                CNcdBaseOperation::CompleteMessage( iPendingMessage,
                    ENCDOperationMessageCompletionError, iError );
                }
            DLTRACE((_L("->EFailed done")));
            break;
            }
        default:
            {
            DLTRACE(("default"));
            DASSERT(0);
            break;
            }
        }  
    }
    
void CNcdLoadRootNodeOperation::ChangeToPreviousStateL()
    {
    DLTRACEIN(("no implementation needed"));
    }

TBool CNcdLoadRootNodeOperation::QueryCompletedL( CNcdQuery* aQuery )
    {    
    DLTRACEIN((""));
    TBool handled = EFalse;
    if ( aQuery == iConfQuery )
        {
        // handle conf query
        DASSERT( iRootNodeState == EConfQuery );
        //RunOperation();
        // Query has been handled, release it
        /*iConfQuery->Release();
        iConfQuery = NULL;*/
        if ( aQuery->Response() == MNcdQuery::ERejected ) 
            {
            Cancel();
            }
        
        handled = ETrue;
        }
    else
        {
        // handle child ops's querys
        TBool found = EFalse;
        for( TInt i = 0 ; i < iSubOps.Count() ; i++ )
            {
            CNcdQuery* query = iSubOps[i]->ActiveQuery();
            if ( aQuery == query )
                {
                iSubOps[i]->QueryHandledL( aQuery );
                TInt index = iSubOpQuerys.Find( aQuery );
                if ( index != KErrNotFound )
                    {
                    // remove reference
                    iSubOpQuerys[index]->InternalRelease();
                    iSubOpQuerys.Remove( index );
                    }
                query->InternalRelease();
                query = NULL;
                found = ETrue;
                break;
                }
            if ( query )
                {
                query->InternalRelease();
                }
            }
        if ( !found )
            {
            DLINFO(("Query doesn't belong to any sub op! ERROR!"))
            DASSERT( 0 );
            User::Leave( KErrArgument );
            }
        else
            {
            handled = ETrue;
            }
        }
    return handled;
    }
