/*
* Copyright (c) 2005-2007 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:  xSP Contact operation
 *
*/


// INCLUDES
#include "CVPbkxSPContactsOperation.h"


#include <barsc.h>
#include <barsread.h>


#include <TVPbkWordParserCallbackParam.h>
#include <VPbkEng.rsg>
#include <CVPbkContactFieldIterator.h>
#include <CVPbkContactManager.h>
#include <CVPbkFieldTypeRefsList.h>
#include <MVPbkStoreContact.h>
#include <MVPbkContactFieldUriData.h>
#include <MVPbkContactStore.h>
#include <MVPbkContactLink.h>
#include <MVPbkContactStoreProperties.h>
#include <VPbkContactStoreUris.h>
#include "VPbkDebug.h"

#include <CVPbkEComImplementationsList.h>
#include <spsettings.h>
#include <spproperty.h>
namespace
    {

#ifdef _DEBUG	
    enum TxSPErrors
        {
        ExSPErrorWrongLogic1,
        ExSPErrorWrongState,
        EInvalidOperation,
        ExSPErrorWrongStateRun
        };

    _LIT( KPanicStrxSPManagement, "VPbk_xSPManag");

    void Panic(TxSPErrors aReason)
        {
        User::Panic(KPanicStrxSPManagement, aReason);
        }
#endif	
    }

///////////////////////////////////////////////////////////////////////////////

CVPbkxSPContactsOperation* CVPbkxSPContactsOperation::NewLC(
        const MVPbkStoreContact& aContact,
        CVPbkContactManager& aContactManager,
        MVPbkOperationErrorObserver& aErrorObserver, TxSPOperation aOperation)
    {
    CVPbkxSPContactsOperation* self = new (ELeave) CVPbkxSPContactsOperation(
            aContact,
            aContactManager,
            aErrorObserver,
            aOperation );
    CleanupStack::PushL(self);
    self->ConstructL();
    return self;
    }

void CVPbkxSPContactsOperation::ConstructL()
    {
    iContactLink = iContact.CreateLinkLC();
    CleanupStack::Pop();  //iContactLink
    iContactLinks = CVPbkContactLinkArray::NewL();
    CompleteOurself(); //start execution right away    
    }

CVPbkxSPContactsOperation::CVPbkxSPContactsOperation(
    const MVPbkStoreContact& aContact,
    CVPbkContactManager& aContactManager,
    MVPbkOperationErrorObserver& aErrorObserver, 
    TxSPOperation /*aOperation*/) :
    CActive(EPriorityStandard), 
        iNextState(EStateNone), iContact(aContact),
        iContactManager(aContactManager), iErrorObserver(&aErrorObserver)
    {
    CActiveScheduler::Add(this);
    }

CVPbkxSPContactsOperation::~CVPbkxSPContactsOperation()
    {
    Cancel();
    delete iContactOperation;

    if(iContactLinks) 
        {
        iContactLinks->ResetAndDestroy();
        }
    
    delete iContactLinks;
    delete iContactLink;
    delete iFieldTypeRefList;
    delete iXspIdArray;
    }

MVPbkContactOperationBase* CVPbkxSPContactsOperation::NewGetxSPLinksOperationL(
        const MVPbkStoreContact& aContact,
        CVPbkContactManager& aContactManager,
        MVPbkOperationResultObserver<MVPbkContactLinkArray*>& aObserver,
        MVPbkOperationErrorObserver& aErrorObserver, TxSPOperation aOperation)
    {
    __ASSERT_DEBUG( aOperation == EGetxSPContactLinks,
            Panic(EInvalidOperation) );

    CVPbkxSPContactsOperation* self = NewLC(aContact, aContactManager,
            aErrorObserver, aOperation);
    self->iLinksObserver = &aObserver;
    self->iNextState = EStateFind;

    CleanupStack::Pop(self);
    return self;
    }

void CVPbkxSPContactsOperation::DoCancel()
    {
    delete iContactOperation;
    iContactOperation = NULL;
    }

