// Pager.cpp : Implementation of cPager
#include "stdafx.h"
#include "Inject.h"
#include "Pager.h"

/////////////////////////////////////////////////////////////////////////////
// cPager

// The velocity of the scroll in pixels/sec
#define VELOCITY  500

void cPager::setupScroll( long nCommand, LPPOINT pptDest )
{
   _ASSERTE( pptDest != NULL );

   m_ptScrollFrom = m_ptCurrent;
   m_dwTimeStart = ::timeGetTime();

   m_ptScrollTo = *pptDest;

   // Figure out the time to completion
   int dx = m_ptScrollTo.x - m_ptScrollFrom.x,
      dy = m_ptScrollTo.y - m_ptScrollFrom.y;

   m_dwTimeEnd = m_dwTimeStart + static_cast< DWORD >( sqrt( static_cast< double >( dx * dx + dy * dy ) ) ) * 1000 / VELOCITY;

   // Clear command options
   m_nCommand = nCommand;
   m_bContinue = ( nCommand == 0 ) ? VARIANT_FALSE : VARIANT_TRUE;

   m_bScrolling = VARIANT_TRUE;
}

void cPager::updatePosition()
{
   long nID;
   m_pSite->get_ID( &nID );
   Fire_Change( nID, m_nCommand, m_ptCurrent.x, m_ptCurrent.y );

   m_pSite->Invalidate();
}

void cPager::endScroll()
{
   if( m_bScrolling )
   {
      m_bScrolling = VARIANT_FALSE;
      m_ptCurrent = m_ptScrollTo;
   }

   updatePosition();
   m_nCommand = 0;
}

void cPager::onCreate()
{
   m_ptCurrent.x = 0;
   m_ptCurrent.y = 0;

   m_dwTimeStart = 0;
   m_dwTimeEnd = 0;

   m_bScrolling = VARIANT_FALSE;
   m_bContinue = VARIANT_FALSE;
   m_nCommand = 0;
}

STDMETHODIMP cPager::ScrollTo(LPPOINT pVal)
{
   setupScroll( 0, pVal );
   
	return S_OK;
}

STDMETHODIMP cPager::get_Command(long *pVal)
{
   _ASSERTE( pVal != NULL );
   *pVal = m_nCommand;

	return S_OK;
}

STDMETHODIMP cPager::put_Command(long nCommand)
{
   // ::MessageBox( NULL, _T( "cPager::SetCommand" ), _T( "Inject.dll" ), MB_OK );
   m_bContinue = VARIANT_TRUE;

   if( nCommand != m_nCommand )
   {
      // Prompt the callback to get a destination
      long nID;
      m_pSite->get_ID( &nID );

      POINT ptDest;
      VARIANT_BOOL bContinue;

      bContinue = Fire_GetNextPosition( nID, nCommand, &ptDest.x, &ptDest.y );

      if( !bContinue )
         endScroll();
      else
         setupScroll( nCommand, &ptDest );
   }

	return S_OK;
}

STDMETHODIMP cPager::FinishCommand()
{
   m_bContinue = VARIANT_FALSE;

	return S_OK;
}

STDMETHODIMP cPager::PreRender()
{
   if( !m_bScrolling )
      // No scrolling means no drawing
      return S_OK;

   // Calculate the new position
   DWORD dwTime = ::timeGetTime();

   // We loop until we've used up our animation time
   // so animations with short steps - a single frame
   // may exceed a small step.
   while( dwTime >= m_dwTimeEnd )
   {
      long nCommand = m_nCommand;
      endScroll();

      // This section of the scroll is complete
      if( !m_bContinue )
      {
         _ASSERTMEM( _CrtCheckMemory( ) );
         return S_OK;
      }

      // Check for a next destination
      POINT ptDest;

      long nID;
      m_pSite->get_ID( &nID );

      VARIANT_BOOL bContinue = VARIANT_FALSE;

      bContinue = Fire_GetNextPosition( nID, nCommand, &ptDest.x, &ptDest.y );

      if( bContinue )
      {
         DWORD dwLastEnd = m_dwTimeEnd;

         // ::MessageBox( NULL, _T( "cPager::Render" ), _T( "Inject.dll" ), MB_OK );
         setupScroll( nCommand, &ptDest );

         DWORD dwOver = m_dwTimeStart - dwLastEnd;

         // Adjust the time to eliminate the stutter for the next section
         m_dwTimeStart -= dwOver;
         m_dwTimeEnd -= dwOver;
      }
      else
      {
         _ASSERTMEM( _CrtCheckMemory( ) );
         return S_OK;
      }
   }

   // Do a time linear interpolation to figure out the current position
   long nTotalTime = m_dwTimeEnd - m_dwTimeStart,
      nCurrentTime = dwTime - m_dwTimeStart;

   m_ptCurrent.x = m_ptScrollFrom.x + ( m_ptScrollTo.x - m_ptScrollFrom.x ) * nCurrentTime / nTotalTime;
   m_ptCurrent.y = m_ptScrollFrom.y + ( m_ptScrollTo.y - m_ptScrollFrom.y ) * nCurrentTime / nTotalTime;

   updatePosition();

   _ASSERTMEM( _CrtCheckMemory( ) );

   return S_OK;
}

STDMETHODIMP cPager::AdjustRenderArea( ICanvas *pCanvas, VARIANT_BOOL *pbDrawChildren )
{
   pCanvas->OffsetOrg( &m_ptCurrent, pbDrawChildren );

   return S_OK;
}

STDMETHODIMP cPager::get_Offset(LPPOINT pVal)
{
   _ASSERTE( pVal != NULL );
   *pVal = m_ptCurrent;

	return S_OK;
}

STDMETHODIMP cPager::put_Offset(LPPOINT newVal)
{
   // Terminate scrolling
   endScroll();
   m_ptCurrent = *newVal;

   // Dispatch changes
   updatePosition();

	return S_OK;
}

STDMETHODIMP cPager::CreateClient(ILayer *pLayer)
{
	// TODO: Add your implementation code here

	return S_OK;
}
