/*
* 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 the License "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 scrolling decelerator
*
*/


// INCLUDE FILES
#include <../bidi.h>
#include "WebScrollingDeceleratorGH.h"
#include "WebView.h"
#include "WebFrame.h"
#include "WebFrameView.h"
#include "WebPageScrollHandler.h"
#include "PlatformScrollbar.h"
#include "WebScrollbarDrawer.h"

#include "WebKitLogger.h"

// constants
const int KRecordSize = 4;

// The following deceleration curve is generated by a script
// It lists the timeout dt values in microseconds.
const int KDecelCurveSize = 10;

const int KScrollIntervalTimeout = 60000; // scroll timer interval in microseconds

const float KDecceleration = -750.0;
const float KSpeedHigh = 2000.0;

int decelTimerCB(TAny* ptr);


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

// -----------------------------------------------------------------------------
// WebScrollingDeceleratorGH::NewL
// The two-phase Symbian constructor
// -----------------------------------------------------------------------------
//

WebScrollingDeceleratorGH* WebScrollingDeceleratorGH::NewL(WebView& webView)
{
    WebScrollingDeceleratorGH* self = new (ELeave) WebScrollingDeceleratorGH(webView);

    CleanupStack::PushL(self);
    self->ConstructL();
    CleanupStack::Pop(); //self
    return self;
}

// -----------------------------------------------------------------------------
// WebScrollingDeceleratorGH::WebScrollingDeceleratorGH
// C++ default constructor can NOT contain any code, that
// might leave.
// -----------------------------------------------------------------------------
//
WebScrollingDeceleratorGH::WebScrollingDeceleratorGH(WebView& webView)
:  m_webView( webView )
{
}

// -----------------------------------------------------------------------------
// WebScrollingDeceleratorGH::ConstructL
// -----------------------------------------------------------------------------
void WebScrollingDeceleratorGH::ConstructL()
{
    m_decelTimer = CPeriodic::NewL(CActive::EPriorityStandard);
    m_deceleration = KDecceleration;
}

// -----------------------------------------------------------------------------
// Destructor
// -----------------------------------------------------------------------------
WebScrollingDeceleratorGH::~WebScrollingDeceleratorGH()
{
    delete m_decelTimer;
}


int WebScrollingDeceleratorGH::getDecceleration()
{
   return  m_deceleration;  
}


int decelTimerCB(TAny* ptr)
{
    (static_cast<WebScrollingDeceleratorGH*>(ptr))->scroll();
    return false;
}


void WebScrollingDeceleratorGH::cancelDecel() 
{ 
    m_decelelatorSwitch = false;
    if (m_decelTimer->IsActive()) {
        m_webView.setScrolling(false);
		m_webView.resumeJsTimers();		
        m_decelTimer->Cancel();
    }
}

void WebScrollingDeceleratorGH::startDecel(TRealPoint& speed, WebScrollbarDrawer* scrollbarDrawer)
{
    m_decelelatorSwitch = true;
    m_scrollbarDrawer = scrollbarDrawer;
    float speedX = speed.iX;
    float speedY = speed.iY;
    float absSpeedX = abs(speedX);
    float absSpeedY = abs(speedY);
    
    if (absSpeedX > KSpeedHigh) {
        speedX = KSpeedHigh * speedX/absSpeedX ;
    }
    if (absSpeedY > KSpeedHigh) {
        speedY = KSpeedHigh * speedY/absSpeedY;
    }
    
    m_initSpeed.iX = (-1) * speedX;
    m_initSpeed.iY = (-1) * speedY;
    
    m_numscrollsteps = 0;
    if (m_decelTimer->IsActive()) {
        m_webView.setScrolling(false);
    	m_webView.resumeJsTimers();
        m_decelTimer->Cancel();
    }
    
    WebFrameView* scrollingView = m_webView.pageScrollHandler()->currentScrollingFrameView();
    if (scrollingView) {
        m_webView.pauseJsTimers(); // pause the JS timers
        m_webView.setScrolling(true);
        m_startPos = scrollingView->contentPos();
        m_lastPos = m_startPos;
        m_decelTimer->Start(0, KScrollIntervalTimeout, 
                            TCallBack(&decelTimerCB, this));
    }
}

void WebScrollingDeceleratorGH::scroll()
{
    if (!m_decelelatorSwitch) return;
    // X = Vst*t - 0.5*a*(t * t)    
    TPoint dist;
    TReal32 intervalInSec = static_cast<TReal32>(KScrollIntervalTimeout) / 1000000;
    TReal32 t = (m_numscrollsteps++) * intervalInSec;
    TReal32 dx = 0.0;
    TReal32 dy = 0.0;
    TReal32 vx = 0.0;
    TReal32 vy = 0.0;
    TReal32 accelX = 0.0;
    TReal32 accelY = 0.0;
    
    TReal32 deceleration = getDecceleration();
    
    if (m_initSpeed.iX) {
        accelX = (m_initSpeed.iX > 0) ?  deceleration : (-1) * deceleration;
        vx = m_initSpeed.iX + accelX * t;
        dx = m_initSpeed.iX * t + 0.5 * accelX * (t * t);
    }
        
    if (m_initSpeed.iY) {
        accelY = (m_initSpeed.iY > 0) ?  deceleration : (-1) * deceleration;
        vy = m_initSpeed.iY + accelY * t;
        dy = m_initSpeed.iY * t + 0.5 * accelY * (t * t);
    }
    
    dist.SetXY(static_cast<TInt>(dx), static_cast<TInt>(dy));
    
    WebFrameView* scrollingView = m_webView.pageScrollHandler()->currentScrollingFrameView();
    TPoint cpos = scrollingView->contentPos();
    dist = scrollingView->toDocCoords(dist);
    TPoint pos = m_startPos + dist;
   
    WebPageScrollHandler* handler = m_webView.pageScrollHandler();

    if ((vx * m_initSpeed.iX < 0) || (vy * m_initSpeed.iY < 0) || (vx + vy == 0) || 
        (m_numscrollsteps > 1 && !scrollingView->needScroll(pos) && 
        !handler->currentScrollingElement())) {
        if (m_scrollbarDrawer) {
            m_scrollbarDrawer->fadeScrollbar();
        }
		
        m_webView.resumeJsTimers(); // resume the js timers
        m_webView.setScrolling(false);
        m_decelTimer->Cancel();
        handler->clearScrollingElement();
        m_webView.setViewIsScrolling(false);
        m_webView.toggleRepaintTimer(true);
    }
    else {
        TPoint scrollDelta = pos - m_lastPos;
        handler->scrollContent(scrollDelta);
        m_lastPos = pos;
    }  
}


//  End of File
