locationtriggering/ltstrategyengine/src/lbtcoordinatesupervisor.cpp
author Pat Downey <patd@symbian.org>
Wed, 01 Sep 2010 12:24:21 +0100
branchRCL_3
changeset 45 6b6920c56e2f
parent 44 2b4ea9893b66
permissions -rw-r--r--
Revert incorrect RCL_3 drop: Revision: 201033 Kit: 201035

/*
* Copyright (c) 2008 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:  Implementation of coordinate supervisor class
*
*/



#include <e32math.h>
#include <e32const.h>
#include <lbttriggerconditionarea.h>
#include <lbtgeocircle.h>
#include "lbtcelliddatabase.h"
#include "lbtcellchangehandler.h"
#include "lbtlogger.h"
#include "lbtcoordinatesupervisor.h"
#include "lbtstrategyengineobserver.h"
#include "lbtpsychangelistner.h"

// ==================== CONSTANTS ===================================

/**
 * Constant used to adjust trigger radius to accomodate inaccuracy 
 * of position fixes
 */
static const TReal32 KAccuracyMultiplier = 0.666667;

/**
 * The cut off value of the ratio of radius to position accuracy. Over this 
 * value the radius of a trigger will not be expanded.
 */
static const TReal32 KCofftOfHighEdgeLimit = 1.5;

/**
 * Constant used in calculation of trigger hysteresis
 */
static const TUint16 KTriggerRadiusCutoff = 500;

/**
 *  Contant time use in calculation of speed
 */
static const TReal32 constantTime = 20;

/**
 * Defines the number of historic speed values that will be stored
 * and used for calculation of current speed
 */
static const TUint16 maxObsValues = 10;

/**
 * Minimum calculated speed. If this calculated speed drops below this value
 * then the below value is speed as the speed value 
 */
static const TReal KMinProjSpeed = 20.0;

static const TReal KMaxSpeedToUseMvmtDet = 5.0;
/**
 * If the estimated sleep interval goes below this value then location request
 * will be issued immediately with the estimated interval as the time out value
 * for the location rquest
 */
static const TInt KMinSleepInterval = 2;

/**
 * Multiplier used for 10 power 3. Used for conversion of seconds to micro
 * seconds
 */
static const TUint KMicroMultiplier = 1000000;

/**
 * Number of seconds to sleep before making location request in cases where 
 * a location acquisition attempt fails to obtain a fix
 */
static const TUint KSleepTimeOnLocAcqFailure = 10; // 10 seconds

/**
 * Safe range of HA obtained from NPP
 */
//static const TUint KNppSafeHA = 1500; // 1500 meters

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

// -----------------------------------------------------------------------------
// CLbtCoOrdinateSupervisor::NewL
// CLbtCoOrdinateSupervisor instantiation method
// -----------------------------------------------------------------------------
//
CLbtCoOrdinateSupervisor* CLbtCoOrdinateSupervisor::NewL( TAny* aConstructionParameters, 
                                                          CLbtTriggerView* aView,
                                                          MLbtStrategyEngineObsrvr* aObserver,
                                                          CLbtCellChangeHandler* aCellChangeHandler )
    {
    CLbtCoOrdinateSupervisor* self = new ( ELeave ) CLbtCoOrdinateSupervisor();
    CleanupStack::PushL( self );
    self->ConstructL( aConstructionParameters, aView,aObserver,aCellChangeHandler );
    CleanupStack::Pop();
    return self;    
    }


// -----------------------------------------------------------------------------
// CLbtCoOrdinateSupervisor::~CLbtCoOrdinateSupervisor
// Default destructor
// -----------------------------------------------------------------------------
//
CLbtCoOrdinateSupervisor::~CLbtCoOrdinateSupervisor()
    {
    // This is just done as a precautionary measure!
    StopSupervision();
    delete iLocationRequestor;
    delete iStatusManager;
    delete iTimer;
    delete iPsyChangeListner;
    delete iCellIdDatabase;
    iNObservedValues.Close();
    iNearestTriggers.Close();
    }	


// -----------------------------------------------------------------------------
// CLbtCoOrdinateSupervisor::StartSupervision
// 
// -----------------------------------------------------------------------------
//
void CLbtCoOrdinateSupervisor::StartSupervision()
    {
    FUNC_ENTER("CLbtCoOrdinateSupervisor::StartSupervision");
    iCellChangeHandler->SetObserver( this );    
    RequestTerminalPosition( iSettings.iLocationRequestTimeout );    
    }

    
// -----------------------------------------------------------------------------
// CLbtCoOrdinateSupervisor::StopSupervision
// 
// -----------------------------------------------------------------------------
//
void CLbtCoOrdinateSupervisor::StopSupervision()
    {
    FUNC_ENTER("CLbtCoOrdinateSupervisor::StopSupervision");
    iCellChangeHandler->Remove( this );
    Term(); 
    }
    

// -----------------------------------------------------------------------------
// CLbtCoOrdinateSupervisor::SettingsChanged
// Handles notification of triggering settings change provided by server
// -----------------------------------------------------------------------------
//
void CLbtCoOrdinateSupervisor::SettingsChanged()
    {    
    iEngObserver->RetrieveTriggeringSettings( iSettings );    
    }


// -----------------------------------------------------------------------------
// CLbtCoOrdinateSupervisor::Resume

// -----------------------------------------------------------------------------
//
void CLbtCoOrdinateSupervisor::Resume()
    {
    FUNC_ENTER("CLbtCoOrdinateSupervisor::Resume");
    TInt err = KErrNone;
    iCellChangeHandler->SetObserver( this );    

    switch( iProjectedState )
            {
        case ELocationAcquisition:
            iProjectedState = EIdle;
            RequestTerminalPosition( iSettings.iLocationRequestTimeout );
            break;

        case ETriggerEvaluation:
            // Reset trigger iterator and start evaluation of all triggers in
            // view            
            iProjectedState = EIdle;
            err = ResetViewIterator();
            if( KErrNone != err )
                {
                return;
                }
            iState = ETriggerEvaluation;
            SetEvent();
            break;
            
        case EUpdateIntervalEstimation:

            // Evaluate triggers that have undergone changes during the state
            // change. This is to determine any new nearest trigger
            iProjectedState = EIdle;


            iView->DetermineNearestTriggerChanges( &iNearestTriggers );
            if( iNearestTriggers.Count() == 0 )
                {
                // This means all known nearest triggers have been modified. 
                // Reset iterator re-evaluate all triggers in the system. 
                TInt err = ResetViewIterator();
                if( KErrNone != err )
                    {
                    return;
                    }
                
                iState = ETriggerEvaluation;
                SetEvent();
                }
            else
                {
                // Evaluate only the modified triggers
                TBool makeLocReq = EFalse;
                TRAP( err, makeLocReq = EvaluateModifiedTriggersL() );
                if( KErrNone == err )
                    {
                    if( makeLocReq )
                    	{
                    	// Location request is needed based on evaluating
            			// modified triggers
                    	RequestTerminalPosition( iSettings.iLocationRequestTimeout );
                    	return;
                    	}
                    // Switch to estimation of update interval
                    iState = EUpdateIntervalEstimation;
                    SetEvent();
                    }
                else
                    {
                    Term();
                    }
                }
            break;

        case ESleep:
            iProjectedState = EIdle;
            iState = ESleep;
            SetEvent();
            break;
            
        case EIdle:
            if( EIdle == iState && EIdle == iProjectedState
                           && iView->CoordTriggerCount() )
                {
                RequestTerminalPosition( iSettings.iLocationRequestTimeout );
                }
            break;
            
        default:
            break;
            }
     }


// -----------------------------------------------------------------------------
// CLbtCoOrdinateSupervisor::Suspend
// -----------------------------------------------------------------------------
//
void CLbtCoOrdinateSupervisor::Suspend()
    {
    FUNC_ENTER("CLbtCoOrdinateSupervisor::Suspend");
    iCellChangeHandler->Remove( this );
    switch( iState )
        {
    case ELocationAcquisition:
    	if( iLastLocationFixType == EProperFix )
    		{
    		iLocationRequestor->Cancel();
    		}
    	else
    		{
    		iLocationRequestor->CancelFixFromNpp();
    		}
    	
        iProjectedState = iState;
        iState = EIdle;
        break;
        
    case ETriggerEvaluation:
        iProjectedState = ETriggerEvaluation;
        iState = EIdle;
        break;
        
    case EUpdateIntervalEstimation:
        iProjectedState = EUpdateIntervalEstimation;
        iState = EIdle;
        break;
        
    case ESleep:
        iTimer->Cancel();
        iProjectedState = iState;
        iState = EIdle;
                
    case EIdle:
        break;
        
    default:
        break;
        }
    
    Cancel();
    }
    

// -----------------------------------------------------------------------------
// CLbtCoOrdinateSupervisor::Reset
// -----------------------------------------------------------------------------
//
void CLbtCoOrdinateSupervisor::Reset()
    {
    iState = iProjectedState = EIdle;
    iNearestTriggers.Reset();
    iLocReqCount = 0;
    TPositionInfo posInfo;
    iPosInfo = posInfo;
    iFixForFiringCloseTriggers = EFalse;
    }


