/*
* 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: Seek or trickplay
 *
*/

// Version : %version: 7 %


// INCLUDE FILES
#include <mpxplaybackpluginobserver.h>

#include "mpxvideoseeker.h"
#include "mpxvideoplaybackcontroller.h"
#include "mpxvideo_debug.h"

// CONSTANTS

#if TRICK_PLAY
const TInt KDefaultPlaySpeed(100);        // 1x
const TInt KDefaultTrickPlaySpeed(400);   // 4x
#else
const TInt KTrickPlayTimeout(5000000);    // 5 sec
const TInt KSpeedInterval(125000);        // 125 msec
const TInt KDurationA(90000000);          // 90 sec
const TInt KDurationB(180000000);         // 180 sec
const TInt64 KSpeedAIncrements(2000000);  // 2 sec
const TInt64 KSpeedBIncrements(4000000);  // 4 sec
#endif

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

// -------------------------------------------------------------------------------------------------
// CMPXVideoSeeker::CMPXVideoSeeker
// C++ default constructor can NOT contain any code, that might leave.
// -------------------------------------------------------------------------------------------------
//
CMPXVideoSeeker::CMPXVideoSeeker( CMPXVideoPlaybackController* aVideoPlaybackCtlr )
    : iVideoPlaybackCtlr( aVideoPlaybackCtlr )
{
    MPX_DEBUG(_L("CMPXVideoSeeker::CMPXVideoSeeker()"));
}

// -------------------------------------------------------------------------------------------------
// CMPXVideoSeeker::ConstructL
// Symbian 2nd phase constructor can leave.
// -------------------------------------------------------------------------------------------------
//
void CMPXVideoSeeker::ConstructL()
{
    MPX_DEBUG(_L("CMPXVideoSeeker::ConstructL()"));

    iTrickPlayTimer = CPeriodic::NewL( CActive::EPriorityStandard );
    iSeekTimer = CPeriodic::NewL( CActive::EPriorityStandard );
}

// -------------------------------------------------------------------------------------------------
// CMPXVideoSeeker::NewL
// Two-phased constructor.
// -------------------------------------------------------------------------------------------------
//
CMPXVideoSeeker* CMPXVideoSeeker::NewL( CMPXVideoPlaybackController* aVideoPlaybackCtlr )
{
    MPX_DEBUG(_L("CMPXVideoSeeker::NewL()"));

    CMPXVideoSeeker* self = new( ELeave ) CMPXVideoSeeker( aVideoPlaybackCtlr );
    CleanupStack::PushL( self );
    self->ConstructL();
    CleanupStack::Pop();
    return self;
}

// -------------------------------------------------------------------------------------------------
// CMPXVideoSeeker::~CMPXVideoSeeker
// Destructor
// -------------------------------------------------------------------------------------------------
//
CMPXVideoSeeker::~CMPXVideoSeeker()
{
    MPX_DEBUG(_L("CMPXVideoSeeker::~CMPXVideoSeeker()"));

    if ( iTrickPlayTimer )
    {
        iTrickPlayTimer->Cancel();
        delete iTrickPlayTimer;
    }

    if ( iSeekTimer )
    {
        iSeekTimer->Cancel();
        delete iSeekTimer;
    }
}

// -------------------------------------------------------------------------------------------------
// CMPXVideoSeeker::StartSeeking
// -------------------------------------------------------------------------------------------------
//
void CMPXVideoSeeker::StartSeekingL( TBool aForward,
                                     TMPXVideoPlaybackState aState,
                                     TInt64 aPosition,
                                     TInt64 aDuration )
{
    MPX_DEBUG(_L("CMPXVideoSeeker::StartSeekingL() forward = (%d)"), aForward );

    TInt err = KErrNone;
    iPreviousState = aState;
    iForward = aForward;
    iPosition = aPosition;
    iDuration = aDuration;

#if TRICK_PLAY
    if ( iPreviousState == EMPXVideoPaused )
    {
        iVideoPlaybackCtlr->iPlayer->Play();
    }

    TInt trickplaySpeed = KDefaultTrickPlaySpeed;

    if ( !iForward )
    {
        trickplaySpeed *= -1;
    }

    //
    // Start trick play with 4x speed as default
    //
    MPX_TRAP( iVideoPlaybackCtlr->iPlayer->SetPlayVelocityL( trickplaySpeed ) );

#else
    if ( iPreviousState == EMPXVideoPlaying )
    {
        iVideoPlaybackCtlr->iPlayer->PauseL();
    }

    iIncrements = KSpeedAIncrements / 2;
    TInt interval = KSpeedInterval * 2;

    if ( !iForward )
    {
        iIncrements *= -1;
    }

    iSeekTimer->Start( 0,
                       interval,
                       TCallBack( CMPXVideoSeeker::UpdatePosition, this ) );
#endif

    if ( err == KErrNone )
    {
        iTrickPlayTimer->Start( KTrickPlayTimeout,
                                0,
                                TCallBack( CMPXVideoSeeker::StopTrickPlay, this ) );
    }
}

