/*
* Copyright (c) 2006-2007 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:  Emulate key and pointer event.
*
*/


#include <eikon.hrh>

#include "AutotestCommands.h" // test commands are defined in here
#include "bctestkeyfeeder.h"
#include "bctestlogger.h"
#include "bctestsuite.h"

const TInt KInitDelay = 1000000; // 1 second
const TInt KInterval = 100000; // 1/10 second
const TInt KTickCount = 10; // default one second between key feeds
const TText KKey1 = '1';
const TText KKey2 = '2';
const TText KKey3 = '3';
const TText KKey4 = '4';
const TText KKey5 = '5';
const TText KKey6 = '6';
const TText KKey7 = '7';
const TText KKey8 = '8';
const TText KKey9 = '9';
const TText KKey0 = '0';
const TText KKeyAsterisk = '*';
const TText KKeyHash = '#';

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

// ---------------------------------------------------------------------------
// C++ default constructor
// ---------------------------------------------------------------------------
//
CBCTestKeyFeeder::CBCTestKeyFeeder()
    {
    }

// ---------------------------------------------------------------------------
// Destructor
// ---------------------------------------------------------------------------
//
CBCTestKeyFeeder::~CBCTestKeyFeeder()
    {
    if ( iPeriodic )
        {
        iPeriodic->Cancel();
        delete iPeriodic;
        }
    }

// ---------------------------------------------------------------------------
// CBCTestKeyFeeder::StartAutoTestL
// Initialize member variables and start timer.
// ---------------------------------------------------------------------------
//
void CBCTestKeyFeeder::StartAutoTestL( SAutoTest* aAutoTest )
    {    
    if ( aAutoTest )
        {
        iAutoTest = aAutoTest;        
        iScriptCommands = iAutoTest->scripts[0];        
        }    
    if ( !iAutoTest || !iScriptCommands )
        {
        return;
        }   
    
    iSuite->HandleTestEventL( ETestCaseStart, iScriptIndex );
    
    if ( iPeriodic )
        {
        iPeriodic->Cancel();
        delete iPeriodic;
        iPeriodic = NULL;
        }
    iPeriodic=CPeriodic::NewL( CActive::EPriorityHigh );
    // Start periodic function after 1 seconds and after that call
    // it every 1/10th of second    
    iPeriodic->Start( KInitDelay, KInterval, TCallBack( 
        PeriodicKeyFeederL, this ) );

    // member variables don't need to be cleared before use,
    // but do it anyway - just in case
    iIndex = 0;
    iScriptIndex = 0;
    iCommand = 0;
    iRepeatCommand = 0;
    iRepeat = 0;
    iWaitCount = 0;
    
    iTickCount = KTickCount;
    iTickCounter = iTickCount;

    iKeyUp = EFalse;
    iKeyDown = EFalse;
    
    // ensure sane values for conditional stuff
    iIfCount = 0;    
    
    if ( !iEikEnv )
        {
        iEikEnv = CEikonEnv::Static();
        }    
    }

// ---------------------------------------------------------------------------
// CBCTestKeyFeeder::PeriodicKeyFeeder
// This method is called every 0.1 seconds, calls HandleAutoCommand
// ---------------------------------------------------------------------------
//
TInt CBCTestKeyFeeder::PeriodicKeyFeederL( TAny* aThis )
    {
    CBCTestKeyFeeder* feeder = 
        static_cast<CBCTestKeyFeeder*>( aThis );

    feeder->HandleAutoCommandL();
    return 0;
    }