// -----------------------------------------------------------------------------
// CLbtCoOrdinateSupervisor::GetPositionInfo
// Processes the location information obtained from location requestor
// -----------------------------------------------------------------------------
//
void CLbtCoOrdinateSupervisor::GetPositionInfoL()
    {
    FUNC_ENTER("CLbtCoOrdinateSupervisor::GetPositionInfo");
    
    // Update location acquisition status information
    
    if( !( (KErrNone == iStatus.Int()) ||
    	   (KPositionQualityLoss == iStatus.Int()) ) )
    	{
    	ERROR("Position Information with : %d",iStatus.Int());
    	iStatusManager->ReportLocationAcquisitionStatus( iStatus.Int() );
    	    	
    	// The following check determines if there was a problem using the 
    	// specified positioning technology to retrieve position information
    	if( KErrNotFound == iStatus.Int() &&
    	    iLastLocationFixType == EProperFix )
    	    {
    	    LOG("Specified PSY not found");
    	    iAcquisitionStatus = ELocationAcquisitionNoMethod;
    	    
    	    if( iPsyChangeListner == NULL )
    	        {
    	        iPsyChangeListner = CLbtPsyChangeListner::NewL( *this );
    	        }
    	    iPsyChangeListner->StartToListen( iModuleId );
    	    LOG1("Listen to PSY change:%x",iModuleId);
    	    TUid defaultID = { 0XFFFFFFFF };
    	    if( iLocationRequestor->GetPositionModuleId() != defaultID )
    	        {
    	        LOG("Use default proxy");
    	        // switch to using default positioning technology
    	        iModuleId = defaultID;
    	        RequestTerminalPosition( iSettings.iLocationRequestTimeout,EProperFix );   
    	        }
    	    }
    	else
    	    {
    	    LOG("Location acquisition failed");
    	    if( iFixForFiringCloseTriggers && 
    	        (KErrTimedOut == iStatus.Int())&&
    	        iLastLocationFixType == EProperFix )
    	        {
    	        LOG("Firing Close triggers");
                FireClosestTriggers();                
                RequestTerminalPosition(iSettings.iLocationRequestTimeout, EProperFix);
                }
            else
                {
                if( iLastLocationFixType == EProperFix )
                    {
                    // Get fix from NPP PSY
                    LOG("Timed Out. Taking fix from NPP");
                    RequestTerminalPosition( iSettings.iLocationRequestTimeout, EFixFromNpp );
                    return;
                    
                    /*
                    iState = ESleep;
                    iTimer->Set( iStatus, KSleepTimeOnLocAcqFailure, ETrue );               
                    SetActive();

                    if( KErrAccessDenied == iStatus.Int() )
                        {
                        iAcquisitionStatus = ELocationAcquisitionPrivacyReject;
                        }
                    else 
                        {
                        iAcquisitionStatus = ELocationAcquisitionFailure;
                        }*/
                    }
                else
                    {
                    LOG("Npp psy failed to provide fix. Sleep now");
                    iState = ESleep;
                    iTimer->Set( iStatus, KSleepTimeOnLocAcqFailure, ETrue );               
                    SetActive();

                    if( KErrAccessDenied == iStatus.Int() )
                        {
                        iAcquisitionStatus = ELocationAcquisitionPrivacyReject;
                        }
                    else 
                        {
                        iAcquisitionStatus = ELocationAcquisitionFailure;
                        }
                    }
                }
    	    }

    	if( iFixForFiringCloseTriggers )
    	    {
    	    iFixForFiringCloseTriggers = EFalse;
    	    }

    	// Update supervision dynamic info to the strategy class
        TLbtStrategySupervisionDynamicInfo supervisionDynamicInfo;
        supervisionDynamicInfo.iDistanceToNearestTrigger = 0.0;
        supervisionDynamicInfo.iLatestAcquiredPosInfo = iPosInfo;
        supervisionDynamicInfo.iLocationAcquisitionStatus = iAcquisitionStatus;
        supervisionDynamicInfo.iNearestTriggerId = 0;
    
        iEngObserver->ReportTriggeringSupervisionStatus( supervisionDynamicInfo );    
    	return;
    	}

	if( iStatus.Int() == KPositionQualityLoss )
		{
		TPosition currentPosition;
		iPosInfo.GetPosition( currentPosition );
		LOG("Received KPositionQualityLoss");
		LOG1("Lat:%f",currentPosition.Latitude());
		LOG1("Long:%f",currentPosition.Longitude());
		LOG1("HA:%f",currentPosition.HorizontalAccuracy());
		}
    		
    iStatusManager->ReportLocationAcquisitionStatus( KErrNone );
    // The fix was taken to fire nearest triggers then reset the flag
    // to EFalse since the fix was successful and the nearest triggers will be
    // evaluated and will be fired
    if(iFixForFiringCloseTriggers)
        {
        iFixForFiringCloseTriggers = EFalse;
        }
    
    TPosition currentPosition, prevPosition;
    iPosInfo.GetPosition( currentPosition );
    iPrevPosInfo.GetPosition( prevPosition );
    
    if( Math::IsNaN( currentPosition.Latitude() ) || 
        Math::IsNaN( currentPosition.Longitude() ) )
    	{
    	LOG("ERROR:Lat/Long is Nan. Sleep now");
    	iState = ESleep;
        iTimer->Set( iStatus, KSleepTimeOnLocAcqFailure, ETrue );               
        SetActive();

        if( KErrAccessDenied == iStatus.Int() )
            {
            iAcquisitionStatus = ELocationAcquisitionPrivacyReject;
            }
        else 
            {
            iAcquisitionStatus = ELocationAcquisitionFailure;
            }
    	return;
    	}
    
    // Record the time at which we got the fix
    iLastFixTime.UniversalTime();
    
    // Take note of reference time that would be used during estimation of 
    // sleep interval
    iAcquisitionStatus = ELocationAcquisitionActive;
    
    iLocReqCount++;
    iLocationRequestor->GetModuleInfo( iPosInfo.ModuleId() );    
        
    if( iLocArea.iCellId && iLastCellRequestStatus == KErrNone )
        {
        LOG("Writing position to DB");
        LOG1("Cell Id = %d", iLocArea.iCellId );
        LOG1("LAC = %d", iLocArea.iLocationAreaCode );
        // Add current cell id position to cell-id database
        TInt countryCode,networkCode;
        
        TLex lex( iNwInfo.iCountryCode );
        lex.Val( countryCode );
        
        lex.Assign( iNwInfo.iNetworkId );
        lex.Val( networkCode );
        
        TPosition cellPosition;
        iPosInfo.GetPosition( cellPosition );
        if( iLastLocationFixType == EProperFix )
            {
            cellPosition.SetHorizontalAccuracy( 3000 );
            }
        
        iCellIdDatabase->InsertCidLocation( countryCode,
                                            networkCode,
                                            iLocArea.iLocationAreaCode,
                                            iLocArea.iCellId,
                                            cellPosition );
        }
    
    // Check if there is no movement from last location fix. If true then 
    // re-evaluate sleep interval
    TReal32 dist;
    currentPosition.Distance( prevPosition, dist );
    if( dist == 0 )
        {
        iState = EUpdateIntervalEstimation;
        SetEvent();
        }
    
    LOG1("Lat:%f",currentPosition.Latitude());
	LOG1("Long:%f",currentPosition.Longitude());
	LOG1("HA:%f",currentPosition.HorizontalAccuracy());
    
    // Switch to idle state as refresh is an async operation. Set projected 
    // state to trigger evaluation which will commence once the refresh 
    // operation is complete
    iState = ETriggerEvaluation;
    SetEvent();

    }