void CVPbkxSPContactsOperation::RunL()
    {
    switch(iNextState)
        {
        case EStateFind:
            {
            GetIMPPDataL();
            }
            break;
        
        case EStateAbortWithError:
            {
            NotifyError(iAbortError);
            }
            break;
            
        default:
            {
            __ASSERT_DEBUG( EFalse,Panic( ExSPErrorWrongStateRun ) );
            }
        }
    }

TInt CVPbkxSPContactsOperation::RunError(TInt aError)
    {
    NotifyError(aError);
    return KErrNone;
    }

//---------------------------------------------------------------
// These are from MVPbkContactStoreObserver

void CVPbkxSPContactsOperation::FindFromStoreSucceededL(
        MVPbkContactStore& /*aStore*/,
        MVPbkContactLinkArray* aResultsFromStore)
    {
    ProcessContactLinksL(aResultsFromStore);
    delete aResultsFromStore;
    }

void CVPbkxSPContactsOperation::FindFromStoreFailed(
        MVPbkContactStore& /*aStore*/, TInt /*aError*/)
    {
    //do nothing
    }

void CVPbkxSPContactsOperation::FindFromStoresOperationComplete()
    {
    TRAP_IGNORE(SubsearchCompleteL());
    }

// ----------------------------------------------------------
// CVPbkxSPContactsOperation::GetIMPPDataL
// 
// ----------------------------------------------------------
//
void CVPbkxSPContactsOperation::GetIMPPDataL()
    {
    //Check is contact valid.
    __ASSERT_ALWAYS ( NULL != &iContact, User::Leave(KErrArgument));
    
    TBool imppFound = EFalse;
    iXspIdArray = new ( ELeave ) CDesCArrayFlat( 5 );    
    const MVPbkFieldType* type = 
        iContactManager.FieldTypes().Find( R_VPBK_FIELD_TYPE_IMPP);
    CVPbkBaseContactFieldTypeIterator* itr =
            CVPbkBaseContactFieldTypeIterator::NewLC( *type,
                    iContact.Fields() );
    if (itr->HasNext() )
        {
        imppFound = ETrue;
        while (itr->HasNext() )
            {
            const MVPbkBaseContactField* field = itr->Next();
            const MVPbkContactFieldUriData& uri =
                    MVPbkContactFieldUriData::Cast(field->FieldData() );
            HBufC* data = uri.Uri().AllocL();
            CleanupStack::PushL(data);
            iXspIdArray->AppendL(data->Des() ); 
            CleanupStack::PopAndDestroy(data); 
            }

        iFieldTypeRefList = CVPbkFieldTypeRefsList::NewL();
        iFieldTypeRefList->AppendL( 
            *iContactManager.FieldTypes().Find( R_VPBK_FIELD_TYPE_IMPP) );
        FindUsingIdL();
        }

    CleanupStack::PopAndDestroy(itr);     

    //If there isn't any impp fields, notify empty contact link array. 
    if (!imppFound)
        {
        NotifyResult();
        }
    }

