// Looks up the name of the device with the given address.
// Arguments:
//  - wantedAddr - address of the device to look up. Note that the address 
//    is expected without colons!! e.g. "000D9319C868"
//  - aDeviceName - the object to hold the name once it is found
//  - ignoreCache - if True, performs a remote name request even if the device
//    name is known in the cache from a previous request.
//
// Returns an error code.
static TInt LookupName(TBTDevAddr& wantedAddr, THostName* aDeviceName, 
    bool ignoreCache)
{
    TInt err = KErrNone;
    RSocketServ socketServer;
    RHostResolver hostResolver;
    TRequestStatus status; 
    TNameEntry nameEntry;        
    
    // make a TInquirySockAddr with the address of the device we want to look up
    TBTSockAddr sockAddr;
    sockAddr.SetBTAddr(wantedAddr);
    TInquirySockAddr addr = addr.Cast(sockAddr);
    
    // connect 
    err = socketServer.Connect();
    if (err) 
        return err;    
        
    // load protocol for discovery
	TProtocolDesc protocolDesc;
	err = socketServer.FindProtocol(_L("BTLinkManager"), protocolDesc);
	if (!err) { 
        
        // initialize host resolver
        err = hostResolver.Open(socketServer, protocolDesc.iAddrFamily, protocolDesc.iProtocol);
    	if (!err) {
        	            
        	// Request name lookup.
        	// We don't need to call SetIAC() if we're just doing name lookup.
        	// Don't put KHostResInquiry flag in SetAction(), because that
        	// will start a device inquiry, when we just want to find the one 
        	// name.
        	if (ignoreCache) {
        	    addr.SetAction(KHostResName|KHostResIgnoreCache);
	        } else {
    	        addr.SetAction(KHostResName);
	        }
        	
        	hostResolver.GetByAddress(addr, nameEntry, status);
        	
        	User::WaitForRequest(status);
        	
            if (status == KErrNone) {
                *aDeviceName = nameEntry().iName;
                err = KErrNone;
            } else {
                err = KErrGeneral;
            }
            
            hostResolver.Close();
        }
    }
    
    socketServer.Close();
    
    return err; 
}
void CGpsDataHandler::ResolveAndConnectL() {
	TInt aResult;

#ifndef __SERIES60_3X__

	if((aResult = iSocketServ.Connect()) == KErrNone) {
		if(iGpsDeviceResolved) {
			if((aResult = iSocket.Open(iSocketServ, KBTAddrFamily, KSockStream, KRFCOMM)) == KErrNone) {
				iEngineStatus = EGpsConnecting;

				iSocket.Connect(iBTAddr, iStatus);
				SetActive();
			}
		}
		else {
			_LIT(KLinkMan, "BTLinkManager");
			//_LIT(KLinkMan, "RFCOMM");
			TProtocolName aProtocolName(KLinkMan);

			if((aResult = iSocketServ.FindProtocol(aProtocolName, iProtocolDesc)) == KErrNone) {
				if((aResult = iResolver.Open(iSocketServ, iProtocolDesc.iAddrFamily, iProtocolDesc.iProtocol)) == KErrNone) {
					TInquirySockAddr aInquiry;
					aInquiry.SetIAC(KGIAC);
					//aInquiry.SetMajorServiceClass(EMajorServicePositioning);
					aInquiry.SetAction(KHostResName | KHostResInquiry | KHostResIgnoreCache);
					iResolver.GetByAddress(aInquiry, iNameEntry, iStatus);

					iEngineStatus = EGpsResolving;
					SetActive();
				}
			}
		}
	}

	if(aResult != KErrNone) {
		iEngineStatus = EGpsDisconnected;
		iSocketServ.Close();
		iObserver->GpsError(EGpsConnectionFailed);
	}
#else
	TBool aDeviceFound = false;

	if((aResult = iPositionServ.Connect()) == KErrNone) {
		iEngineStatus = EGpsConnecting;
		TUint aNumOfModules;

		if((aResult = iPositionServ.GetNumModules(aNumOfModules)) == KErrNone) {
			TPositionModuleInfo aModuleInfo;
			TUid aModuleId;
			
			for(TUint i = 0; i < aNumOfModules && aResult == KErrNone && !aDeviceFound; i++) {
				if((aResult = iPositionServ.GetModuleInfoByIndex(i, aModuleInfo)) == KErrNone) {
					aModuleId = aModuleInfo.ModuleId();
					
					if(aModuleInfo.IsAvailable() && aModuleInfo.TechnologyType() != TPositionModuleInfo::ETechnologyNetwork) {
						aDeviceFound = true;
					}
				}
			}

			if(aResult == KErrNone && aDeviceFound) {
				if((aResult = iPositioner.Open(iPositionServ, aModuleId)) == KErrNone) {
					iEngineStatus = EGpsConnected;

					if((aResult = iPositioner.SetRequestor(CRequestor::ERequestorService, CRequestor::EFormatApplication, _L("Buddycloud"))) == KErrNone) {
						iEngineStatus = EGpsReading;
						
						TPositionUpdateOptions aOptions;
						aOptions.SetAcceptPartialUpdates(true);				
						iPositioner.SetUpdateOptions(aOptions);	
						
						iPositioner.NotifyPositionUpdate(iPositionInfo, iStatus);
						SetActive();
					}

					if(aResult != KErrNone) {
						iPositioner.Close();
					}
				}
			}
		}
	}

	if(aResult != KErrNone || !aDeviceFound) {
		iEngineStatus = EGpsDisconnected;
		iPositionServ.Close();
		iObserver->GpsError(EGpsConnectionFailed);
	}
#endif
}
void CGpsDataHandler::RunL() {
#ifndef __SERIES60_3X__
	TPtr8 pBuffer = iBuffer->Des();

	THostName aHostName;
	TInquirySockAddr aInquiry;
	TInt aServiceClass;

	switch(iEngineStatus) {
		case EGpsResolving:
			if(iStatus == KErrNone) {
				// Next device found
				aHostName = iNameEntry().iName;

				aInquiry = TInquirySockAddr::Cast(iNameEntry().iAddr);
				aServiceClass = aInquiry.MajorServiceClass();
				iBTAddr.SetBTAddr(aInquiry.BTAddr());
				iBTAddr.SetPort(1);

				if(aServiceClass & 0x08 || aHostName.Find(_L("GPS")) != KErrNotFound || aHostName.Find(_L("gps")) != KErrNotFound) {
					// Found Positioning device
					if(iSocket.Open(iSocketServ, KBTAddrFamily, KSockStream, KRFCOMM) == KErrNone) {
						iEngineStatus = EGpsConnecting;
						//iResolver.Close();

						iSocket.Connect(iBTAddr, iStatus);
						SetActive();
					}
					else {
						iSocketServ.Close();
						iEngineStatus = EGpsDisconnected;
						iObserver->GpsError(EGpsConnectionFailed);
					}
				}
				else {
					// Get next
					iResolver.Next(iNameEntry, iStatus);
    				SetActive();
				}

				// TODO - Is correct device?

			}
			else if(iStatus == KErrHostResNoMoreResults) {
				// No (more) devices found
				iSocketServ.Close();
				iEngineStatus = EGpsDisconnected;
				iGpsDeviceResolved = false;
				iObserver->GpsError(EGpsDeviceUnavailable);
			}
			else {
				iSocketServ.Close();
				iEngineStatus = EGpsDisconnected;
				iObserver->GpsError(EGpsDeviceUnavailable);
			}
			break;
		case EGpsConnecting:
			if(iStatus == KErrNone) {
				iEngineStatus = EGpsReading;
				iGpsDeviceResolved = true;
				iResolver.Close();

				pBuffer.Zero();

				iSocket.Recv(iChar, 0, iStatus);
				SetActive();
			}
			else {
				if(iGpsDeviceResolved) {
					iSocket.Close();
					iSocketServ.Close();
					iEngineStatus = EGpsDisconnected;
					iObserver->GpsError(EGpsConnectionFailed);
				}
				else {
					// Get next
					iEngineStatus = EGpsResolving;
					iResolver.Next(iNameEntry, iStatus);
					SetActive();
				}
			}
			break;
		case EGpsReading:
			if(iStatus == KErrNone) {
				iEngineStatus = EGpsConnected;

				if(pBuffer.Length() + iChar.Length() > pBuffer.MaxLength()) {
					iBuffer = iBuffer->ReAlloc(pBuffer.MaxLength()+iChar.Length());
					pBuffer.Set(iBuffer->Des());
				}

				pBuffer.Append(iChar);
				ProcessData();
			}
			else {
				iSocket.Close();
				iSocketServ.Close();
				iEngineStatus = EGpsDisconnected;
				iObserver->GpsError(EGpsConnectionFailed);
			}
			break;
		case EGpsDisconnecting:
			iResolver.Close();
			iSocket.Close();
			iSocketServ.Close();
			iEngineStatus = EGpsDisconnected;
			break;
		default:;
	}
#else
	switch(iEngineStatus) {
		case EGpsReading:
			iEngineStatus = EGpsConnected;
			
			if(iStatus == KErrNone) {
				TPosition aPosition;
				iPositionInfo.GetPosition(aPosition);

				iObserver->GpsData(aPosition.Latitude(), aPosition.Longitude(), aPosition.HorizontalAccuracy());
				
				if( !iGpsWarmedUp ) {
					iGpsWarmedUp = true;
					
					TPositionUpdateOptions aOptions;
					aOptions.SetUpdateTimeOut(30000000);	
					aOptions.SetAcceptPartialUpdates(true);
					iPositioner.SetUpdateOptions(aOptions);
				}
			}
			else {
				iObserver->GpsError(EGpsDeviceUnavailable);
			}
			break;
		case EGpsDisconnecting:
			iPositioner.Close();
			iPositionServ.Close();
			iEngineStatus = EGpsDisconnected;
			break;
		default:;
	}
#endif
}
// Performs a device discovery. Blocks until all devices are found.
// Arguments:
//  - aDevDataList - details of each found device will be put in a TDeviceData
//    and added to this list
//  - lookupNames - whether to perform name lookups
//
// Returns an error code.
static TInt DiscoverDevices(TDeviceDataList* aDevDataList, bool lookupNames) 
{
    TInt err = KErrNone;
    RSocketServ socketServer;
    RHostResolver hostResolver;
    TInquirySockAddr addr;
    TRequestStatus status; 
    TNameEntry nameEntry;
        
    // connect 
    err = socketServer.Connect();
    if (err) 
        return err;
    
    // load protocol for discovery
	TProtocolDesc protocolDesc;
	err = socketServer.FindProtocol(_L("BTLinkManager"), protocolDesc);
	if (!err) { 
        
        // initialize host resolver
        err = hostResolver.Open(socketServer, protocolDesc.iAddrFamily, protocolDesc.iProtocol);
    	if (!err) {
        	
        	// start device discovery by invoking remote address lookup
        	addr.SetIAC(KGIAC);
        	if (lookupNames) {
        	    addr.SetAction(KHostResInquiry|KHostResName|KHostResIgnoreCache);
    	    } else {
        	    addr.SetAction(KHostResInquiry|KHostResIgnoreCache);
    	    }     
                    	
        	hostResolver.GetByAddress(addr, nameEntry, status);        	        	

            while( User::WaitForRequest( status ), 
                    (status == KErrNone || status == KRequestPending) )
            {                
        		// store new device data entry
        		TDeviceData *devData = new (ELeave) TDeviceData();
        		if (lookupNames) 
        		    devData->iDeviceName = nameEntry().iName;
        		    
        		devData->iDeviceAddr = 
        			static_cast<TBTSockAddr>(nameEntry().iAddr).BTAddr();
        			
                TInquirySockAddr &isa = TInquirySockAddr::Cast(nameEntry().iAddr);	
        		devData->iServiceClass = (TInt16)isa.MajorServiceClass();		
                devData->iMajorClass = (TInt8)isa.MajorClassOfDevice();
                devData->iMinorClass = (TInt8)isa.MinorClassOfDevice();
        		
        		// add device data entry to list
        		aDevDataList->Append(devData);        
        		
                // get next discovered device
                hostResolver.Next( nameEntry, status );
            }	
            
            hostResolver.Close();
        }
    }
    
    socketServer.Close();
    
    return err;
}