// -----------------------------------------------------------------------------
// CLbtCoOrdinateSupervisor::EvaluateTriggersL
// Evaluates triggers based on the location information obtained 
// -----------------------------------------------------------------------------
//
void CLbtCoOrdinateSupervisor::EvaluateTriggersL()
    {
    FUNC_ENTER("CLbtCoOrdinateSupervisor::EvaluateTriggersL");
    
    // Reset nearest trigger array
    iNearestTriggers.Reset();
    
    // TODO: In case of updates to trigger information do not change state
    //       else change state to EUpdateIntervalEstimation
    CLbtContainerTriggerEntry* conTrigger;
    
    // ResetViewIterator will switch state to Idle if there are no triggers in 
    // the system
    if( KErrNone != ResetViewIterator() )
        {
        return;
        }

    while( iViewIterator.NextL( conTrigger ) )
        {
        if( conTrigger )    
            {
            CLbtTriggerEntry* trigger = conTrigger->TriggerEntry();
            if( CLbtTriggerConditionBase::ETriggerConditionArea == 
                                                trigger->GetCondition()->Type() )
                {
                // Area type trigger
                CLbtTriggerConditionArea* triggerConArea = 
                                        static_cast< CLbtTriggerConditionArea* >
                                                ( trigger->GetCondition() );
                   
                switch( triggerConArea->TriggerArea()->Type() )
                    {
                	// Circular area
                	case CLbtGeoAreaBase::ECircle:
                		{
                		if( iLastLocationFixType == EProperFix )
                            {
                            EvalCircularTriggerL( conTrigger );
                            }
                        else if( iLastLocationFixType == EFixFromDb || iLastLocationFixType == EFixFromNpp )
                            {
                            if( EvalCircularTriggerBasedOnCellPositionL( conTrigger ) )
                                {
                                if( iLastLocationFixType == EFixFromNpp )
                                	{
                                	// Fix is taken from NPP only when Proper Fix fails. Now we should
                                	// sleep for location acquisition failure time our period since there is no point
                                	// in attempting another proper fix
                                	iState = ESleep;
				                    iTimer->Set( iStatus, KSleepTimeOnLocAcqFailure, ETrue );               
				                    SetActive();

				                    if( KErrAccessDenied == iStatus.Int() )
				                        {
				                        iAcquisitionStatus = ELocationAcquisitionPrivacyReject;
				                        }
				                    else 
				                        {
				                        iAcquisitionStatus = ELocationAcquisitionFailure;
				                        }
                                	}
                                else
                                	{
                                	RequestTerminalPosition( iSettings.iLocationRequestTimeout,EProperFix );
                                	}                                
                                return;
                                }
                            }                            
                    	break;
                		}                    
                	default:
                    	break;
                    }
                }
            }
        }
        
    // Update supervision dynamic info to the strategy class
    TLbtStrategySupervisionDynamicInfo supervisionDynamicInfo;
    if( iNearestTriggers.Count() )
        {
        supervisionDynamicInfo.iDistanceToNearestTrigger = iNearestTriggers[0].distance;
        supervisionDynamicInfo.iNearestTriggerId = iNearestTriggers[0].id;
        }
    supervisionDynamicInfo.iLatestAcquiredPosInfo = iPosInfo;
    supervisionDynamicInfo.iLocationAcquisitionStatus = iAcquisitionStatus;
    
    
    iEngObserver->ReportTriggeringSupervisionStatus( supervisionDynamicInfo );
    
    iState = EUpdateIntervalEstimation;
    SetEvent();
    }
    

// -----------------------------------------------------------------------------
// CLbtCoOrdinateSupervisor::EvaluateTriggers
// Evaluates triggers based on the location information obtained 
// -----------------------------------------------------------------------------
//
TBool CLbtCoOrdinateSupervisor::EvaluateModifiedTriggersL()
    {
    FUNC_ENTER("CLbtCoOrdinateSupervisor::EvaluateModifiedTriggersL");
    
    // Retrieve modified trigger list from trigger view to be supervised
    RArray< TLbtTriggerId > modifiedTriggers;
    iView->GetModifiedTriggers( modifiedTriggers );
    CleanupClosePushL( modifiedTriggers );
    if( modifiedTriggers.Count() )
        {
        // TODO: Need to check for the deletion of
        // Create an iterator to parse through the modified trigger list
        CLbtTriggerView::TTriggerViewIter iter = iView->Begin( &modifiedTriggers, CLbtGeoAreaBase::ECircle );        
        
        CLbtContainerTriggerEntry* conTrigger;
        while( iter.NextL( conTrigger ) )
            {
            if( conTrigger )
                {
                CLbtTriggerEntry* trigger = conTrigger->TriggerEntry();
                if( CLbtTriggerConditionBase::ETriggerConditionArea == 
                                                    trigger->GetCondition()->Type() )
                    {
                    // Area type trigger
                    CLbtTriggerConditionArea* triggerConArea = 
                                            static_cast< CLbtTriggerConditionArea* >
                                                    ( trigger->GetCondition() );
                       
                    switch( triggerConArea->TriggerArea()->Type() )
                        {
	                    // Circular area
	                    case CLbtGeoAreaBase::ECircle:
	                        if( iLastLocationFixType == EProperFix )
	                            {
	                            EvalCircularTriggerL( conTrigger );
	                            }
	                        else if( iLastLocationFixType == EFixFromDb || iLastLocationFixType == EFixFromNpp )
	                            {
	                            if( EvalCircularTriggerBasedOnCellPositionL( conTrigger ) )
	                                {
	                                CleanupStack::PopAndDestroy();  // modifiedTriggers
	                                return ETrue;
	                                }
	                            }
	                        break; 
	                        
	                    default:
	                        break;
                        }
                    }
                }
            }        
        }
        
    CleanupStack::PopAndDestroy();  // modifiedTriggers
    return EFalse;
    }
    