// ---------------------------------------------------------------------------
// CVPbkxSPContactsOperation::FindUsingIdL
// ---------------------------------------------------------------------------
//
TBool CVPbkxSPContactsOperation::FindUsingIdL()
    {
    TBool started(EFalse);

    if( iXspIdArray->MdcaCount() > iNextXspId )
        {
        if ( iContactOperation != NULL )
            {
            delete iContactOperation;
            iContactOperation = NULL;
            }
   
        started = ETrue;
        CDesCArrayFlat* idArray = new ( ELeave ) CDesCArrayFlat( 1 );
        CleanupStack::PushL(idArray);
        idArray->AppendL( iXspIdArray->MdcaPoint(iNextXspId) );
        iNextXspId++;
        TCallBack parser(CVPbkxSPContactsOperation::WordParserL, this);        
        CDesC16ArrayFlat* aXUriArray = new ( ELeave ) CDesCArrayFlat( 52 );
		CleanupStack::PushL(aXUriArray);
		RIdArray ids;
		CleanupClosePushL( ids );
		CSPSettings* settings = CSPSettings::NewL();
		CleanupStack::PushL( settings ); 
		TInt error = settings->FindServiceIdsL( ids );  
		const TInt count = ids.Count();
       	TVPbkContactStoreUriPtr defaultUri = VPbkContactStoreUris::DefaultCntDbUri();

		for( TInt i = 0; i < count; i++ )
		    {
		    CSPProperty* property = CSPProperty::NewLC();
		    error = settings->FindPropertyL( ids[i], EPropertyContactStoreId,
		        *property );
		    if( KErrNone == error )
		        {
		        RBuf uri;
		        uri.Create( KSPMaxDesLength );
		        CleanupClosePushL( uri );  
		        property->GetValue( uri );
		        
		        // Append the uri which is not equal to default store uri
		       	if ( defaultUri.UriDes().CompareF(uri) != KErrNone )
		       		{
		       		aXUriArray->AppendL( uri );
		       		}
		        CleanupStack::PopAndDestroy();  //uri
		        }
		    CleanupStack::PopAndDestroy();  //property
		    }
		CleanupStack::PopAndDestroy( 2 ); // settings, ids
        
        iContactOperation = iContactManager.FindL( *idArray, *iFieldTypeRefList,
                *this, parser,*aXUriArray);
                
        CleanupStack::PopAndDestroy( 2 );
        }
    
    return started;
    }

// ----------------------------------------------------------
// CVPbkxSPContactsOperation::WordParserL
// 
// ----------------------------------------------------------
//
TInt CVPbkxSPContactsOperation::WordParserL(TAny* aWordParserParam)
    {
    //Get all data, no need to parse anything.. 
    TVPbkWordParserCallbackParam* param =
            static_cast<TVPbkWordParserCallbackParam*>(aWordParserParam );
    TPtrC data(param->iStringToParse->Ptr() );
    param->iWordArray->AppendL(data);
    return 0;
    }

void CVPbkxSPContactsOperation::ProcessContactLinksL(
        MVPbkContactLinkArray* aResultsFromStore)
    {
    TInt count = aResultsFromStore->Count();

    for (TInt a = 0; a < count; a++)
        {
        const MVPbkContactLink& link = aResultsFromStore->At(a);

        //If not from original storage, add to array.
        if (!link.RefersTo(iContact))
            {
            if(iContactLinks->Find(link) == KErrNotFound)
                {
                iContactLinks->AppendL(link.CloneLC());
                CleanupStack::Pop(); //Clone
                }
            }
        }
    }

// --------------------------------------------------------------------------
// Completes this active object.
// --------------------------------------------------------------------------
void CVPbkxSPContactsOperation::CompleteOurself()
    {
    if ( !IsActive() )
        {
        TRequestStatus* status = &iStatus;
        User::RequestComplete(status, KErrNone);
        SetActive();
        }
    else
        {
        __ASSERT_DEBUG( EFalse, Panic(ExSPErrorWrongLogic1) );
        }
    }

// --------------------------------------------------------------------------
// Search completed 
// --------------------------------------------------------------------------
void CVPbkxSPContactsOperation::SubsearchCompleteL()
    {
    if(!FindUsingIdL())
        {
        NotifyResult();
        }
    }

// --------------------------------------------------------------------------
// Notifies operation observer of results
// --------------------------------------------------------------------------
void CVPbkxSPContactsOperation::NotifyResult()
    {
    iLinksObserver->VPbkOperationResultCompleted( this, iContactLinks);
    }

// --------------------------------------------------------------------------
// Sends error notification to the error observer
// --------------------------------------------------------------------------
inline void CVPbkxSPContactsOperation::NotifyError(TInt aErr)
    {
    iErrorObserver->VPbkOperationFailed( this, aErr);
    }

// --------------------------------------------------------------------------
// Notify error async
// --------------------------------------------------------------------------
void CVPbkxSPContactsOperation::AbortWithError(TInt aErr)
    {
    iAbortError = aErr;
    iNextState = EStateAbortWithError;
    CompleteOurself();
    }

// end of file
