/*
* 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:  Handles getLocation requests
 *
*/


// INCLUDE FILES
#include "cpositioner.h"
#include "logger.h"
#include "locationfunctionserver.h"

using namespace java::location;

// UNNAMED LOCAL NAMESPACE
namespace
{
// Delay subsequent getLocation() calls. This way the failing
// requests do not steal all processing time
const TInt KLocCallDelay = 500000;
}

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

// -----------------------------------------------------------------------------
// CPositioner::CPositioner
// C++ default constructor can NOT contain any code, that
// might leave.
// -----------------------------------------------------------------------------
//
CPositioner::CPositioner(LocationFunctionServer* aFunctionSource) :
        CPositionerBase(aFunctionSource)
{
}

// -----------------------------------------------------------------------------
// CPositioner::ConstructL
// Symbian 2nd phase constructor can leave.
// -----------------------------------------------------------------------------
//
void CPositioner::ConstructL(RPositionServer& aServer,
                             TPositionModuleId aModuleId,
                             TPositionModuleInfo::TCapabilities aCapabilities)
{
    BaseConstructL(aServer, aModuleId, aCapabilities);
    User::LeaveIfError(iTimer.CreateLocal());
}

// -----------------------------------------------------------------------------
// CPositioner::NewL
// Two-phased constructor.
// -----------------------------------------------------------------------------
//
CPositioner* CPositioner::NewL(LocationFunctionServer* aFunctionSource,
                               RPositionServer& aServer, TPositionModuleId aModuleId,
                               TPositionModuleInfo::TCapabilities aCapabilities)
{
    CPositioner* self = new(ELeave) CPositioner(aFunctionSource);
    CleanupStack::PushL(self);
    self->ConstructL(aServer, aModuleId, aCapabilities);
    CleanupStack::Pop(self);
    return self;
}

// Destructor
CPositioner::~CPositioner()
{
    iTimer.Close();
    Cancel();
}

// -----------------------------------------------------------------------------
// CPositioner::StaticCancel
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CPositioner::StaticCancel(CPositioner* aSelf)
{
    aSelf->Cancel();
}

// -----------------------------------------------------------------------------
// CPositioner::SetCallBackData
// -----------------------------------------------------------------------------
//
void CPositioner::SetCallBackData(jobject aJavaPositioner, JNIEnv* aJni)
{
    mJni = aJni;
    mPeer = aJavaPositioner;

    jclass positionerClass = (*mJni).GetObjectClass(mPeer);

    //Get Method ID of Get Location Data Callback
    mGetLocationCallBack = mJni->GetMethodID(positionerClass, "syncComplete",
                           "(I)V");
}

// -----------------------------------------------------------------------------
// CPositioner::RunL
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CPositioner::RunL()
{
    TInt returnCode = iStatus.Int();

    switch (returnCode)
    {
    case KErrNone:
    {
        // If previously returned code was buffer overflow just inform
        // that the request was successful.
        TInt ret = (iDelayedCode == KErrPositionBufferOverflow)
                   || (iDelayedCode == KErrOverflow) ? KErrNone : iDelayedCode;
        // Obtained location information successfully, location fix is partial,
        // or the quality of the fix is poor. In the last two cases the
        // Java implementation tries to obtain location fix again. see API
        // specification about location fixes when temporary unavailable.
        // This is because the current implementation does not support partial
        // location fixes
        mJni = mFunctionServer->getValidJniEnv();
        (*mJni).CallVoidMethod(mPeer, mGetLocationCallBack, ret);
        break;
    }
    case KErrOverflow: // Fallthrough
    case KErrPositionBufferOverflow:
    {
        // CPositionerBase handles buffer size errors
        HandleBufferSizeErrorL(returnCode);
        // Buffer increased successfully. Make a new request
        UpdatePosition();
        break;
    }
    // Handle other return codes of RPositioner::NotifyPositionUpdate()
    // Partial update feature is not supported by this implementation
    case KPositionPartialUpdate: // Fallthrough
    case KPositionQualityLoss: // Fallthrough
        // KErrTimedOut is handled on Java-side
    case KErrTimedOut: // Fallthrough
        // KErrNotFound is returned if current module is invalid
    case KErrNotFound: // Fallthrough
        // HPositionGenericInfo should be supported by all PSYs
    case KErrArgument: // Fallthrough
        // KErrAccessDenied if no requestor specified
    case KErrAccessDenied: // Fallthrough
    case KErrUnknown: // Used in MLFW
        // Position request was canceled
    case KErrCancel: // Fallthrough
        // Bad implementation but due to partial fixes this cannot be fixed
        // at the moment. Correct when partial fixes are supported. Java tries
        // to obtain location fixes until time specified in Java-side expires
        // Delay response so that repeated calls to getLocation do not steal
        // all CPU time
    default:
    {
        iTimer.After(iStatus, KLocCallDelay);
        SetActive();
        break;
    }
    }
    iDelayedCode = returnCode;
}

// -----------------------------------------------------------------------------
// CPositioner::DoCancel
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CPositioner::DoCancel()
{
    iTimer.Cancel();
    iPositioner.CancelRequest(EPositionerNotifyPositionUpdate);
    mJni = mFunctionServer->getValidJniEnv();
    (*mJni).CallVoidMethod(mPeer, mGetLocationCallBack, KErrCancel);
}

// -----------------------------------------------------------------------------
// CPositioner::RunError
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
TInt CPositioner::RunError(TInt aError)
{
    mJni = mFunctionServer->getValidJniEnv();
    (*mJni).CallVoidMethod(mPeer, mGetLocationCallBack, aError);
    return KErrNone;
}

// -----------------------------------------------------------------------------
// CPositioner::GetLocation
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
TInt CPositioner::GetLocation(TInt aTimeout)
{
    TTimeIntervalMicroSeconds timeout = MAKE_TINT64(0, aTimeout) * 1000000;
    TPositionUpdateOptions updateOptions;
    updateOptions.SetUpdateTimeOut(timeout);

    TInt err = iPositioner.SetUpdateOptions(updateOptions);

    if (err == KErrNone)
    {
        UpdatePosition();
    }
    return err;
}

//  End of File