// -----------------------------------------------------------------------------
// CLbtCoOrdinateSupervisor::EvalCircularTrigger
// Evaluates triggers with circular area definition
// -----------------------------------------------------------------------------
//
void CLbtCoOrdinateSupervisor::EvalCircularTriggerL( 
                                          CLbtContainerTriggerEntry* aTrigger )
    {
    FUNC_ENTER("CLbtCoOrdinateSupervisor::EvalCircularTrigger");
    
    
    // Extract strategy data
    TStrategyData strategyData = aTrigger->StrategyData();                                          
    
    TInt remRearmTime = 0;
    TReal distanceToLatestLocation = 0.0;
    TBool hasRearmTimeExpired = ETrue;
    
    LOGSTRING("Trigger: \"%S\" ", &(aTrigger->TriggerEntry()->Name()));
        
    if( strategyData.iFireTime )
        {
        TTime triggerFiredTime( strategyData.iFireTime );

        TTime currentTime;
        currentTime.UniversalTime();
        
        TTimeIntervalSeconds interval;
        currentTime.SecondsFrom( triggerFiredTime, interval );
        
        remRearmTime = aTrigger->TriggerEntry()->TimeToRearm() - interval.Int();
        
        
        if( remRearmTime <= 0 )
            {
            remRearmTime = 0;
            strategyData.iFireTime = 0;
            }
        else
        	{
        	LOG("Rearm Time has not expired");
        	hasRearmTimeExpired = EFalse;
        	}
        }
        
    CLbtTriggerConditionArea* trgCondition = 
                              static_cast< CLbtTriggerConditionArea* >
                              ( ( aTrigger->TriggerEntry() )->GetCondition() );
    
    CLbtGeoCircle* circularArea = static_cast< CLbtGeoCircle* >
                                               ( trgCondition->TriggerArea() );

    // Calculate distance of trigger from current location
    TReal32 distanceToCenter;
    TPosition currentPosition;
    iPosInfo.GetPosition( currentPosition );
    TInt err = currentPosition.Distance( circularArea->Center(), 
                                         distanceToCenter );
    if( KErrNone != err )
        {
        ERROR("Error in calculating distance:%d",err);
        LOG1("Current Lat:%f",currentPosition.Latitude());
	    LOG1("Current Long:%f",currentPosition.Longitude());   
	    LOG1("Trigger Lat:%f",circularArea->Center().Latitude());   
	    LOG1("Trigger Long:%f",circularArea->Center().Longitude());
        return;
        }

    // Determine trigger radius and hysteresis radius to be used for supervision
    // based on the accuracy of location fix
    TTriggerArea triggerArea;
    TReal positionAccuracy = currentPosition.HorizontalAccuracy();    
    triggerArea = EstimateTriggerRadii( circularArea->Radius(), 
                    aTrigger->ExtendedTriggerInfo()->HysteresisRadius(), 
                        positionAccuracy );
    
    // ENTRY Trigger
    // Determine current position of terminal relative to the trigger area and 
    // set trigger fire status accordingly
    if( CLbtTriggerConditionArea::EFireOnEnter == trgCondition->Direction() )
        {
        TLbtTriggerDataMask dataMask = 0;
        
        TReal tolerableRadius = CalculateTolerableRadius( triggerArea.triggerRadius );
        // Terminal is inside trigger area
        if( ( distanceToCenter < tolerableRadius ) && 
            ( ( distanceToCenter + positionAccuracy ) <= triggerArea.hysteresisRadius ) )
            {
            LOG("Inside triggerin area");
            // If trigger in active state then fire trigger and set state to
            // inactive. If trigger is inactive nothing is to be done other
            // than calculating its distance from the hysteresis boundary
            if( EActive == strategyData.iActivityStatus )
                {
				LOG("Active trigger");
                // Check FireOnCreation flag here. If EFalse then dont 
                // fire the trigger. Instead only change the activity
                // status.
                if( aTrigger->ExtendedTriggerInfo()->IsTriggerFireOnCreation() &&
                    hasRearmTimeExpired )
                    {
                    // Set trigger state to fired
                    aTrigger->ExtendedTriggerInfo()->SetTriggerFiredState( ETrue );
                    TLbtTriggerFireInfo triggerFireInfo;
                    TPositionInfo positionInfo;
                    triggerFireInfo.iTriggerId = aTrigger->TriggerEntry()->Id();
                    triggerFireInfo.iFiredPositionInfo = iPosInfo;
                    
                    aTrigger->ExtendedTriggerInfo()->SetFiredInfo( triggerFireInfo );
                    
                    // Time at which trigger fired
                    TTime triggerFiredTime;
                    triggerFiredTime.UniversalTime();
                    LOG("TRIGGER FIRED");
                    
                    strategyData.iFireTime = triggerFiredTime.Int64();
                    
                    remRearmTime = aTrigger->TriggerEntry()->TimeToRearm();
                    dataMask |= 
                    CLbtContainerTriggerEntry::EContainerAttributeIsFired | 
                    CLbtContainerTriggerEntry::EContainerAttributeFireInfo ;
                    }
                
                // Set trigger to inactive state                
                strategyData.iActivityStatus = EInactive;
                }
            
            // Calculate distance to current location and update trigger's 
            // dynamic info. This distance is (rH - D) where D is the distance 
            // between the two centers and rH is the radius of the hysteresis 
            // circle. Here the radius of hysteresis boundary is considered for 
            // distance calculation as this trigger would undergo a state 
            // change only when it crosses the hysteresis area
            distanceToLatestLocation = Abs( triggerArea.hysteresisRadius - distanceToCenter );
            }
            
        // Terminal is outside hysteresis area
        else if( distanceToCenter > ( triggerArea.hysteresisRadius + positionAccuracy ) )
            {
            if( EInactive == strategyData.iActivityStatus )
                {
                // Reset trigger state to valid
                strategyData.iActivityStatus = EActive;     
                LOG("Trigger activated");
                }
                
            // Calculate distance of trigger to current location and update
            // trigger's dynamic info. This distance is (D - rT) where D is 
            // the distance between two centers and rT is the radius of trigger. 
            // State change will occur only when the terminal moves beyond the
            // boundary of the trigger
            distanceToLatestLocation = Abs( distanceToCenter - triggerArea.triggerRadius );
            }

        // Terminal is inside hysteresis area. 
        else
            {
            // Trigger does not undergo any state change in this region. Theres 
            // only distance to be determined here
            if( EActive == strategyData.iActivityStatus )
                {
                // Terminal was outside hysteresis area earlier. Distance is
                // therefore (D - rT)
                distanceToLatestLocation = Abs( distanceToCenter - triggerArea.triggerRadius );
                }
            else
                {
                // Terminal was inside trigger area earlier. Distance is
                // therefore (rH - D)
                distanceToLatestLocation = Abs( triggerArea.hysteresisRadius - distanceToCenter );
                }
            }
        
        // Set FireOnCreation flag to ETrue here if its not already
        // ETrue. This is done to ensure that the trigger is fired 
        // in the subsequent iterations if the triggering conditions
        // are satisfied.
        if( !aTrigger->ExtendedTriggerInfo()->IsTriggerFireOnCreation() )
            {
            aTrigger->ExtendedTriggerInfo()->SetTriggerFireOnCreation( ETrue );
            dataMask |= CLbtContainerTriggerEntry::EContainerAttributeIsTriggerFireOnCreation;
            }
        
        if( dataMask )
            {
            iView->UpdateTriggerInfo( CLbtGeoAreaBase::ECircle,iPosInfo, aTrigger, dataMask );            
            }
        }
        
    // EXIT Trigger
    else
        {
        TLbtTriggerDataMask dataMask = 0;
        // Retrieve boundary information of trigger
        TTriggerBoundary boundary = EUndefined;
        
        // Retrieve boundary information of trigger
        ( strategyData.iBoundaryCondition >= 0 && strategyData.iBoundaryCondition <= 2 )?boundary =
                                     TTriggerBoundary( strategyData.iBoundaryCondition ):boundary;
        
        TReal tolerableRadius = CalculateTolerableRadius( triggerArea.triggerRadius );                             
        
        // Terminal is inside trigger area
        if( ( distanceToCenter < tolerableRadius ) && 
            ( ( distanceToCenter + positionAccuracy ) <= triggerArea.hysteresisRadius ) )
            {
            // Check boundary condition to determine if the terminal has moved
            // inside the trigger area without having gone beyond the area of
            // hysteresis. In this case the trigger shall not be set as active
            if( EOutside != boundary && 
                    EInactive == strategyData.iActivityStatus )
                {
                // Set trigger state to active
                strategyData.iActivityStatus = EActive;
                }
            
            // Set boundary as Outside
            strategyData.iBoundaryCondition =  TInt( EOutside );
            
            if( EActive == strategyData.iActivityStatus )
                {
                // Set Distance to the border of trigger area. This distance is
                // (rT - D).
                distanceToLatestLocation = Abs( triggerArea.triggerRadius - distanceToCenter );
                }
            else
                {
                // Set distance to border of hysteresis area. This distance is
                // (rH - D) where rH is the radius of hysteresis and D is the 
                // distance between the center of trigger and the center of 
                // location
                distanceToLatestLocation = Abs( triggerArea.hysteresisRadius - distanceToCenter );
                }
            }
            
        // Terminal is outside hysteresis area  
        else if( ( distanceToCenter > triggerArea.hysteresisRadius )  &&
            ( distanceToCenter > ( triggerArea.triggerRadius + positionAccuracy ) ) )
            {
            if( EActive == strategyData.iActivityStatus  )
                {
                // Check FireOnCreation flag here. If EFalse then dont 
                // fire the trigger. Instead only change the activity
                // status.
                if( aTrigger->ExtendedTriggerInfo()->IsTriggerFireOnCreation() &&
                    hasRearmTimeExpired )
                    {
                    // Set trigger state to fired
                    aTrigger->ExtendedTriggerInfo()->SetTriggerFiredState( ETrue );
                    
                    TLbtTriggerFireInfo triggerFireInfo;
                    TPositionInfo positionInfo;
                    triggerFireInfo.iTriggerId = aTrigger->TriggerEntry()->Id();
                    triggerFireInfo.iFiredPositionInfo = iPosInfo;
                    
                    aTrigger->ExtendedTriggerInfo()->SetFiredInfo( triggerFireInfo );
                    
                     // Time at which trigger fired
                    TTime triggerFiredTime;
                    triggerFiredTime.UniversalTime();
                    strategyData.iFireTime = triggerFiredTime.Int64();
                    LOG("TRIGGER FIRED");
                    remRearmTime = aTrigger->TriggerEntry()->TimeToRearm();             
                    dataMask |= 
                    CLbtContainerTriggerEntry::EContainerAttributeIsFired | 
                    CLbtContainerTriggerEntry::EContainerAttributeFireInfo;
                    }
                
                // Set the trigger state to inactive
                strategyData.iActivityStatus = EInactive;
                
                }

            // Set boundary as Inside
            strategyData.iBoundaryCondition = TInt( EInside );
            
            // Calculate distance to border of trigger area. This distance
            // is (D - rT)
            distanceToLatestLocation = Abs( distanceToCenter - triggerArea.triggerRadius );
            }
        
        // Terminal is inside hysteresis area
        else
            {
            if( EOutside == boundary && EActive == strategyData.iActivityStatus )
                {
                // Check FireOnCreation flag here. If EFalse then dont 
                // fire the trigger. Instead only change the activity
                // status.
                if( aTrigger->ExtendedTriggerInfo()->IsTriggerFireOnCreation() )
                    {
                    // Set trigger state to fired
                    aTrigger->ExtendedTriggerInfo()->SetTriggerFiredState( ETrue );
                    TLbtTriggerFireInfo triggerFireInfo;
                    TPositionInfo positionInfo;
                    triggerFireInfo.iTriggerId = aTrigger->TriggerEntry()->Id();
                    triggerFireInfo.iFiredPositionInfo = iPosInfo;
                    
                    aTrigger->ExtendedTriggerInfo()->SetFiredInfo( triggerFireInfo );
                    
                     // Time at which trigger fired
                    TTime triggerFiredTime;
                    triggerFiredTime.UniversalTime();
                    
                    strategyData.iFireTime = triggerFiredTime.Int64();
                    strategyData.iBoundaryCondition =  TInt( EOutside );
                    
                    remRearmTime = aTrigger->TriggerEntry()->TimeToRearm();             
                    dataMask |= 
                    CLbtContainerTriggerEntry::EContainerAttributeIsFired | 
                    CLbtContainerTriggerEntry::EContainerAttributeFireInfo;
                    }
                
                // Set the trigger state to inactive
                strategyData.iActivityStatus = EInactive;
                }

            if( EOutside != boundary )
                {
                // Set the trigger state to inactive. This is done here because
                // if a trigger was newly created (state is active) and it is
                // found to be within hysteresis area, then the activity status 
                // needs to be set to inactive to enable the trigger to be
                // handled appropriately when terminal moves inside trigger
                // area.
                strategyData.iActivityStatus = EInactive;
                // Calclulate distance to border of trigger area. This 
                // distance is (D - rT)
                distanceToLatestLocation = Abs( distanceToCenter - triggerArea.triggerRadius );
                }
            else 
                {
                // Calculate distance to the boundary of hysteresis. This 
                // distance is (rH - D)
                distanceToLatestLocation = 
                               Abs( triggerArea.hysteresisRadius - distanceToCenter );
                }
            }
        
        // Set FireOnCreation flag to ETrue here if its not already
        // ETrue. This is done to ensure that the trigger is fired 
        // in the subsequent iterations if the triggering conditions
        // are satisfied.
        if( !aTrigger->ExtendedTriggerInfo()->IsTriggerFireOnCreation() )
            {
            aTrigger->ExtendedTriggerInfo()->SetTriggerFireOnCreation( ETrue );
            dataMask |= CLbtContainerTriggerEntry::EContainerAttributeIsTriggerFireOnCreation;
            }
        
        if( dataMask )    
            {
            iView->UpdateTriggerInfo( CLbtGeoAreaBase::ECircle,iPosInfo, aTrigger, dataMask );
            }
        }
    aTrigger->SetStrategyData( strategyData );    
    UpdateNearestTriggers( aTrigger->TriggerEntry()->Id(), distanceToLatestLocation , remRearmTime );
    LOG1("DistToTrig:%f",distanceToLatestLocation );
    }


