// Copyright (c) 2010 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:
//

/**
 @file
 @test
 @internalComponent - Internal Nokia test code 
*/

#include <w32std.h>

#include <wspublishandsubscribedata.h>
#include "trenderorientation.h"

const TInt KPublishTimeout  = 1000000;  // 1 second in microseconds
const TInt KNumIterations   = 20;

// Values for the device orientation that we receive via P&S from the Theme Server
// Must match those in renderorientationtracker.h, and, obviously, those used by the real theme server 
const TUid  KThemeOrientationCategory   = {0x20022E82}; // == KHbPsHardwareCoarseOrientationCategoryUid 
const TUint KThemeOrientationKey        = 0x4F726965; // == KHbPsHardwareCoarseOrientationKey 

void CWindowStuff::ConstructL()
    {
    User::LeaveIfError(iWs.Connect());
    iWs.SetAutoFlush(ETrue);
    
    iWindowGroup = RWindowGroup(iWs);
    User::LeaveIfError(iWindowGroup.Construct(reinterpret_cast<TUint32>(&iWindowGroup)));
    
    iChildWindow = RWindow(iWs);
    User::LeaveIfError(iChildWindow.Construct(iWindowGroup, reinterpret_cast<TUint32>(&iChildWindow)));
    }

CWindowStuff::~CWindowStuff()
    {
    Destroy();
    }

void CWindowStuff::Destroy()
    {
    iChildWindow.Close();
    iWindowGroup.Close();
    iWs.Close();    
    }

CTRenderOrientation::CTRenderOrientation()
    {
    // check that these two enums are aligned
    __ASSERT_COMPILE(EDisplayOrientationAuto == ENumWindowThings);
    
    SetTestStepName(KTRenderOrientation);
    }

CTRenderOrientation::~CTRenderOrientation()
    {
    }

TRenderOrientation CTRenderOrientation::GetRenderOrientationL()
    {    
    return GetOrientationL(iWsRenderOrientationProperty);    
    }

TRenderOrientation CTRenderOrientation::GetThemeOrientationL()
    {    
    return GetOrientationL(iThemeOrientationProperty);    
    }

TRenderOrientation CTRenderOrientation::GetOrientationL(RProperty& aProperty)
    {
    TInt orientation=EDisplayOrientationNormal;
    User::LeaveIfError(aProperty.Get(orientation));
    
    TESTL(orientation >= EDisplayOrientationNormal);
    TESTL(orientation < EDisplayOrientationAuto);    
    
    return static_cast<TRenderOrientation>(orientation);    
    }

void CTRenderOrientation::TestOrientationChangeL(const TDesC& aStepName, TTestPhase aTestPhase)
    {
    SetTestStepID(aStepName);
    
    if(EThemeOrientationChange == aTestPhase)
        {               
        TESTL(EDisplayOrientationNormal == GetThemeOrientationL());
        iWindowStuff[EFirstWindowThing].Session().IndicateAppOrientation(EDisplayOrientationAuto);        
        }
    
    TInt renderOrientation = GetRenderOrientationL();
    
    // For consistancy, check that we are starting from the same orientation
    TESTL(EDisplayOrientationNormal == renderOrientation);    
    
    // Set-up the timer
    iProfiler->InitResults();
    iTimingsTaken = 0;    
    
    // repeat numerous times to get a decent average
    for(TInt iterations=0; iterations < KNumIterations; ++iterations)
        {
        renderOrientation = GetRenderOrientationL();
        // For consistancy, check that we are starting from the same orientation
        TESTL(EDisplayOrientationNormal == renderOrientation);           
        
        // loop through the orientations, ending up changing back to normal
        for(++renderOrientation; renderOrientation <= EDisplayOrientationAuto; ++renderOrientation)
            {
            // % can be slow, do it outside of the timing
            TRenderOrientation testOrientation = static_cast<TRenderOrientation>(renderOrientation%EDisplayOrientationAuto);
            
            iWsRenderOrientationProperty.Subscribe(iRenderOrientationStatus);            
            // start the timeout timer
            iTimeoutTimer.After(iTimeoutStatus, KPublishTimeout);
            // start the results timer
            iProfiler->StartTimer();
            
            switch(aTestPhase)
                {
                case EIndicatedOrientationChange:
                    // Do the indicated orientation Change
                    iWindowStuff[EFirstWindowThing].Session().IndicateAppOrientation(testOrientation);
                    break;
                    
                case EWindowOrdinalChange:
                    // move the relevant window group to the front
                    // N.B. this will go wrong if the number of orientations and windows are not equal
                    iWindowStuff[testOrientation].WindowGroup().SetOrdinalPosition(0);
                    break;
                    
                case EThemeOrientationChange:
                    // Needs the focus window to be in auto mode
                    iThemeOrientationProperty.Set(testOrientation);
                    break;
                    
                default:
                    TESTL(EFalse);
                }
        
            // Wait for the update to have been published ( or time out while waiting )
            User::WaitForRequest(iRenderOrientationStatus, iTimeoutStatus);
            
            iProfiler->MarkResultSetL();
            ++iTimingsTaken;
            
            if(KErrNone != iRenderOrientationStatus.Int())
                {
                // timed out
                iWsRenderOrientationProperty.Cancel();                
                TESTL(EFalse);
                }
            else
                {
                // Check that it is actually the expected orientation
                TESTL(GetRenderOrientationL() == testOrientation);
                }

            if(KRequestPending == iTimeoutStatus.Int())
                {
                // as expected, so cancel the timeout timer
                iTimeoutTimer.Cancel();
                }
            else
                {
                // timed out
                TESTL(EFalse);
                }
            }
        }    
    
    // wrap it up    
    iProfiler->ResultsAnalysis(KTRenderOrientation,KErrNotFound,ENone,ENone,iTimingsTaken);
    }

