/*
* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description:
*
*/
#include "cxecameradevicecontrolsymbian.h"
#include "cxesettingsimp.h"
#include "cxefeaturemanagerimp.h"
#include "cxesettingsmodel.h"
#include "cxutils.h"
#include "cxenamespace.h"
#include "cxeerrormappingsymbian.h"
#include "cxestate.h"

#include "OstTraceDefinitions.h"
#ifdef OST_TRACE_COMPILER_IN_USE
#include "cxecameradevicecontrolsymbianTraces.h"
#endif



CxeCameraDeviceControlSymbian::CxeCameraDeviceControlSymbian()
    : CxeStateMachine("CxeCameraDeviceControlSymbian"),
    mCameraDevice(NULL),
    mCameraIndex(Cxe::PrimaryCameraIndex),
    mCameraMode(Cxe::ImageMode)
{
    CX_DEBUG_ENTER_FUNCTION();

#ifdef FORCE_SECONDARY_CAMERA
    mCameraIndex = Cxe::SecondaryCameraIndex;
#endif
    qRegisterMetaType<CxeCameraDeviceControl::State>();
    initializeStates();

    mCameraDevice = new CxeCameraDevice();

    CX_DEBUG_EXIT_FUNCTION();
}

CxeCameraDeviceControlSymbian::~CxeCameraDeviceControlSymbian()
{
    CX_DEBUG_ENTER_FUNCTION();

    // release current camera
    releaseCurrentCamera();

    delete mCameraDevice;

    CX_DEBUG_EXIT_FUNCTION();
}

void CxeCameraDeviceControlSymbian::init()
{
    CX_DEBUG_ENTER_FUNCTION();

    CxeError::Id err = mCameraDevice->newCamera(mCameraIndex, this);

    if (err) {
        emit initModeComplete(err);
    }

    CX_DEBUG_EXIT_FUNCTION();
}

void CxeCameraDeviceControlSymbian::reserve()
{
    CX_DEBUG_ENTER_FUNCTION();

    CX_DEBUG_ASSERT(mCameraDevice && mCameraDevice->camera());

    if (state() == Idle) {
        setState(Initializing);
        mCameraDevice->camera()->Reserve();
        OstTrace0(camerax_performance, CXECAMERADEVICECONTROLSYMBIAN_RESERVE, "msg: e_CX_RESERVE 1");
    } else if (state() == PendingRelease) {
        // if we get a reserve request and if there is a pending release
        // it is just fine to continue the init operation.
        setState(Initializing);
    } else {
        // nothing to do
    }

    CX_DEBUG_EXIT_FUNCTION();
}

void CxeCameraDeviceControlSymbian::powerOn()
{
    CX_DEBUG_ENTER_FUNCTION();

    CX_DEBUG_ASSERT(mCameraDevice && mCameraDevice->camera());
    if (state() == Initializing) {
        mCameraDevice->camera()->PowerOn();
        OstTrace0(camerax_performance, CXECAMERADEVICECONTROLSYMBIAN_POWERON, "msg: e_CX_POWER_ON 1");
    }
    CX_DEBUG_EXIT_FUNCTION();
}

void CxeCameraDeviceControlSymbian::HandleEvent(const TECAMEvent &aEvent)
{
    doHandleEvent( aEvent );
    emit cameraEvent( aEvent.iEventType.iUid, aEvent.iErrorCode );
}

void CxeCameraDeviceControlSymbian::doHandleEvent(const TECAMEvent &aEvent)
{
    CX_DEBUG_ENTER_FUNCTION();

    CX_DEBUG(("Cxe: event 0x%08x, %d", aEvent.iEventType.iUid, aEvent.iErrorCode));

    if(aEvent.iEventType == KUidECamEventReserveComplete) {
        handleReserveComplete(aEvent.iErrorCode);
    }
    else if(aEvent.iEventType == KUidECamEventPowerOnComplete) {
        handlePowerOnComplete(aEvent.iErrorCode);
    }
    else if(aEvent.iEventType == KUidECamEventCameraNoLongerReserved)
        {
        handleNoLongerReserved(aEvent.iErrorCode);
        }
    else
        {
        // We don't care about this event -- ignore
        }

    CX_DEBUG_EXIT_FUNCTION();
}

void CxeCameraDeviceControlSymbian::handleReserveComplete(int error)
{
    CX_DEBUG_ENTER_FUNCTION();
    OstTrace0( camerax_performance, CXECAMERADEVICECONTROLSYMBIAN_HANDLERESERVECOMPLETE, "msg: e_CX_RESERVE 0" );

    if(state() == PendingRelease) {
        release();
    } else {
        if (!error) {
            powerOn();
        } else {
            emit initModeComplete(CxeErrorHandlingSymbian::map(error));
            setState(Idle);
        }
    }

    CX_DEBUG_EXIT_FUNCTION();
}