// -----------------------------------------------------------------------------
// CLbtCoOrdinateSupervisor::EvalCircularTriggerBasedOnCellPosition
// Evaluates triggers with circular area definition
// -----------------------------------------------------------------------------
//
TBool CLbtCoOrdinateSupervisor::EvalCircularTriggerBasedOnCellPositionL( 
                                          CLbtContainerTriggerEntry* aTrigger )
    {
    TTime currentTime;
    currentTime.UniversalTime();
    
    CLbtTriggerConditionArea* trgCondition = 
                              static_cast< CLbtTriggerConditionArea* >
                              ( ( aTrigger->TriggerEntry() )->GetCondition() );
        
    // Extract strategy data
    TStrategyData strategyData = aTrigger->StrategyData();
    
    TInt remRearmTime = 0;
    TReal distanceToLatestLocation = 0.0;
       
    if( strategyData.iFireTime )
        {
        TTime triggerFiredTime( strategyData.iFireTime );

        TTimeIntervalSeconds interval;
        currentTime.SecondsFrom( triggerFiredTime, interval );
    
        remRearmTime = aTrigger->TriggerEntry()->TimeToRearm() - interval.Int();
        
        if( remRearmTime <= 0 )            
            {
            remRearmTime = 0;
            strategyData.iFireTime = 0;
            aTrigger->SetStrategyData( strategyData );
            }
        }
            
    
    TPosition currentPosition;
    iPosInfo.GetPosition( currentPosition );
    TReal positionAccuracy = currentPosition.HorizontalAccuracy();    
    
    CLbtGeoCircle* circularArea = static_cast< CLbtGeoCircle* >
                                           ( trgCondition->TriggerArea() );
                                           
    TReal32 distanceToCenter;
    TInt err = currentPosition.Distance( circularArea->Center(), 
                                                        distanceToCenter );
    if( err!=KErrNone )
        {
        return ETrue;
        }
    
    // If the trigger is entry type,we calculate distance to the hysterisis radius
    if( CLbtTriggerConditionArea::EFireOnEnter == trgCondition->Direction() )
        {
        distanceToLatestLocation = distanceToCenter -
                                         ( positionAccuracy+aTrigger->ExtendedTriggerInfo()->HysteresisRadius());
                                         
        if( distanceToLatestLocation < 0 && (remRearmTime == 0) )
        	{
        	// Request fix using any of the available psy
        	LOG("Request Proper Fix");
        	return ETrue;
        	}

        // Activate the trigger if the trigger is outside Hysteresis area
        if( EInactive == strategyData.iActivityStatus && distanceToLatestLocation > 0 )
        	{
	   		// Activate the trigger
    		strategyData.iActivityStatus = EActive;
    		aTrigger->SetStrategyData( strategyData );
    		LOG("Trigger activated based on NPP fix");
        	}
        UpdateNearestTriggers( aTrigger->TriggerEntry()->Id(), distanceToLatestLocation, remRearmTime );
        }
    // If the trigger is exit type,we calculate distance to the radius    
    else if( CLbtTriggerConditionArea::EFireOnExit == trgCondition->Direction() )  
        {
        distanceToLatestLocation = distanceToCenter -
                                     ( positionAccuracy+circularArea->Radius() );

        if( distanceToLatestLocation < 0 && (remRearmTime == 0) )
        	{
        	// Request fix using any of the available psy
        	LOG("Request Proper Fix");
        	return ETrue;
        	}	                             
        UpdateNearestTriggers( aTrigger->TriggerEntry()->Id(), distanceToLatestLocation,remRearmTime );                                                          
        }
    return EFalse;     
    }

// -----------------------------------------------------------------------------
// CLbtCoOrdinateSupervisor::EstimateSleepInterval
// Calculates the sleep interval
// -----------------------------------------------------------------------------
//
void CLbtCoOrdinateSupervisor::EstimateSleepInterval()
    {
    FUNC_ENTER("CLbtCoOrdinateSupervisor::EstimateSleepInterval");
    
    TReal maxUserSpeed = iSettings.iMaximumUserSpeed;
        
    TReal actualEstimatedSpeed = KMinProjSpeed;
    // Flag to determine if the nearest trigger is an inactive trigger
    TBool nearestTriggerInactive = EFalse;
    
    // This is first time when there are no previously observed values
    if( iLocReqCount == 1 )
        {
        // First iteration use the minimum update interval
        if( iNearestTriggers.Count() )
            {
            iSleepInterval = iNearestTriggers[0].distance / maxUserSpeed;
            }
        else
            {
            iSleepInterval = iSettings.iMinimumLocationUpdateInterval;
            }
        }
    else
        {
        iEstimatedUserSpeed = 0.0;
        if( (iLastLocationFixType == EFixFromDb) || 
            (iLastLocationFixType == EFixFromNpp) )
            {
            iEstimatedUserSpeed = (maxUserSpeed + KMinProjSpeed)/2;
            }
        else if( iLastLocationFixType == EProperFix )
            {
            // determine average speed from previous location request which is the
            // observed speed
            TPosition currentPosition, prevPosition;
            iPosInfo.GetPosition( currentPosition );
            iPrevPosInfo.GetPosition( prevPosition );
            
            TReal32 avgSpeed = 0.0;
            
            currentPosition.Speed( prevPosition, avgSpeed );
            TObservedValues obsValue;
            obsValue.speed = avgSpeed;
            obsValue.time = currentPosition.Time();

            if( iNObservedValues.Count() == maxObsValues )
                {
                iNObservedValues.Remove( 0 );
                }
            iNObservedValues.Append( obsValue );
            
            TReal num = 0.0;
            TReal den = 0.0;
            TReal obsSpeed = 0.0;
            TReal obsTime = 0.0;
            TTime currentTime;

            // Determine average of previously obtained observed speed, time values.
            // Use the current time value obtained from the approximation of speed.
            currentTime.UniversalTime();
            
            for( TInt i = 0; i < iNObservedValues.Count(); i++ )
                {
                obsSpeed = maxUserSpeed - ( iNObservedValues[i] ).speed;
                TTimeIntervalSeconds timediff; 
                currentTime.SecondsFrom( ( iNObservedValues[i] ).time, timediff );  
                obsTime = timediff.Int() / constantTime;
                TReal timeExp = 0.0;
                Math::Exp( timeExp, (-1 * obsTime ) );
                
                num += obsSpeed * timeExp * timeExp;
                den += timeExp;
                }
        
            iEstimatedUserSpeed = maxUserSpeed - ( num / den );
            
            if( Math::IsNaN(iEstimatedUserSpeed) )
            	{
            	iEstimatedUserSpeed = maxUserSpeed;
            	}

            actualEstimatedSpeed = iEstimatedUserSpeed;
            LOG1("Actual estimated speed:%f",actualEstimatedSpeed);
            
            if(iEstimatedUserSpeed < KMinProjSpeed)
                {
                iEstimatedUserSpeed = KMinProjSpeed;
                }
            // There are some cases estimate user speed goes to infinty.    
            else if( iEstimatedUserSpeed > maxUserSpeed )    
                {
                iEstimatedUserSpeed = maxUserSpeed;
                }
            }
        
        /**
         * Find the position of the nearest trigger which: -
         *
         * a) Is Active
         * b) Its rearm time has expired
         */
        TInt position = -1;
        for( TInt i=0;i<iNearestTriggers.Count();i++ )
            {
            iNearestTriggers[i].minTimeRequired = iNearestTriggers[i].distance / iEstimatedUserSpeed;
                
            if( iNearestTriggers[i].remRearmTime == 0 )
                {
                // It is enough for us to know the approx time required to reach nearest trigger whose 
                // rearm time is not zero( nearest which is not fired )  
                position = i;
                break;
                }
            }
        
        /**
         * Determine the sleep interval considering the rearm time of all the fired triggers.
         * Sleep interval should be min[max[rearm time,minimum time to reach trigger]]. Flag needed
         * for determining if movement detection is needed. Movement detector will be used if
         * position acquisition should be made to re-activate the trigger.
         */        
        iSleepInterval = 0;
        TLbtTriggerId nearestTriggerId = 0;
        
        // Sleep interval should be min[max[rearm time,minimum time to reach trigger]]
        if( position >= 0 )
            {
            for( TInt i=0;i<=position;i++ )
                {
                // Sleep interval for a trigger is the maximum of time to trigger and rearm time
                TInt maxSleepTimeForTrigger;
                if( iNearestTriggers[i].remRearmTime < iNearestTriggers[i].minTimeRequired )
                    {
                    maxSleepTimeForTrigger = iNearestTriggers[i].minTimeRequired;
                    }
                else
                    {
                    maxSleepTimeForTrigger = iNearestTriggers[i].remRearmTime;
                    }
                
                // Sleep interval for system is minimum sleep interval of all triggers    
                if( ( !iSleepInterval.Int() && maxSleepTimeForTrigger ) ||
                      iSleepInterval.Int() > maxSleepTimeForTrigger )  
                    {
                    iSleepInterval = maxSleepTimeForTrigger;
                    nearestTriggerId = iNearestTriggers[i].id;
                    }
                }
            }
        // Case where all the triggers are waiting for rearm time to elapse
        else
            {
            for( TInt i=0;i<iNearestTriggers.Count();i++ )
                {
                if( !iSleepInterval.Int() || 
                    ( iSleepInterval.Int() > iNearestTriggers[i].remRearmTime ))
                    {
                    iSleepInterval = iNearestTriggers[i].remRearmTime;
                    }
                }
            }  
            
        LOG1("Estimated speed:%f",iEstimatedUserSpeed);
        
        
        if( nearestTriggerId )
            {
            // Update the nearestTriggerInactive flag                        
            CLbtContainerTriggerEntry* trigEntry = NULL;
            TBool found = iView->GetTriggerByID( nearestTriggerId, trigEntry );
            
            if( found && (trigEntry != NULL) )
                {
                TStrategyData strategyData = trigEntry->StrategyData();
                
                if( strategyData.iActivityStatus == EInactive )
                    {
                    // Inside triggering area
                    nearestTriggerInactive = ETrue;
                    }
                else
                    {
                    // Outside triggering area
                    nearestTriggerInactive = EFalse;
                    }
                }
            }
        
        // Reduce the time taken from last position fix
        if( iLastLocationFixType == EProperFix )
        	{
        	TTime currentTime;
    	    currentTime.UniversalTime();
    	    TTimeIntervalSeconds seconds;
    	    currentTime.SecondsFrom(iLastFixTime, seconds);
    	    iProcessingInterval = seconds.Int();
    	    iSleepInterval = iSleepInterval.Int() - iProcessingInterval;
        	}
        }   
    
    // If sleep interval is less than KMinSleepInterval and the UE is travelling in
    // high speed then request terminal position immediately
    if( !nearestTriggerInactive &&
        ( iSleepInterval.Int() <= KMinSleepInterval ) &&
        ( iLastLocationFixType == EProperFix ) )
        {
        LOG1("Requesting time out %d", iSleepInterval.Int());
        iFixForFiringCloseTriggers = ETrue;
        // Here we need fix with in the estimated time to reach trigger.Hence setting timeout value to 
        // estimated sleep interval	
        RequestTerminalPosition( (KMinSleepInterval * KMicroMultiplier),EProperFix );
        return;
        }
    
    iState = ESleep;
    TBool useMvmtDet = ETrue;
    if( iLastLocationFixType != EProperFix )
    	{
    	useMvmtDet = ETrue;
    	}
    else if( nearestTriggerInactive )
    	{
    	useMvmtDet = ETrue;
    	}    
    else if( iSleepInterval.Int() < 20 )
    	{
    	useMvmtDet = EFalse;
    	}
	else if( actualEstimatedSpeed > KMaxSpeedToUseMvmtDet )
    	{
    	useMvmtDet = EFalse;
    	}
    LOG1("useMvmtDet = %d", useMvmtDet);
    iTimer->Set( iStatus, iSleepInterval, useMvmtDet );
    SetActive();
    }

    