// ---------------------------------------------------------------------------
// CBCTestKeyFeeder::HandleAutoCommand
// Does the actual key feeding
// ---------------------------------------------------------------------------
//
void CBCTestKeyFeeder::HandleAutoCommandL()
    {    
    if ( iTimerPaused ) // timer paused, do nothing
        {
        return;
        }
    if ( iTickCounter > 0 )
        {
        iTickCounter--;
        return; // tick count not yet full, do nothing
        }
    iTickCounter=iTickCount; // reset tick counter and continue

    //commands in one script done
    if ( iIndex >= iAutoTest->countArray[iScriptIndex] )
        {
        iSuite->HandleTestEventL( ETestCaseEnd, iScriptIndex );
        iScriptIndex++;      
        TBool continueRun = ETrue;        
        if ( iScriptIndex >= iAutoTest->scriptCount ) // all scripts done
            {
            continueRun = EFalse;            
            }
        else
            {            
            iScriptCommands = iAutoTest->scripts[iScriptIndex];            
            iIndex = 0; 
            if ( !iScriptCommands )
                {                
                iSuite->HandleTestEventL( ETestCaseNoScript, iScriptIndex );
                iIndex = iAutoTest->countArray[iScriptIndex];              
                }
            else
                {
                iSuite->HandleTestEventL( ETestCaseStart, iScriptIndex );
                }
            }        
        
        if ( iIfCount != 0 )
            {
            iSuite->HandleTestEventL( 
                ETestCaseUnbalancedIf, iScriptIndex - 1 );            
            iIfCount = 0;
            }
        
        if ( !continueRun )
            {
            iPeriodic->Cancel(); // stop periodic timer
            }
                
        return;
        }

    if ( iWaitCount > 0 ) // still waiting (WAIT command)
        {
        iWaitCount--;
        return;    // waiting - do nothing
        }

    if ( iRepeat == 0 ) // not repeating, parse next command
        {
        iCommand = iScriptCommands[iIndex];
        iIndex++;
        }
    else // still doing REPEAT
        {
        iCommand = iRepeatCommand; // command being repeated
        iRepeat--;
        }
    
    switch ( iCommand )
        {
        case LeftCBA:
            KeyPress( EKeyDevice0, EStdKeyDevice0 );
            break;
        case RightCBA:
            KeyPress( EKeyDevice1, EStdKeyDevice1 );
            break;
        case KeyOK:
            KeyPress( EKeyDevice3, EStdKeyDevice3 );
            break;
        case Up:
            KeyPress( EKeyUpArrow, EStdKeyUpArrow );
            break;
        case Down:
            KeyPress( EKeyDownArrow, EStdKeyDownArrow );
            break;
        case Left:
            KeyPress( EKeyLeftArrow, EStdKeyLeftArrow );
            break;
        case Right:
            KeyPress( EKeyRightArrow, EStdKeyRightArrow );
            break;
        case Key1:
            KeyPress( KKey1, KKey1 );
            break;
        case Key2:
            KeyPress( KKey2, KKey2 );
            break;
        case Key3:
            KeyPress( KKey3, KKey3 );
            break;
        case Key4:
            KeyPress( KKey4, KKey4 );
            break;
        case Key5:
            KeyPress( KKey5, KKey5 );
            break;
        case Key6:
            KeyPress( KKey6, KKey6 );
            break;
        case Key7:
            KeyPress( KKey7, KKey7 );
            break;
        case Key8:
            KeyPress( KKey8, KKey8 );
            break;
        case Key9:
            KeyPress( KKey9, KKey9 );
            break;
        case Key0:
            KeyPress( KKey0, KKey0 );
            break;
        case KeyAsterisk:
            KeyPress( KKeyAsterisk, EStdKeyNkpAsterisk );
            break;
        case KeyHash:
            KeyPress( KKeyHash, EStdKeyHash );
            break;
        case KeyApplication:
            KeyPress( EKeyApplication, EStdKeyApplication0 );
            break;
        case KeyPhoneSend:
            KeyPress( EKeyPhoneSend, EStdKeyYes );
            break;
        case KeyPhoneEnd:
            KeyPress( EKeyPhoneEnd, EStdKeyNo );
            break;
        case KeyPower:
            KeyPress( EKeyPowerOff, EStdKeyDevice2 );
            break;
        case KeyVoice:
            KeyPress( EKeySide, EStdKeyDevice6 );
            break;
        case KeyBackspace:
            KeyPress( EKeyBackspace, EStdKeyBackspace );
            break;
        case KeyABC:  // may not work as ABC key, should work as shift, tough
            KeyPress( EStdKeyRightShift, EStdKeyRightShift );
            break;
        case GripOpen:
            KeyPress( EKeyGripOpen, EStdKeyDevice4 );
            break;
        case GripClose:
            KeyPress( EKeyGripClose, EStdKeyDevice5 );
            break;
        case REPEAT: // one round missed because no commands executed
            iRepeatCommand = iScriptCommands[iIndex++];
            iRepeat = iScriptCommands[iIndex++];
            break;
        case WAITCOMMAND:
            iWaitCount = iScriptCommands[iIndex++];
            break;        
        case SETTICKCOUNT:
            iTickCount = iScriptCommands[iIndex++];
            iTickCounter = iTickCount;
            break;
        case JUSTKEYDOWN:
            iKeyDown = ETrue;
            break;
        case JUSTKEYUP:
            iKeyUp = ETrue;            
            break;        
        case PointerDown:
        	{
        	TInt pointerX = iScriptCommands[iIndex++];
        	TInt pointerY = iScriptCommands[iIndex++];
        	TRawEvent event;
        	event.Set( TRawEvent::EButton1Down, pointerX, pointerY );
        	PointerEvent( event );
        	}
        	break;
        case PointerUp:    
        	{
        	TInt pointerX = iScriptCommands[iIndex++];
        	TInt pointerY = iScriptCommands[iIndex++];
        	TRawEvent event;
        	event.Set( TRawEvent::EButton1Up, pointerX, pointerY );
        	PointerEvent( event );
        	}
            break;
        case PointerMove:
	    	{
        	TInt pointerX = iScriptCommands[iIndex++];
        	TInt pointerY = iScriptCommands[iIndex++];
        	TRawEvent event;
        	event.Set( TRawEvent::EPointerMove, pointerX, pointerY );
        	PointerEvent( event );
	    	break;	
	    	}        
        default:
            break;
        }
    }