void CxeCameraDeviceControlSymbian::handlePowerOnComplete(int error)
{
    CX_DEBUG_ENTER_FUNCTION();
    OstTrace0(camerax_performance, CXECAMERADEVICECONTROLSYMBIAN_HANDLEPOWERONCOMPLETE, "msg: e_CX_POWER_ON 0");

    if(state() == PendingRelease) {
        release();
    } else {
        if (!error) {
            setState(Ready);
            emit deviceReady(); // this will trigger prepare for either still or video mode
        } else {
            setState(PendingRelease);
            release();
            emit initModeComplete(CxeErrorHandlingSymbian::map(error));
        }
    }

    CX_DEBUG_EXIT_FUNCTION();
}

void CxeCameraDeviceControlSymbian::handleNoLongerReserved(int /* error */)
{
    setState( Idle );
    //! @todo: handle cases where camera is lost
}


/*
* switch between camera <-> primary <-> secondary
*/

CxeError::Id CxeCameraDeviceControlSymbian::switchCamera(Cxe::CameraIndex cameraIndex)
{
    CX_DEBUG_ENTER_FUNCTION();

#ifdef FORCE_SECONDARY_CAMERA
    // 2nd camera forced use, make us believe camera never needs to be swithed.
    CX_DEBUG(("CxeCameraDeviceControlSymbian::switchCamera() second camera forced, skip switch"));
    cameraIndex = mCameraIndex;
#endif

    // during mode change, we have to re-create camera reference and release resources.
    // in all other cases if the camera indexes are same, it means that camera reference
    // is already created and hence we can return immediately.
    if (cameraIndex == mCameraIndex) {
        CX_DEBUG_EXIT_FUNCTION();
        return CxeError::None;
    }

    releaseCurrentCamera();

    CxeError::Id err = mCameraDevice->newCamera(cameraIndex, this);

    if (err == CxeError::None){
        // CCamera object created, so make sure that appropriate index is used
        mCameraIndex = cameraIndex;
    }

    if (!err) { // if there is no error creating new camera, then start Reserve
        reserve();
    }

    CX_DEBUG_EXIT_FUNCTION();
    return err;
}

void CxeCameraDeviceControlSymbian::release()
{
    CX_DEBUG_ENTER_FUNCTION();

    if (state() == Idle) {
        // nothing to do
        return;
    }

    if (state() == Initializing) {
        setState(PendingRelease);
    } else {
        mCameraDevice->releaseCamera();
        setState(Idle);
    }

    CX_DEBUG_EXIT_FUNCTION();
}

/*
* Release resources w.r.t current camera
*/
void CxeCameraDeviceControlSymbian::releaseCurrentCamera()
{
    CX_DEBUG_ENTER_FUNCTION();

    release();
    // delete old camera instance, this will inturn generates "prepareForCameraDelete" event
    // across all interested classes which wants to do cleanup for new camera reference change
    mCameraDevice->deleteCamera();

    CX_DEBUG_EXIT_FUNCTION();
}

void CxeCameraDeviceControlSymbian::ViewFinderReady(MCameraBuffer &aCameraBuffer, TInt aError)
{
    CX_DEBUG_ENTER_FUNCTION();
    emit vfFrameReady(&aCameraBuffer, aError);
    CX_DEBUG_EXIT_FUNCTION();
}

void CxeCameraDeviceControlSymbian::ImageBufferReady(MCameraBuffer& aCameraBuffer, TInt aError)
{
    CX_DEBUG_ENTER_FUNCTION();

    emit imageBufferReady( &aCameraBuffer, aError );

    CX_DEBUG_EXIT_FUNCTION();
}

void CxeCameraDeviceControlSymbian::VideoBufferReady(MCameraBuffer &/*aCameraBuffer*/, TInt /*aError*/)
{
    CX_DEBUG_IN_FUNCTION();
}

Cxe::CameraIndex CxeCameraDeviceControlSymbian::cameraIndex() const
{
    return mCameraIndex;
}

Cxe::CameraMode CxeCameraDeviceControlSymbian::mode() const
{
    return mCameraMode;
}

void CxeCameraDeviceControlSymbian::setMode(Cxe::CameraMode mode)
{
    mCameraMode = mode;
}

CxeCameraDeviceControl::State CxeCameraDeviceControlSymbian::state() const
{
    return static_cast<State>(stateId());
}

void CxeCameraDeviceControlSymbian::handleStateChanged(int newStateId, CxeError::Id error)
{
    emit stateChanged(static_cast<State>(newStateId), error);
}

void CxeCameraDeviceControlSymbian::initializeStates()
{
    // addState( id, name, allowed next states )
    addState(new CxeState( Idle , "Idle", Initializing));
    addState(new CxeState( Initializing, "Initializing", PendingRelease | Ready | Idle));
    addState(new CxeState( Ready, "Ready", Idle));
    addState(new CxeState( PendingRelease, "PendingRelease", Initializing | Idle));

    setInitialState(Idle);
}

CxeCameraDevice *CxeCameraDeviceControlSymbian::cameraDevice()
{
    return mCameraDevice;
}

// end of file