// -----------------------------------------------------------------------------
// CLbtCoOrdinateSupervisor::ProcessInterrupt
// Evaluates the cause of a timer interrupt and determines the necessary 
// actions to be performed
// -----------------------------------------------------------------------------
//
void CLbtCoOrdinateSupervisor::ProcessInterrupt()
    {
    FUNC_ENTER("CLbtCoOrdinateSupervisor::ProcessInterrupt");
    
    // This is when errors occur while acquiring terminal position
    if( !iStatusManager->LocationAcqSuccess() )
        {
        // Check sleep interval and determine if sleep mode can continue else 
        // retry acquiring terminal position. This happens when there are 
        // changes to triggers in the sleep mode during which the sleep is 
        // cancelled and trigger view is refreshed. Once the refresh operation
        // is completed, this method is invoked.
        TTimeIntervalSeconds interval;
        if( iTimer->RemainingSleepInterval( interval ) )
            {
            iState = ESleep;
            if( interval.Int() < 5 )
                {
                iTimer->ResetInterval( iStatus, interval,EFalse );
                }
            else
                {
                iTimer->ResetInterval( iStatus, interval,ETrue );
                }
            SetActive();
            }
        else
            {
            // If the last location acqusition has failed and the location information for the current cell
            // is unavailable then request location from NPP PSY else request from DB itself
            if( (iLastCellRequestStatus == KErrNone) && 
                iLocArea.iCellId )
		        {
		        // Cell information is available
		        if( !(KErrNone == GetCellIdPosition( iPosInfo ) ) )
		        	{
		        	RequestTerminalPosition( iSettings.iLocationRequestTimeout, EProperFix );
		        	}
		        else
		            {
		            RequestTerminalPosition( iSettings.iLocationRequestTimeout, EFixFromDb );
		            }
            	}
            else
            	{
            	// Current cell information un-available. Make proper fix
            	RequestTerminalPosition( iSettings.iLocationRequestTimeout, EProperFix );
            	}
        	}
        }

    
    // This is when sleep mode is interrupted due to notifications from 
    // container for addition/modification/deletion of triggers in the system
    else if( iTimer->SleepIntervalInterrupted() )
        {
        TLbtTriggerId nearestTrigger = 0;
        if( iNearestTriggers.Count() )
            {
            for( TInt i=0;i<iNearestTriggers.Count();i++ )
                {
                if( iNearestTriggers[i].remRearmTime == 0 )
                    {
                    nearestTrigger = iNearestTriggers[i].id;
                    break;
                    }
                }
            }
        iView->DetermineNearestTriggerChanges( &iNearestTriggers );
        
        if( iNearestTriggers.Count() == 0 )
            {
            // This means the nearest 5 triggers have been changed. Reset
            // iterator re-evaluate all triggers in the system. 
            if( KErrNone != ResetViewIterator() )
                {
                return;
                }
            iState = ETriggerEvaluation;
            SetEvent();
            }
        else
            {
            TBool makeLocReq = EFalse;
            TRAPD( err, makeLocReq = EvaluateModifiedTriggersL( ) );
            
            if( KErrNone != err )
            	{
            	ERROR("EvaluateTriggersL leaving with %d", err);
	            Term();
	            return;            	
            	}
            
            if( makeLocReq )
            	{
            	// Location request is needed based on evaluating
            	// modified triggers
            	RequestTerminalPosition( iSettings.iLocationRequestTimeout );
            	return;
            	}
            
            // Check if nearest trigger has changed
            TLbtTriggerId nearestTriggerAfterEvaluation = 0;
            if( iNearestTriggers.Count() )
                {
                for( TInt i=0;i<iNearestTriggers.Count();i++ )
                    {
                    if( iNearestTriggers[i].remRearmTime == 0 )
                        {
                        nearestTriggerAfterEvaluation = iNearestTriggers[i].id;
                        break;
                        }
                    }
                }
            // This is check is required when all triggers in the system has fired
            // and new trigger has been added.
            if( (nearestTriggerAfterEvaluation) && 
                (nearestTrigger != nearestTriggerAfterEvaluation) )                 
                {
                RequestTerminalPosition( iSettings.iLocationRequestTimeout );
                }            
            else
                {
                // Check if there be any remaining sleep interval. If true, 
                // then switch to sleep mode for the remaining time period. 
                // Else switch to acquiring location information.
                TTimeIntervalSeconds remainingInterval;
                if( iTimer->RemainingSleepInterval( remainingInterval ) )
                    {
                    iState = ESleep;
                    if( remainingInterval.Int() < 5 )
                        {
                        iTimer->ResetInterval( iStatus, remainingInterval,EFalse ); 
                        }
                    else
                        {
                        iTimer->ResetInterval( iStatus, remainingInterval,ETrue ); 
                        }
                    SetActive();
                    }
                else
                    {
                    RequestTerminalPosition( iSettings.iLocationRequestTimeout );
                    }
                }
            }
        }        
    else if( KErrNone == iStatus.Int() || KErrAbort == iStatus.Int() )
        {
        RequestTerminalPosition( iSettings.iLocationRequestTimeout );
        }
    else
        {
        LOG1("Error in timer:%d",iStatus.Int());
        }
    }
    

