/*
* 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 "BTServiceSearcher.h"
#include "BTServiceSearcher.pan"


CBTServiceSearcher::CBTServiceSearcher()
:  iIsDeviceSelectorConnected(EFalse)   
    {
    }

CBTServiceSearcher::~CBTServiceSearcher()
{
    if (iIsDeviceSelectorConnected)
	{
        iDeviceSelector.CancelNotifier(KDeviceSelectionNotifierUid);
        iDeviceSelector.Close();
	}
    delete iSdpSearchPattern;
    iSdpSearchPattern = NULL;
	
    delete iAgent;
    iAgent = NULL;
    
	// An outstanding FindServiceL request must be completed upon object delete
	if (iStatusObserver) {
		User::RequestComplete(iStatusObserver, KErrNone); // everything ~OK
	}
}

void CBTServiceSearcher::Cancel() {

    if (iIsDeviceSelectorConnected)
	{
        iDeviceSelector.CancelNotifier(KDeviceSelectionNotifierUid);
    
	}
    delete iSdpSearchPattern;
    iSdpSearchPattern = NULL;
	
    delete iAgent;
    iAgent = NULL;
    
	// An outstanding FindServiceL request must be completed upon object delete
	if (iStatusObserver) {
		User::RequestComplete(iStatusObserver, KErrCancel); // everything ~OK
	}



}

void CBTServiceSearcher::SelectDeviceByDiscoveryL(TRequestStatus& aObserverRequestStatus)
    {
    if (!iIsDeviceSelectorConnected)
        {
        User::LeaveIfError(iDeviceSelector.Connect());
        iIsDeviceSelectorConnected = ETrue;
        }

    //  Request a device selection 
    TBTDeviceSelectionParamsPckg selectionFilter;
    selectionFilter().SetUUID(ServiceClass());

    iDeviceSelector.StartNotifierAndGetResponse(
        aObserverRequestStatus, 
        KDeviceSelectionNotifierUid, 
        selectionFilter, 
        iResponse);
    }


void CBTServiceSearcher::FindServiceL(TRequestStatus& aObserverRequestStatus)
    {
    if (!iResponse().IsValidBDAddr())
        {
        User::Leave(KErrNotFound);
        }
    iHasFoundService = EFalse;

    // delete any existing agent and search pattern
    delete iSdpSearchPattern;
    iSdpSearchPattern = NULL;

    delete iAgent;
    iAgent = NULL;

    iAgent = CSdpAgent::NewL(*this, BTDevAddr());

    iSdpSearchPattern = CSdpSearchPattern::NewL();
   
    iSdpSearchPattern->AddL(ServiceClass()); 
    // return code is the position in the list that the UUID is inserted at 
    // and is intentionally ignored
  
    iAgent->SetRecordFilterL(*iSdpSearchPattern);

    iStatusObserver = &aObserverRequestStatus;

    iAgent->NextRecordRequestL();
    }

void CBTServiceSearcher::NextRecordRequestComplete(
    TInt aError, 
    TSdpServRecordHandle aHandle, 
    TInt aTotalRecordsCount)
    {
    TRAPD(error,
        NextRecordRequestCompleteL(aError, aHandle, aTotalRecordsCount);
    );

    if (error != KErrNone) 
        {
        Panic(EBTServiceSearcherNextRecordRequestComplete);
        }
    }

void CBTServiceSearcher::NextRecordRequestCompleteL(
    TInt aError, 
    TSdpServRecordHandle aHandle, 
    TInt aTotalRecordsCount
)
    {
    if (aError == KErrEof)
        {
        Finished();
        return;
        }

    if (aError != KErrNone)
        {        
        Finished(aError);
        return;
        }

    if (aTotalRecordsCount == 0)
        {        
        Finished(KErrNotFound);
        return;
        }

    //  Request its attributes
    iAgent->AttributeRequestL(aHandle, KSdpAttrIdProtocolDescriptorList);
    }

void CBTServiceSearcher::AttributeRequestResult(
    TSdpServRecordHandle aHandle, 
    TSdpAttributeID aAttrID, 
    CSdpAttrValue* aAttrValue
)
    {
    TRAPD(error,
        AttributeRequestResultL(aHandle, aAttrID, aAttrValue);
    );
    if (error != KErrNone)
        {
        Panic(EBTServiceSearcherAttributeRequestResult);
        }

    // Ownership has been transferred
    delete aAttrValue;
    }

void CBTServiceSearcher::AttributeRequestResultL(
    TSdpServRecordHandle /*aHandle*/, 
    TSdpAttributeID aAttrID, 
    CSdpAttrValue* aAttrValue
)
    {
    __ASSERT_ALWAYS(aAttrID == KSdpAttrIdProtocolDescriptorList, User::Leave( KErrNotFound ));

    TSdpAttributeParser parser(ProtocolList(), *this);

    // Validate the attribute value, and extract the RFCOMM channel
    aAttrValue->AcceptVisitorL(parser);

    if (parser.HasFinished())
        {
        // Found a suitable record so change state
        iHasFoundService = ETrue;
        }
    }

void CBTServiceSearcher::AttributeRequestComplete(TSdpServRecordHandle aHandle, TInt aError)
    {
    TRAPD(error,
        AttributeRequestCompleteL(aHandle, aError);
    );
    if (error != KErrNone)
        {
        Panic(EBTServiceSearcherAttributeRequestComplete);
        }
    }

void CBTServiceSearcher::AttributeRequestCompleteL(TSdpServRecordHandle /*aHandle*/, TInt aError)
    {
    if (aError != KErrNone)
        {        
        }
    else if (!HasFinishedSearching())
        {
        // have not found a suitable record so request another
        iAgent->NextRecordRequestL();
        }
    else
        {        
        Finished();
        }
    }

void CBTServiceSearcher::Finished(TInt aError /* default = KErrNone */)
    {
    if (aError == KErrNone && !HasFoundService())
        {
        aError = KErrNotFound;
        }
    User::RequestComplete(iStatusObserver, aError);
    }

TBool CBTServiceSearcher::HasFinishedSearching() const
    {
    return EFalse;
    }

const TBTDevAddr& CBTServiceSearcher::BTDevAddr()
    {
    return iResponse().BDAddr();
    }

const TBTDeviceResponseParams& CBTServiceSearcher::ResponseParams()
    {
    return iResponse();
    }

TBool CBTServiceSearcher::HasFoundService() const
    {
    return iHasFoundService;
    }
