//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft shared
// source or premium shared source license agreement under which you licensed
// this source code. If you did not accept the terms of the license agreement,
// you are not authorized to use this source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the SOURCE.RTF on your install media or the root of your tools installation.
// THE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES OR INDEMNITIES.
//
// --------------------------------------------------------------------
//
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
// Copyright (c) 1996-2003 Microsoft Corporation.  All rights reserved.
//
// --------------------------------------------------------------------


#include <windows.h>
#include <time.h>
#include <tchar.h>
#include <tux.h>
#include "main.h"
#include "globals.h"
#include "pwrtstutil.h"

#define CLOCKS_PER_SEC  1000

#define ERROR_GEN_FAILURE                31L
#define ERROR_SUCCESS                    0L
#define ERROR_SERVICE_DOES_NOT_EXIST     1060L
#define ERROR_NOT_SUPPORTED              50L



CSysPwrStates* g_pCSysPwr = NULL;  //use the power management libraray API

//-------------------------------------------------------------------
// Purpose: Check whether the device supports power suspend & resume
//          if yes, proceeds to power suspend & resume
//          if no, the test will be skipped
// Parameter: DWORD in_dwSecsBeforeSuspend -- time before suspend
//--------------------------------------------------------------------

DWORD WINAPI
SuspendDeviceAndScheduleWakeupThread(DWORD userData)
{
    const DWORD TIME_BEFORE_RESUME = 15;

    DWORD l_dwRefMillis;
    DWORD l_dwRepeatSecs;
    DWORD l_dwRet;

    DWORD in_dwSecsBeforeSuspend = (DWORD) userData;

    WCHAR  state[1024] = {0};
    LPWSTR pState = &state[0];
    DWORD dwBufChars = (sizeof(state) / sizeof(state[0]));
	DWORD dwStateFlags = 0;

	//check whether power management service exists on the device
    if (GetSystemPowerState(pState, dwBufChars, &dwStateFlags) != ERROR_SUCCESS ||
        GetSystemPowerState(pState, dwBufChars, &dwStateFlags) == ERROR_SERVICE_DOES_NOT_EXIST){
			DETAIL(TEXT("ERROR: SKIPPING TEST: Power Management does not exist on this device.\n"));
			return ERROR_NOT_SUPPORTED;
	}

	//Initialize time before suspend to 1 if it's not specified
	if (0==in_dwSecsBeforeSuspend){
		in_dwSecsBeforeSuspend=1;
    }

    DETAIL(TEXT("\n\n"));
    DETAIL(TEXT(" Start counting down before going into power suspend ... \n\n\n"));


	// counting down before power suspend
    for (l_dwRepeatSecs = 0;
         l_dwRepeatSecs < (DWORD)in_dwSecsBeforeSuspend;
         l_dwRepeatSecs++)
    {
        l_dwRefMillis = GetTickCount();
        while (GetTickCount()-l_dwRefMillis < CLOCKS_PER_SEC)
        {
            ; // spin
        }
        Log(TEXT("%2ld "), in_dwSecsBeforeSuspend - l_dwRepeatSecs-1);
    }

    DETAIL(TEXT("System is going to suspend now.\n"));

	// power suspends if power management is suppored on this device
	if(g_pCSysPwr->SetupRTCWakeupTimer(TIME_BEFORE_RESUME) == FALSE ){
		DETAIL(TEXT("ERROR: SKIPPING TEST: Power Management does not exist on this device.\n"));
		g_pCSysPwr->CleanupRTCTimer();
		return ERROR_NOT_SUPPORTED;
	}
	else{
		DETAIL(TEXT("\n\n\n System power suspend is in progress, will resume in 5 secs ... \n"));
	}

    if((l_dwRet = SetSystemPowerState(_T("suspend"), NULL, POWER_FORCE)) != ERROR_SUCCESS){
		DETAIL(TEXT("ERROR: SetSystemPowerState failed.\n"));
		g_pCSysPwr->CleanupRTCTimer();
		return ERROR_GEN_FAILURE;
    }

	DETAIL(TEXT("\n\n System power has resumed.\n"));

	//Manually Force to On State
	if((l_dwRet = SetSystemPowerState(_T("on"), NULL, POWER_FORCE)) != ERROR_SUCCESS){
		DETAIL(TEXT("ERROR: SetSystemPowerState failed.\n"));
		g_pCSysPwr->CleanupRTCTimer();
		return ERROR_GEN_FAILURE;
    }
	DETAIL(TEXT("\n\n System power is now on.\n"));

	g_pCSysPwr->CleanupRTCTimer();

    return ERROR_SUCCESS;

}


/****** test utility procs ************************************************************/

DWORD Util_SuspendAndResume()
{
	g_pCSysPwr = new CSysPwrStates();

	DWORD dwStatus,dwRet = 0;
	dwStatus = SuspendDeviceAndScheduleWakeupThread(10);

	if(dwStatus == ERROR_NOT_SUPPORTED)
	{
		dwRet =  ERROR_NOT_SUPPORTED;
		SKIP(IDS_SUSPEND_RESUME_UNSUPPORTED);
	}

	if(dwStatus == ERROR_SUCCESS)
	{
		dwRet = ERROR_SUCCESS;
		Log(TEXT(IDS_SUSPEND_RESUME));
	}

	return (dwRet);

}