// -----------------------------------------------------------------------------
// CLbtCoOrdinateSupervisor::RequestTerminalPosition
// Issues an asynchronous request to determine terminal's position
// -----------------------------------------------------------------------------
//
void CLbtCoOrdinateSupervisor::RequestTerminalPosition( TInt aLocationRequestTimeout,
                                                        TLocationFixType aFixLocationFixType )
    {
    FUNC_ENTER("CLbtCoOrdinateSupervisor::RequestTerminalPosition");
    iPrevPosInfo = iPosInfo;
    LOG1("aFixLocationFixType = %d", aFixLocationFixType);
    LOG1("Cell Id = %d", iLocArea.iCellId);

    if( (aFixLocationFixType == EFixFromDb) && 
        (iLastCellRequestStatus == KErrNone) && 
        iLocArea.iCellId )
        {
        LOG("Taking fix from DB");
        TInt error = GetCellIdPosition( iPosInfo );
        if( KErrNone ==  error)
            {
            LOG("Fix From DB");
            TPosition position;
            iPosInfo.GetPosition(position);
            LOG1("Lat:%f", position.Latitude());
			LOG1("Long:%f", position.Longitude());
			LOG1("HA:%f", position.HorizontalAccuracy());
            iLastLocationFixType = EFixFromDb;
            iState = ETriggerEvaluation;
            SetEvent();
            return;
            }
        else
        	{
        	LOG1("Failed to get Fix From DB with %d", error);
        	}
        }
    else if( aFixLocationFixType == EFixFromNpp )
        {
        iLastLocationFixType = EFixFromNpp;
        iLocationRequestor->CurrentLocationFromNpp( iPosInfo, iStatus, 
                                                    TTimeIntervalMicroSeconds( aLocationRequestTimeout ) );
        iState = ELocationAcquisition;
        SetActive();
        return;
        }

    iLastLocationFixType = EProperFix;
    iLocationRequestor->CurrentLocation( iPosInfo, iStatus, 
                                            iModuleId,
                                            TTimeIntervalMicroSeconds( aLocationRequestTimeout ) );
    iState = ELocationAcquisition;
    SetActive();        
    }


// -----------------------------------------------------------------------------
// CLbtCoOrdinateSupervisor::GetCellIdPosition
// Get the position corresponding to current cell id
// -----------------------------------------------------------------------------
//
TInt CLbtCoOrdinateSupervisor::GetCellIdPosition( TPositionInfo& aPositionInfo )
    {
    FUNC_ENTER("CLbtCoOrdinateSupervisor::GetCellIdPosition");
    TInt countryCode,networkCode;
    
    TLex lex( iNwInfo.iCountryCode );
    lex.Val( countryCode );
    
    lex.Assign( iNwInfo.iNetworkId );
    lex.Val( networkCode );
    
    TPosition position;
    TInt error = iCellIdDatabase->GetLocationForCid( countryCode,networkCode,iLocArea.iLocationAreaCode,
                                                     iLocArea.iCellId,position );
    if( error == KErrNone )
        {
        aPositionInfo.SetPosition( position );
        }
    return error;    
    }


// -----------------------------------------------------------------------------
// CLbtCoOrdinateSupervisor::UpdateNearestTriggers
// Updates the record of nearest triggers
// -----------------------------------------------------------------------------
//
void CLbtCoOrdinateSupervisor::UpdateNearestTriggers( TLbtTriggerId aID, TReal aDistance , TInt aRemRearmTime )
    {
    FUNC_ENTER("CLbtCoOrdinateSupervisor::UpdateNearestTriggers");
    TNearestTrigger nTrigger;
    nTrigger.distance = aDistance;
    nTrigger.id = aID;
    nTrigger.remRearmTime = aRemRearmTime;
    
    TLinearOrder< TNearestTrigger > byDistance( CompareByDistance );
    iNearestTriggers.InsertInOrderAllowRepeats( nTrigger, byDistance );
    }


// -----------------------------------------------------------------------------
// CLbtCoOrdinateSupervisor::EstimateTriggerRadii
// Calculcates the trigger radius and the radius of the hysteresis circle
// -----------------------------------------------------------------------------
//
CLbtCoOrdinateSupervisor::TTriggerArea CLbtCoOrdinateSupervisor::EstimateTriggerRadii( 
                         TReal aTriggerRadius, TReal aHysteresisRadius,
                         TReal aPositionAccuracy )
    {
    TTriggerArea trgArea;
    TReal ratioOfCircularAreas =  aPositionAccuracy / aTriggerRadius;
    
    if(  ratioOfCircularAreas >= KCofftOfHighEdgeLimit )
        {
        trgArea.triggerRadius = aTriggerRadius;
        trgArea.hysteresisRadius = aHysteresisRadius;
        }
    else
        {
        // Update radiusOfTrigger and radiusOfHysteresis accordingly
        trgArea.triggerRadius = aTriggerRadius +( KAccuracyMultiplier * aPositionAccuracy );
        trgArea.hysteresisRadius = Hysteresis( trgArea.triggerRadius );        
        }
        
    return trgArea;
    }


// -----------------------------------------------------------------------------
// CLbtCoOrdinateSupervisor::Hysteresis
// Calculates the hysteresis radius 
// -----------------------------------------------------------------------------
//
TReal CLbtCoOrdinateSupervisor::Hysteresis( TReal aTriggerRadius )
    {
    TReal hysteresis;
    if( aTriggerRadius > KTriggerRadiusCutoff )
        {
        TReal logRadius;				
        Math::Ln( logRadius, aTriggerRadius / 10 );
        hysteresis = aTriggerRadius / logRadius;        
        }
    else
        {
        hysteresis = aTriggerRadius / 4;
        }
    
    return hysteresis + aTriggerRadius;
    }


// -----------------------------------------------------------------------------
// CLbtCoOrdinateSupervisor::DetermineNearestDistances
// Algorithm to determine the shortest distance
// -----------------------------------------------------------------------------
//
TInt CLbtCoOrdinateSupervisor::CompareByDistance( const TNearestTrigger& src,
        const TNearestTrigger& dst )
    {
    if( src.distance > dst.distance )
        {
        return 1;
        }
    else if( src.distance < dst.distance )
        {
        return -1;
        }
    return 0;
    }
   

// -----------------------------------------------------------------------------
// CLbtCoOrdinateSupervisor::CompareByID
// Determine equality of nearest triggers by id
// -----------------------------------------------------------------------------
//
TBool CLbtCoOrdinateSupervisor::CompareByID( const TNearestTrigger& src,
        const TNearestTrigger& dst )
    {
    if( src.id > dst.id )
        {
        return ETrue;
        }
    return EFalse;
    }


// -----------------------------------------------------------------------------
// CLbtCoOrdinateSupervisor::ResetViewIterator
// Resets trigger view iterator.
// -----------------------------------------------------------------------------
//
TInt CLbtCoOrdinateSupervisor::ResetViewIterator()
    {
    FUNC_ENTER("CLbtCoOrdinateSupervisor::ResetViewIterator");
    TInt err = iViewIterator.Reset();
    if( KErrNone != err )
        {
        if( KErrNotFound == err )
            {
            // determine update interval
            iState = iProjectedState = EIdle;
            }
        else
            {
            // TODO: Report error to server. This can be done only after 
            // introducing new state to strategy dynamic info.
            Term();
            }
        return err;
        }
        
    return KErrNone;
    }


// -----------------------------------------------------------------------------
// CLbtCoOrdinateSupervisor::RunL
// Inherited from CActive - called when the request issued is completed.
// -----------------------------------------------------------------------------
//
void CLbtCoOrdinateSupervisor::RunL()
    {
    FUNC_ENTER("CLbtCoOrdinateSupervisor::RunL");
    switch ( iState )
        {
        case ELocationAcquisition:
            GetPositionInfoL();
            break;

        case ETriggerEvaluation:
            EvaluateTriggersL();
            break;
            
        case EUpdateIntervalEstimation:
            EstimateSleepInterval();
            break;

        case ESleep:
        	LOG("Wakeup");
            ProcessInterrupt();
            break;
        
        default:
            break;
        }
    }


// -----------------------------------------------------------------------------
// CLbtCoOrdinateSupervisor::DoCancel
// Inherited from CActive - called to cancel outanding events.
// -----------------------------------------------------------------------------
//
void CLbtCoOrdinateSupervisor::DoCancel()
    {
    FUNC_ENTER("CLbtCoOrdinateSupervisor::DoCancel");
    iFixForFiringCloseTriggers = EFalse;
    }


// -----------------------------------------------------------------------------
// CLbtCoOrdinateSupervisor::RunError
// Handles the event of leave from the request completion event handler RunL()
// -----------------------------------------------------------------------------
//
TInt CLbtCoOrdinateSupervisor::RunError( TInt /*aError*/ ) 
    {
    FUNC_ENTER("CLbtCoOrdinateSupervisor::RunError");
    Term();
    return KErrNone;
    }