TVerdict CTRenderOrientation::doTestStepL()
    {     
    INFO_PRINTF1(_L("Testing: Indicated Orientation Change"));
    TestOrientationChangeL(_L("GRAPHICS-UI-BENCH-0xxx1"), EIndicatedOrientationChange);
    
    INFO_PRINTF1(_L("Testing: Window Ordinal Position Change"));
    TestOrientationChangeL(_L("GRAPHICS-UI-BENCH-0xxx2"), EWindowOrdinalChange);
    
    INFO_PRINTF1(_L("Testing: Theme Orientation Change"));
    TestOrientationChangeL(_L("GRAPHICS-UI-BENCH-0xxx3"), EThemeOrientationChange);
    
    return TestStepResult();    
    }

_LIT(KThemeServerPropertyDefine, "twsthemeserverpropertydefine.exe");
_LIT(KThemeServerPropertyDefineCmdDefine, "define");
_LIT(KThemeServerPropertyDefineCmdDelete, "delete");   
   
void CTRenderOrientation::ThemeServerProperty(const TDesC& aCmd)
    {
    /* This Process called with the argument KThemeServerPropertyDefineCmdDelete, deletes 
       the theme server RProperty. This is because an RProperty can only be defined and 
       deleted from within a process with the same UID3 as the RProperty catogory you are 
       trying to define/delete.*/
    RProcess themeServerPropertyDefine;
    TInt err = themeServerPropertyDefine.Create(KThemeServerPropertyDefine, aCmd);
    if (KErrNone != err)
        {
        _LIT(KLog, "themeServerPropertyDefine.Create() failed with error: %d");
        INFO_PRINTF2(KLog, err);
        TEST(EFalse);        
        }
    
    //wait for themeServerPropertyDefine process to terminate
    TRequestStatus themeServerPropertyDefineLogonStatus;
    themeServerPropertyDefine.Logon(themeServerPropertyDefineLogonStatus);
    themeServerPropertyDefine.Resume();
    User::WaitForRequest(themeServerPropertyDefineLogonStatus);
    if (themeServerPropertyDefineLogonStatus != KErrNone)
        {
        _LIT(KLog, "themeServerPropertyDefine.Logon() failed with error: %d");
        INFO_PRINTF2(KLog, themeServerPropertyDefineLogonStatus);
        TEST(EFalse);        
        }
    themeServerPropertyDefine.Close();    
    }

TVerdict CTRenderOrientation::doTestStepPreambleL()
    {
    // Create in reverse order so that windowThing 0 is at the front
    for(TInt windowThing = ENumWindowThings - 1; windowThing >= 0 ; --windowThing)
        {
        iWindowStuff[windowThing].ConstructL();
        TRenderOrientation orientation = static_cast<TRenderOrientation>(windowThing%EDisplayOrientationAuto);
        iWindowStuff[windowThing].Session().IndicateAppOrientation(orientation);
        iWindowStuff[windowThing].WindowGroup().SetOrdinalPosition(0);
        }
    
    User::LeaveIfError(iWsRenderOrientationProperty.Attach(KRenderOrientationCategory, KRenderOrientationKey));
    
    ThemeServerProperty(KThemeServerPropertyDefineCmdDefine);
    User::LeaveIfError(iThemeOrientationProperty.Attach(KThemeOrientationCategory, KThemeOrientationKey));
    
    User::LeaveIfError(iTimeoutTimer.CreateLocal());
    
    return CTe_graphicsperformanceSuiteStepBase::doTestStepPreambleL();
    }

TVerdict CTRenderOrientation::doTestStepPostambleL()
    {
    iTimeoutTimer.Close();
    
    iThemeOrientationProperty.Close();
    ThemeServerProperty(KThemeServerPropertyDefineCmdDelete);    
    iWsRenderOrientationProperty.Close();
    
    for(TInt windowThing = 0; windowThing < ENumWindowThings; ++windowThing)
        {
        iWindowStuff[windowThing].Destroy();
        }
    
    return CTe_graphicsperformanceSuiteStepBase::doTestStepPostambleL();
    }