/******************* autotest key feeder implementations ********************/

// ---------------------------------------------------------------------------
// CBCTestKeyFeeder::KeyDown
// ---------------------------------------------------------------------------
//
void CBCTestKeyFeeder::KeyDown( TInt aScanCode )
    {
    if ( aScanCode == EStdKeyRightShift )
        {
        iOldModifiers = iEikEnv->WsSession().GetModifierState();
        iModifiers = EModifierShift | iOldModifiers;
        }
    
    TRawEvent event;
    event.Set( TRawEvent::EKeyDown, aScanCode );
    iEikEnv->WsSession().SimulateRawEvent( event );
    }

// ---------------------------------------------------------------------------
// CBCTestKeyFeeder::KeyUp
// ---------------------------------------------------------------------------
//
void CBCTestKeyFeeder::KeyUp( TInt aScanCode )
    {
    if ( aScanCode == EStdKeyRightShift )
        {
        iModifiers = iOldModifiers;
        }

    TRawEvent event;
    event.Set( TRawEvent::EKeyUp, aScanCode );
    iEikEnv->WsSession().SimulateRawEvent( event );
    }

// ---------------------------------------------------------------------------
// CBCTestKeyFeeder::KeyPress
// ---------------------------------------------------------------------------
//
void CBCTestKeyFeeder::KeyPress( TInt aCode, TInt aScanCode )
    {
    User::ResetInactivityTime();// Reset user inactivity timers

    if ( iKeyDown ) // Long key press -> do just key down
        {
        KeyDown( aScanCode );
        iKeyDown = EFalse;
        return; // ends key press
        }

    if ( iKeyUp ) // Ends long key press -> do just key up
        {
        KeyUp( aScanCode );
        iKeyUp = EFalse;
        return; // ends key press
        }

    // there seems to be no keycode for abc-key, simulate by pressing
    // key down and up
    if ( aCode == EStdKeyRightShift )
        {
        KeyDown( aCode );
        KeyUp( aCode );
        return; 
        }

    // Do normal key press
    TKeyEvent event = { aCode, aScanCode, iModifiers, 0 };
    iEikEnv->WsSession().SimulateKeyEvent( event );
    }

// ---------------------------------------------------------------------------
// CBCTestKeyFeeder::PauseTimer
// ---------------------------------------------------------------------------
//
void CBCTestKeyFeeder::PauseTimer()
    {
    iTimerPaused = ETrue;
    }

// ---------------------------------------------------------------------------
// CBCTestKeyFeeder::ResumeTimer
// ---------------------------------------------------------------------------
//
void CBCTestKeyFeeder::ResumeTimer()
    {
    iTimerPaused = EFalse;
    }

// ---------------------------------------------------------------------------
// CBCTestKeyFeeder::PointerEvent
// ---------------------------------------------------------------------------
//
void CBCTestKeyFeeder::PointerEvent( TRawEvent& aEvent )
	{	
    iEikEnv->WsSession().SimulateRawEvent( aEvent );
	}

// ---------------------------------------------------------------------------
// CBCTestKeyFeeder::SetSuite
// ---------------------------------------------------------------------------
//
void CBCTestKeyFeeder::SetSuite( CBCTestSuite* aSuite )
    {
    iSuite = aSuite;
    }