// -----------------------------------------------------------------------------
// CLbtCoOrdinateSupervisor::CLbtCoOrdinateSupervisor
// C++ default constructor.
// -----------------------------------------------------------------------------
//
CLbtCoOrdinateSupervisor::CLbtCoOrdinateSupervisor() : 
                CActive( EPriorityHigh )
    {
    CActiveScheduler::Add( this );
    }

    
// -----------------------------------------------------------------------------
// CLbtCoOrdinateSupervisor::ConstructL
// Symbian 2nd phase constructor.
// -----------------------------------------------------------------------------
//
void CLbtCoOrdinateSupervisor::ConstructL( TAny* /*aConstructionParameters*/,
                                           CLbtTriggerView* aView,
                                           MLbtStrategyEngineObsrvr* aObserver,
                                           CLbtCellChangeHandler* aCellChangeHandler )
    {
	iEngObserver = aObserver;
	iState = iProjectedState = EIdle;
	iEngObserver->RetrieveTriggeringSettings( iSettings );
	iCellChangeHandler = aCellChangeHandler;
  
    iModuleId = iSettings.iPositioningTechnology;
    
	iLocationRequestor = CLbtLocationRequestor::NewL();
	
	iStatusManager = CLbtStatusManager::NewL();
	iTimer = CLbtStrategyTimer::NewL();
	iView = aView;	
	
	iViewIterator = iView->BeginL( CLbtGeoAreaBase::ECircle );
	iCellIdDatabase = CLbtCellIdDatabase::NewL();
	iLastCellRequestStatus = KErrUnknown;
	iLastLocationFixType = EFixUnknown;
	iPsyChangeListner = NULL;
	iFixForFiringCloseTriggers = EFalse;
    }
    

// -----------------------------------------------------------------------------
// CLbtCoOrdinateSupervisor::SetEvent
// Completes the iRequestStatus with KErrNone.
// -----------------------------------------------------------------------------
//
void CLbtCoOrdinateSupervisor::SetEvent()
    {
    if ( !IsActive() )
    	{
    	TRequestStatus* lStatus = &iStatus;
    	User::RequestComplete( lStatus, KErrNone );
        SetActive();
    	}    
    }


// -----------------------------------------------------------------------------
// CLbtCoOrdinateSupervisor::Term
// 
// -----------------------------------------------------------------------------
//
void CLbtCoOrdinateSupervisor::Term()
    {
    FUNC_ENTER("CLbtCoOrdinateSupervisor::Term");
    
    iSupervisionInitiated = EFalse;
            
    iView->Cancel();
    switch( iState )
        {
    case ELocationAcquisition:
        if( iLastLocationFixType == EProperFix )
    		{
    		iLocationRequestor->Cancel();
    		}
    	else
    		{
    		iLocationRequestor->CancelFixFromNpp();
    		}
        break;
        
    case ESleep:
        iTimer->Cancel();
        break;
    
    default:
        Cancel();
        break;
        }
        
    iState = iProjectedState = EIdle;
    iLastLocationFixType = EFixUnknown;
    iFixForFiringCloseTriggers = EFalse;
    }

// -----------------------------------------------------------------------------
// CLbtCoOrdinateSupervisor::FireClosestTriggers
// 
// -----------------------------------------------------------------------------
//
void CLbtCoOrdinateSupervisor::FireClosestTriggers()
	{
	FUNC_ENTER("CLbtCoOrdinateSupervisor::FireClosestTriggers");
	LOG1("NT Count = %d", iNearestTriggers.Count());
	for( TInt i=0;i<iNearestTriggers.Count();i++ )
		{
		if(iNearestTriggers[i].remRearmTime != 0)
		    {
		    continue;
		    }

		TInt timeToTrigger = (iNearestTriggers[i].distance / iEstimatedUserSpeed);		

        TInt estimatedInterval = timeToTrigger - iProcessingInterval;

		LOG1("estimatedInterval = %d", estimatedInterval);

		if( estimatedInterval <= KMinSleepInterval )
			{
			LOG("NEED TO FIRE");
			CLbtContainerTriggerEntry* trigger;
			if( iView->GetTriggerByID( iNearestTriggers[i].id,trigger ) )
				{
				LOGSTRING("Trigger: \"%S\" ", &(trigger->TriggerEntry()->Name()));
				// check the activity status
				TStrategyData strategyData = trigger->StrategyData();   
				if( strategyData.iActivityStatus == EActive )
				    {
				    // Fire the trigger
                    TLbtTriggerDataMask dataMask = 0;
                    
                    // Set trigger state to fired
                    trigger->ExtendedTriggerInfo()->SetTriggerFiredState( ETrue );
                    TLbtTriggerFireInfo triggerFireInfo;
                    TPositionInfo positionInfo;
                    triggerFireInfo.iTriggerId = trigger->TriggerEntry()->Id();
                    triggerFireInfo.iFiredPositionInfo = iPrevPosInfo;
                    
                    trigger->ExtendedTriggerInfo()->SetFiredInfo( triggerFireInfo );
                    
                    // Time at which trigger fired
                    TTime triggerFiredTime;
                    triggerFiredTime.UniversalTime();
                    LOG("NEAREST TRIGGER FIRED");
                    
                    strategyData.iFireTime = triggerFiredTime.Int64();
                    // Set trigger to inactive state
                    strategyData.iActivityStatus = EInactive;
                    
                    dataMask |= 
                    CLbtContainerTriggerEntry::EContainerAttributeIsFired | 
                    CLbtContainerTriggerEntry::EContainerAttributeFireInfo ;
                    
                    iView->UpdateTriggerInfo( CLbtGeoAreaBase::ECircle,iPosInfo, trigger, dataMask );
                    trigger->SetStrategyData( strategyData );
				    }
                }
            else
                {
                LOG("TRIGGER NOT FOUND ??");
                }
			}
		else
			{
			LOG("ELSE");
			// Since the array is in the ascending order of distance( which is directly proportional to time ),
			// we can need not search rest of the array.	
			break;
			}					
		}
	}

// -----------------------------------------------------------------------------
// CLbtCoOrdinateSupervisor::CalculateTolerableRadius
// 
// -----------------------------------------------------------------------------
//
TReal CLbtCoOrdinateSupervisor::CalculateTolerableRadius( TReal aRadius )
    {
    // Tolerance can be calculated using the straight line equation. Slope of straight line is 0.07 and 
    // intercept is 22.2
    TReal tolerableInaccuracy = ( 0.07 * aRadius ) + 22.2;
    return ( tolerableInaccuracy + aRadius );
    }

// -----------------------------------------------------------------------------
// CLbtCoOrdinateSupervisor::HandleCellChangeEvent
// 
// -----------------------------------------------------------------------------
//
void CLbtCoOrdinateSupervisor::HandleCellChangeEvent(
            const TInt aStatus,
            const RMobilePhone::TMobilePhoneNetworkInfoV1& aNwInfo,
            const RMobilePhone::TMobilePhoneLocationAreaV1& aLocArea)
    {
    FUNC_ENTER("CLbtCoOrdinateSupervisor::HandleCellChangeEvent");
    if( KErrNone == aStatus )
	    {
	    // validate network info
		if (aNwInfo.iMode == RMobilePhone::ENetworkModeGsm ||
            aNwInfo.iMode == RMobilePhone::ENetworkModeWcdma)
            {
            TLex lex( aNwInfo.iCountryCode );
            TInt countryCode,networkCode;
            lex.Val( countryCode );
            if( countryCode )
                {
                lex.Assign( aNwInfo.iNetworkId );
                lex.Val( networkCode );
                if( networkCode )
                    {
                    if( aLocArea.iLocationAreaCode && aLocArea.iCellId )
                        {
                        iLastCellRequestStatus = KErrNone;
                        iNwInfo = aNwInfo;
		                iLocArea = aLocArea;
		                }
                    }
                }
            }
		}
	else 
	    {
	    iLastCellRequestStatus = aStatus;
	    }	
    }

// -----------------------------------------------------------------------------
// CLbtCoOrdinateSupervisor::HandlePsyChangeEvent
// 
// -----------------------------------------------------------------------------
//
void CLbtCoOrdinateSupervisor::HandlePsyChangeEvent( TPositionModuleId aModuleId  )
    {
    LOG("CLbtCoOrdinateSupervisor::HandlePsyChangeEvent");
    if( aModuleId == iSettings.iPositioningTechnology )
        {
        LOG("aModuleId == iSettings.iPositioningTechnology");
        iModuleId = aModuleId;
        delete iPsyChangeListner;
        iPsyChangeListner = NULL;        
        }
    else
        {
        LOG("aModuleId != iSettings.iPositioningTechnology");
        // We will use defualt proxy
        iModuleId = TUid::Uid(0xFFFFFFFF);
        iPsyChangeListner->StartToListen( iSettings.iPositioningTechnology );
        }
    
    // If coordinate supervisor AO is not active,request terminal position    
    if( !IsActive() )
        {
        RequestTerminalPosition( iSettings.iLocationRequestTimeout,EProperFix );
        }    
    }
// end of file