// -------------------------------------------------------------------------------------------------
// CMPXVideoSeeker::StopSeekingL
// -------------------------------------------------------------------------------------------------
//
void CMPXVideoSeeker::StopSeekingL()
{
    MPX_DEBUG(_L("CMPXVideoSeeker::StopSeekingL()"));

    TBool seekTimerActive = EFalse;

    if ( iTrickPlayTimer->IsActive() )
    {
        iTrickPlayTimer->Cancel();
    }

    if ( iSeekTimer->IsActive() )
    {
        seekTimerActive = ETrue;
        iSeekTimer->Cancel();
    }

    //
    // If it reaches the end of a clip, issue stop
    //
    if ( iDuration <= iPosition )
    {
        iVideoPlaybackCtlr->iState->HandleEndOfClip();
    }
    else
    {
        if ( seekTimerActive )
        {
            iVideoPlaybackCtlr->iPlayer->SetPositionL( iPosition );

            if ( iPreviousState == EMPXVideoPlaying )
            {
                iVideoPlaybackCtlr->DoHandleCommandL( EPbCmdPlay );
            }
            else if (iPreviousState == EMPXVideoPaused )
            {
                iVideoPlaybackCtlr->DoHandleCommandL( EPbCmdPause );
            }
            else
            {
                iVideoPlaybackCtlr->ChangeState( iPreviousState );
            }
        }

#if TRICK_PLAY
        else
        {
            //
            // Start trick play with default speed
            //
            MPX_TRAP( iVideoPlaybackCtlr->iPlayer->SetPlayVelocityL( KDefaultPlaySpeed ) );

            if ( iPreviousState == EMPXVideoPaused )
            {
                iVideoPlaybackCtlr->DoHandleCommandL( EPbCmdPause );
            }
            else if ( iPreviousState == EMPXVideoPlaying )
            {
                iVideoPlaybackCtlr->DoHandleCommandL( EPbCmdPlay );
            }
        }
#endif
    }

}

// -------------------------------------------------------------------------------------------------
// CMPXVideoSeeker::StopTrickPlay
// -------------------------------------------------------------------------------------------------
//
TInt CMPXVideoSeeker::StopTrickPlay( TAny* aPtr )
{
    MPX_DEBUG(_L("CMPXVideoSeeker::StopTrickPlay()"));

	static_cast<CMPXVideoSeeker*>(aPtr)->DoStopTrickPlay();

	return KErrNone;
}

// -------------------------------------------------------------------------------------------------
// CMPXVideoSeeker::DoStopTrickPlay
// -------------------------------------------------------------------------------------------------
//
void CMPXVideoSeeker::DoStopTrickPlay()
{
    MPX_DEBUG(_L("CMPXVideoSeeker::DoStopTrickPlay()"));

    TInt err = KErrNone;

    //
    // Stop trick play
    //
    if ( iTrickPlayTimer->IsActive() )
    {
        iTrickPlayTimer->Cancel();
    }

#if TRICK_PLAY
    MPX_TRAP( err,
              iVideoPlaybackCtlr->iPlayer->SetPlayVelocityL( KDefaultPlaySpeed );
              iVideoPlaybackCtlr->iPlayer->PauseL() );
#endif

    if ( err == KErrNone )
    {
        ConvertToSeeking();
    }
}

// -------------------------------------------------------------------------------------------------
// CMPXVideoSeeker::ConvertToSeeking
// -------------------------------------------------------------------------------------------------
//
void CMPXVideoSeeker::ConvertToSeeking()
{
    MPX_DEBUG(_L("CMPXVideoSeeker::ConvertToSeeking()"));

    //
    // Start seeking (increments in every 125 msec)
    // - ~ 90sec      : Increment is 2 sec
    // - 91sec~180sec : Increment is 4 sec
    // - 181sec~      : Increment depends on the duration
    //                  ( 0.5 % * duration ) + 3 sec
    //
    if ( iDuration < KDurationA )
    {
        iIncrements = KSpeedAIncrements;
    }
    else
    {
        if ( iDuration < KDurationB )
        {
            iIncrements = KSpeedBIncrements;
        }
        else
        {
            iIncrements = (TInt)( iDuration / 200 ) + 3;
        }
    }

    if ( !iForward )
    {
        iIncrements *= -1;
    }

    if ( iSeekTimer->IsActive() )
    {
        iSeekTimer->Cancel();
    }

    iSeekTimer->Start( 0, KSpeedInterval, TCallBack( CMPXVideoSeeker::UpdatePosition, this ) );
}

// -------------------------------------------------------------------------------------------------
// CMPXVideoSeeker::UpdatePosition
// -------------------------------------------------------------------------------------------------
//
TInt CMPXVideoSeeker::UpdatePosition( TAny* aPtr )
{
    MPX_DEBUG(_L("CMPXVideoSeeker::UpdatePosition()"));

    static_cast<CMPXVideoSeeker*>(aPtr)->DoUpdatePosition();
    return KErrNone;
}

// -------------------------------------------------------------------------------------------------
// CMPXVideoSeeker::DoUpdatePosition
// -------------------------------------------------------------------------------------------------
//
void CMPXVideoSeeker::DoUpdatePosition()
{
    MPX_DEBUG(_L("CMPXVideoSeeker::DoUpdatePosition()"));

    iPosition += iIncrements;

    if ( iPosition > iDuration )
    {
        iPosition = iDuration;
    }
    else if ( iPosition < 0 )
    {
        iPosition = 0;
    }

    iVideoPlaybackCtlr->iPlaybackMode->UpdateSeekPosition( iPosition );
}

//  End of File
