//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this sample source code is subject to the terms of the Microsoft
// license agreement under which you licensed this sample source code. If
// you did not accept the terms of the license agreement, you are not
// authorized to use this sample source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the LICENSE.RTF on your install media or the root of your tools installation.
// THE SAMPLE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES.
//

//
// This module implements a set of states defined by the MS Mobile Devices
// Division as a baseline for Pocket PC devices.  OEMs may choose to customize
// this file to support the hardware specific to their platform.
//

#include <pmimpl.h>
#include <nkintr.h>
#include <extfile.h>
#include <pmpolicy.h>
#include <Csync.h>
#include <cRegEdit.h>
#include <pwsdef.h>

typedef enum {
    NoTimeoutItem,
    SuspendTimeout,
    SystemActivityTimeout,
    UserActivityTimeout,
} TIMEOUT_ITEM, *PTIMEOUT_ITEM;

typedef enum { 
    On,                     // system is running normally with UI enabled
    UserIdle,               // User Idle state.
    SystemIdle,
    Resuming,               // system is determining what to do after a resume
    Suspend,                 // system suspended, all devices off (or wake-enabled)
    ColdReboot,
    Reboot,
    Shutdown,
    UnknownState = PM_UNKNOWN_POWER_STATE,       // Unknown
} PLATFORM_ACTIVITY_STATE, *PPLATFORM_ACTIVITY_STATE;
    
#define STRING_ON _T("on")
#define STRING_USERIDLE _T("useridle")
#define STRING_SYSTEMIDLE _T("systemidle")
#define STRING_RESUMING _T("resuming")
#define STRING_SUSPEND _T("suspend")
#define STRING_ColdReboot _T("coldreboot")
#define STRING_Reboot _T("reboot")
#define STRING_SHUTDOWN _T("shutdown")

// platform-specific default values
#define DEF_TIMEOUTTOUSERIDLE           60          // in seconds, 0 to disable
#define DEF_TIMEOUTTOSYSTEMIDLE         300         // in seconds, 0 to disable
#define DEF_TIMEOUTTOSUSPEND            600         // in seconds, 0 to disable

extern DWORD RegReadStateTimeout(HKEY hk, LPCTSTR pszName, DWORD dwDefault);
// need "C" linkage for compatibility with C language PDD implementations
extern "C" extern POWER_BROADCAST_POWER_INFO gSystemPowerStatus;

class PowerStateManager: public DefaultPowerStateManager {
public:
    PowerStateManager(PVOID pParam) 
        : DefaultPowerStateManager (pParam)
    {
        m_fActiveManagement = TRUE;
    }
    ~PowerStateManager() {
        while (m_pPowerStateList!=NULL) {
            PowerState * pNextState = m_pPowerStateList->GetNextPowerState();
            delete m_pPowerStateList;
            m_pPowerStateList = pNextState;
        }
    }
    BOOL Init() {
        if (DefaultPowerStateManager::Init() && m_pSystemActivity && m_pUserActivity) { // This is required by Default PM.
            PlatformLoadTimeouts();
            ReInitTimeOuts();
            return CreatePowerStateList();
        }
        return FALSE;
    }

    virtual void ResetUserIdleTimeout(BOOL fIdle) {
        m_dwCurUserIdleTimeout = (fIdle? GetUserIdleTimeOut():INFINITE);
        if (m_dwCurUserIdleTimeout == 0 )
            m_dwCurUserIdleTimeout = INFINITE ;
        m_dwCurTimeoutToSystemIdle = (fIdle? GetSystemIdleTimeOut(): INFINITE);
        if (m_dwCurTimeoutToSystemIdle == 0)
            m_dwCurTimeoutToSystemIdle = INFINITE ;
    }
    virtual void ResetSystemIdleTimeTimeout(BOOL fIdle) {
        m_dwCurSuspendTimeout = (fIdle? GetSuspendTimeOut(): INFINITE);
        if (m_dwCurSuspendTimeout == 0)
            m_dwCurSuspendTimeout = INFINITE ;
    }
    virtual void SubtractTimeout(DWORD dwTicks) {
        if (m_dwCurSuspendTimeout != INFINITE )
            m_dwCurSuspendTimeout = (m_dwCurSuspendTimeout>dwTicks? m_dwCurSuspendTimeout- dwTicks: 0 );
        if (m_dwCurTimeoutToSystemIdle != INFINITE)
            m_dwCurTimeoutToSystemIdle = (m_dwCurTimeoutToSystemIdle>dwTicks? m_dwCurTimeoutToSystemIdle- dwTicks: 0 );
        if (m_dwCurUserIdleTimeout!= INFINITE)
            m_dwCurUserIdleTimeout =  (m_dwCurUserIdleTimeout> dwTicks? m_dwCurUserIdleTimeout - dwTicks: 0 );
    }
    virtual DWORD   ThreadRun() {
        SETFNAME(_T("PowerStateManager::ThreadRun"));
        // Assume First state is PowerStateOn. So please put POwerStateOn on the header.
        if (m_pPowerStateList) {
            // We need get first SetSystemPower from device to make initial power state correct.
            PowerState * pCurPowerState = GetFirstPowerState();
            if (pCurPowerState != NULL) {
                Lock();
                m_pCurPowerState =  pCurPowerState;
                pCurPowerState->EnterState();
                BOOL fDone = FALSE;
                // Create Legacy Registry modify notification event array.
                while (!fDone && pCurPowerState) {
                    PLATFORM_ACTIVITY_STATE curState = (PLATFORM_ACTIVITY_STATE) pCurPowerState->GetState();
                    PLATFORM_ACTIVITY_STATE newState = curState;
                    Unlock();
                    PLATFORM_ACTIVITY_EVENT activityEvent = pCurPowerState->WaitForEvent(INFINITE,0 ,NULL);
                    PMLOGMSG(ZONE_PLATFORM, (_T("%s: activityEvent = %d  \r\n"  ), pszFname,activityEvent)) ;
                    Lock();
                    if (pCurPowerState != m_pCurPowerState) {
                        if (activityEvent!= SystemPowerStateAPI) { 
                            PMLOGMSG(ZONE_ERROR|| ZONE_PLATFORM,(_T("Multiple Event happens during SentSystemPowerState %d, Event will evaluated in new state \r\n"),newState));
                        }
                        pCurPowerState = m_pCurPowerState;
                        newState = curState = (PLATFORM_ACTIVITY_STATE) pCurPowerState->GetState();
                        if ((PLATFORM_ACTIVITY_STATE) pCurPowerState->GetState() == Resuming 
                                || (PLATFORM_ACTIVITY_STATE)pCurPowerState->GetState() == Suspend) {
                            // Application call SetSystemPowerState set to Resuming or Suspend in other thread.
                            // This thread come back, calculate time elapsed and update it. So timeout is wrong 
                            // we need re-intialize timeout paramenter
                            ReInitTimeOuts( ) ;
                        }
                    }
                    switch (activityEvent) {
                    case PmShutDown :
                        fDone = TRUE;
                        break;
                    case PmReloadActivityTimeouts:
                        PlatformLoadTimeouts(); // No break we need run ReInitTimeouts.
                    case RestartTimeouts:
                    case PowerSourceChange: 
                    case SystemPowerStateChange:
                    case PowerButtonPressed: 
                    case AppButtonPressed:
                        ReInitTimeOuts();
                        pCurPowerState->DefaultEventHandle( activityEvent ) ;
                        break;
                    case SystemPowerStateAPI:
                        break;
                    default:
                        pCurPowerState->DefaultEventHandle( activityEvent ) ;
                        break;
                    }
                    pCurPowerState = SetSystemState(pCurPowerState ) ;
                    ASSERT(pCurPowerState!=NULL);
                    m_pCurPowerState =  pCurPowerState; // Update current state.
                }
                Unlock();
            }
            else
                ASSERT(FALSE);
        }
        return 0;
    }
    virtual void ReAdjustTimeOuts( )  {
        if (m_dwCurSuspendTimeout > GetSuspendTimeOut() ) {
            if ((m_dwCurSuspendTimeout=GetSuspendTimeOut()) == 0 )
                m_dwCurSuspendTimeout = INFINITE ;
        }
        if (m_dwCurTimeoutToSystemIdle > GetSystemIdleTimeOut() ) {
            if ((m_dwCurTimeoutToSystemIdle=GetSystemIdleTimeOut()) == 0 )
                m_dwCurTimeoutToSystemIdle = INFINITE ;
        }
        if (m_dwCurUserIdleTimeout > GetUserIdleTimeOut() ) {
            if ((m_dwCurUserIdleTimeout=GetUserIdleTimeOut()) == 0)
                m_dwCurUserIdleTimeout = INFINITE ;
        }
    }
    
    virtual DWORD GetSmallestTimeout(PTIMEOUT_ITEM pTimeoutItem) {
        DWORD dwReturn = INFINITE;
        TIMEOUT_ITEM activeEvent = NoTimeoutItem;
        if (dwReturn > m_dwCurSuspendTimeout) {
            dwReturn = m_dwCurSuspendTimeout;
            activeEvent = SuspendTimeout ;
        }
        if (dwReturn > m_dwCurTimeoutToSystemIdle) {
            dwReturn = m_dwCurTimeoutToSystemIdle;
            activeEvent = SystemActivityTimeout ;
        }
        if (dwReturn > m_dwCurUserIdleTimeout ) {
            dwReturn = m_dwCurUserIdleTimeout;
            activeEvent = UserActivityTimeout;
        }
        if (pTimeoutItem) {
            *pTimeoutItem = activeEvent;
        }
        return dwReturn;
    }
    void DisableUserIdleTimeout() { m_dwCurUserIdleTimeout = INFINITE; };
    void DisableSuspendTimeout() { m_dwCurSuspendTimeout = INFINITE; };
    void DisableSystemIdleTimeout() { m_dwCurTimeoutToSystemIdle = INFINITE; };
    // Timer Function.
    virtual void ReInitTimeOuts() {
        m_dwCurSuspendTimeout = GetSuspendTimeOut();
        m_dwCurTimeoutToSystemIdle = GetSystemIdleTimeOut();
        m_dwCurUserIdleTimeout = GetUserIdleTimeOut() ;
        // If timer is not set. It is not supported.
        if (m_dwCurUserIdleTimeout == 0 )
            m_dwCurUserIdleTimeout = INFINITE ;
        if (m_dwCurTimeoutToSystemIdle == 0)
            m_dwCurTimeoutToSystemIdle = INFINITE ;
        if (m_dwCurSuspendTimeout == 0)
            m_dwCurSuspendTimeout = INFINITE ;
    }
    virtual void   PlatformResumeSystem(BOOL fSuspened) {
        SETFNAME(_T("PowerStateManager::PlatformResumeSystem"));
        TCHAR szResumeState[MAX_PATH];
        DWORD dwStatus;
        HANDLE hevActivityReset = NULL;
        
        PMLOGMSG(ZONE_RESUME, (_T("+%s: suspend flag is %d\r\n"), pszFname, fSuspened));
        
        // Was this an unexpected resume event?  If so, there may be a thread priority problem
        // or some piece of software suspended the system without calling SetSystemPowerState().
        DEBUGCHK(fSuspened);
        if(!fSuspened) {
            // Unexpected resume -- turn everything back on.  OEMs may choose to customize this
            // routine to dynamically determine which system power state is most appropriate rather
            // than using PlatformMapPowerStateHint().
            PMLOGMSG(ZONE_WARN || ZONE_RESUME, (_T("%s: WARNING: unexpected resume!\r\n"), pszFname));
            dwStatus = PlatformMapPowerStateHint(POWER_STATE_ON, szResumeState, dim(szResumeState));
            DEBUGCHK(dwStatus == ERROR_SUCCESS);
            
            // Go into the new state.  OEMs that choose to support unexpected resumes may want to
            // lock PM variables with PMLOCK(), then set the curDx and actualDx values for all
            // devices to PwrDeviceUnspecified before calling PmSetSystemPowerState_I().  This will
            // force an update IOCTL to all devices.
            dwStatus = PmSetSystemPowerState_I(szResumeState, 0, POWER_FORCE, TRUE);
            DEBUGCHK(dwStatus == ERROR_SUCCESS);
        } else if(m_fActiveManagement) {
            DWORD dwWakeSource, dwBytesReturned;
            BOOL fOk;
            
            // get the system wake source to help determine which power state we resume into
            fOk = KernelIoControl(IOCTL_HAL_GET_WAKE_SOURCE, NULL, 0, &dwWakeSource, 
                sizeof(dwWakeSource), &dwBytesReturned);
            if(fOk) {
                // ioctl succeeded (not all platforms necessarily support it), but sanity check
                // the return value, just in case.
                if(dwBytesReturned != sizeof(dwWakeSource)) {
                    PMLOGMSG(ZONE_WARN, (_T("%s: KernelIoControl() returned an invalid size %d\r\n"),
                        pszFname, dwBytesReturned));
                } else {
                    // look for an activity timer corresponding to this wake source
                    PACTIVITY_TIMER pat = ActivityTimerFindByWakeSource(dwWakeSource);
                    if(pat != NULL) {
                        PMLOGMSG(ZONE_RESUME || ZONE_TIMERS, (_T("%s: signaling '%s' activity at resume\r\n"),
                            pszFname, pat->pszName));
                        hevActivityReset = pat->hevReset;
                    }
                }
            }
            
            // did we find an activity timer?
            if(hevActivityReset == NULL) {
                PMLOGMSG(ZONE_RESUME, (_T("%s: assuming user activity\r\n"), pszFname));
                hevActivityReset = (m_pUserActivity!=NULL ?m_pUserActivity->hevReset: NULL);
            }
        }
        
        // is there an activity timer we need to reset?
        if(hevActivityReset != NULL) {
            // found a timer, elevate the timer management priority thread so that it 
            // executes before the suspending thread
            DWORD dwOldPriority = CeGetThreadPriority(ghtActivityTimers);
            DWORD dwNewPriority = (CeGetThreadPriority(GetCurrentThread()) - 1);
            DEBUGCHK(dwNewPriority >= 0);
            SetEvent(hevActivityReset);
            CeSetThreadPriority(ghtActivityTimers, dwNewPriority);
            CeSetThreadPriority(ghtActivityTimers, dwOldPriority);
        }
        
        PMLOGMSG(ZONE_RESUME, (_T("-%s\r\n"), pszFname));
    }

protected:        
    virtual void    PlatformLoadTimeouts() {
        DWORD dwStatus;
        TCHAR szPath[MAX_PATH];
        HKEY hk;
        SETFNAME(_T("PowerStateManager::PlatformLoadTimeouts"));

        // assume default values
        m_dwACSuspendTimeout = DEF_TIMEOUTTOSUSPEND * 1000;
        m_dwACTimeoutToSystemIdle = DEF_TIMEOUTTOSYSTEMIDLE * 1000 ;
        m_dwACUserIdleTimeout = DEF_TIMEOUTTOUSERIDLE * 1000;
        
        m_dwBattSuspendTimeout = DEF_TIMEOUTTOSUSPEND * 1000;
        m_dwBattTimeoutToSystemIdle = DEF_TIMEOUTTOSYSTEMIDLE * 1000 ;
        m_dwBattUserIdleTimeout = DEF_TIMEOUTTOUSERIDLE * 1000;
        // get timeout thresholds for transitions between states
        StringCchPrintf(szPath, MAX_PATH, _T("%s\\%s"), PWRMGR_REG_KEY, _T("Timeouts"));
        dwStatus = RegOpenKeyEx(HKEY_LOCAL_MACHINE, szPath, 0, 0, &hk);
        if(dwStatus == ERROR_SUCCESS) {
            // read system power state timeouts
            m_dwACSuspendTimeout = RegReadStateTimeout(hk, _T("ACSuspend"), DEF_TIMEOUTTOSUSPEND);
            m_dwACTimeoutToSystemIdle = RegReadStateTimeout(hk, _T("ACSystemIdle"), DEF_TIMEOUTTOSYSTEMIDLE);
            m_dwACUserIdleTimeout = RegReadStateTimeout(hk, _T("ACUserIdle"), DEF_TIMEOUTTOUSERIDLE);
             
            m_dwBattSuspendTimeout = RegReadStateTimeout(hk, _T("BattSuspend"), DEF_TIMEOUTTOUSERIDLE);
            m_dwBattTimeoutToSystemIdle = RegReadStateTimeout(hk, _T("BattSystemIdle"), DEF_TIMEOUTTOSYSTEMIDLE);
            m_dwBattUserIdleTimeout = RegReadStateTimeout(hk, _T("BattUserIdle"), DEF_TIMEOUTTOSUSPEND);
             
            // release resources
            RegCloseKey(hk);
        }
        // Update Legacy if we find them.
        PMLOGMSG(ZONE_INIT || ZONE_PLATFORM, 
            (_T("%s: ACSuspendTimeout %d, ACTimeoutToSystemIdle %d, ACUserIdleTimeout %d \r\n"), pszFname, m_dwACSuspendTimeout, m_dwACTimeoutToSystemIdle, m_dwACUserIdleTimeout));
        PMLOGMSG(ZONE_INIT || ZONE_PLATFORM, 
            (_T("%s: BattSuspendTimeout %d,BattTimeoutToSystemIdle %d, BattUserIdleTimeout%d \r\n"  ),pszFname, m_dwBattSuspendTimeout,m_dwBattTimeoutToSystemIdle, m_dwBattUserIdleTimeout));
    }
    
    virtual BOOL    CreatePowerStateList(); // Implement this at last.
    // Timeout Function.
    DWORD GetSuspendTimeOut () {
        return (gSystemPowerStatus.bACLineStatus == AC_LINE_OFFLINE? m_dwBattSuspendTimeout: m_dwACSuspendTimeout);
    }
    DWORD GetSystemIdleTimeOut() {
        return (gSystemPowerStatus.bACLineStatus == AC_LINE_OFFLINE? m_dwBattTimeoutToSystemIdle: m_dwACTimeoutToSystemIdle);
    }
    DWORD GetUserIdleTimeOut() {
        return (gSystemPowerStatus.bACLineStatus == AC_LINE_OFFLINE? m_dwBattUserIdleTimeout: m_dwACUserIdleTimeout);
    }
protected:
    
    // TimeOut Parameter.
    DWORD m_dwACSuspendTimeout;
    DWORD m_dwACTimeoutToSystemIdle ;
    DWORD m_dwACUserIdleTimeout;
    
    DWORD m_dwBattSuspendTimeout ;
    DWORD m_dwBattTimeoutToSystemIdle ;
    DWORD m_dwBattUserIdleTimeout;
        
    DWORD m_dwCurSuspendTimeout;
    DWORD m_dwCurTimeoutToSystemIdle ;
    DWORD m_dwCurUserIdleTimeout;

    BOOL  m_fActiveManagement;

};


class PowerStateOn : public PowerState {
public:
    PowerStateOn(PowerStateManager *pPwrStateMgr, PowerState * pNextPowerState = NULL )      
    :   PowerState(pPwrStateMgr,pNextPowerState)
    {;  };
    virtual void EnterState() {
        PowerState::EnterState();
        ((PowerStateManager *)m_pPwrStateMgr)->ReInitTimeOuts( );
    }

    // This state does not need Resume Time out.
    virtual PLATFORM_ACTIVITY_EVENT  WaitForEvent(DWORD dwTimeouts = INFINITE , DWORD dwNumOfExternEvent = 0, HANDLE * pExternEventArray = NULL) {
        TIMEOUT_ITEM TimeoutItem;
        ((PowerStateManager *) m_pPwrStateMgr)->DisableSuspendTimeout();
        ((PowerStateManager *) m_pPwrStateMgr)->DisableSystemIdleTimeout();
        DWORD dwTimeout =((PowerStateManager *) m_pPwrStateMgr)->GetSmallestTimeout(&TimeoutItem);
        PLATFORM_ACTIVITY_EVENT activeEvent = PowerState::WaitForEvent(dwTimeout ,dwNumOfExternEvent, pExternEventArray) ;
        switch (activeEvent) {
            case Timeout: {
                switch (TimeoutItem) {
                    case UserActivityTimeout:
                        m_LastNewState = UserIdle;
                        break;
                    default:
                        ASSERT(FALSE);
                        break;
                }
                break;
            }
        }
        return activeEvent;
    }
    virtual DWORD  GetState() { return (DWORD)On; };
    virtual LPCTSTR GetStateString() { return STRING_ON ; };
    virtual DWORD StateValidateRegistry(DWORD  , DWORD  ) {
        return PowerState::StateValidateRegistry(0, POWER_STATE_ON|POWER_STATE_PASSWORD);
    }
    virtual BOOL AppsCanRequestState() { return TRUE; }
    
};

class PowerStateUserIdle : public PowerState {
public:
    PowerStateUserIdle(PowerStateManager *pPwrStateMgr, PowerState * pNextPowerState = NULL )     
    :   PowerState(pPwrStateMgr,pNextPowerState)
    {;  };
    virtual void EnterState() {
        PowerState::EnterState();
        ((PowerStateManager *)m_pPwrStateMgr)->ReInitTimeOuts( );
    }
    // This state does not need Resume Time out.
    virtual PLATFORM_ACTIVITY_EVENT  WaitForEvent(DWORD dwTimeouts = INFINITE , DWORD dwNumOfExternEvent = 0, HANDLE * pExternEventArray = NULL) {
        TIMEOUT_ITEM TimeoutItem;
        ((PowerStateManager *)m_pPwrStateMgr)->DisableUserIdleTimeout();
        ((PowerStateManager *) m_pPwrStateMgr)->DisableSuspendTimeout();
        DWORD dwTimeout = ((PowerStateManager *)m_pPwrStateMgr)->GetSmallestTimeout(&TimeoutItem);
        PLATFORM_ACTIVITY_EVENT activeEvent = PowerState::WaitForEvent(dwTimeout ,dwNumOfExternEvent, pExternEventArray) ;
        switch (activeEvent) {
            case UserActivity: 
                m_LastNewState = On;
                break;
            case Timeout: {
                switch (TimeoutItem) {
                    case SystemActivityTimeout:
                        m_LastNewState = SystemIdle;
                        break;
                    default:
                        ASSERT(FALSE);
                        break;
                }
                break;
            }
        }
        return activeEvent;
    }
    virtual DWORD  GetState() { return (DWORD)UserIdle; };
    virtual LPCTSTR GetStateString() { return STRING_USERIDLE; };
    virtual DWORD StateValidateRegistry(DWORD dwDState , DWORD dwFlag ) {
        return PowerState::StateValidateRegistry(1, POWER_STATE_PASSWORD|POWER_STATE_USERIDLE );
    }
    virtual BOOL AppsCanRequestState() { return TRUE; }
    
};

class PowerStateSystemIdle : public PowerState {
public:
    PowerStateSystemIdle(PowerStateManager *pPwrStateMgr, PowerState * pNextPowerState = NULL )     
    :   PowerState(pPwrStateMgr,pNextPowerState)
    {;  };
    virtual void EnterState() {
        PowerState::EnterState();
        ((PowerStateManager *)m_pPwrStateMgr)->ReInitTimeOuts( );
    }
    // This state does not need Resume Time out.
    virtual PLATFORM_ACTIVITY_EVENT  WaitForEvent(DWORD dwTimeouts = INFINITE , DWORD dwNumOfExternEvent = 0, HANDLE * pExternEventArray = NULL) {
        TIMEOUT_ITEM TimeoutItem;
        ((PowerStateManager *)m_pPwrStateMgr)->DisableUserIdleTimeout();
        ((PowerStateManager *)m_pPwrStateMgr)->DisableSystemIdleTimeout();
        DWORD dwTimeout = ((PowerStateManager *)m_pPwrStateMgr)->GetSmallestTimeout(&TimeoutItem);
        PLATFORM_ACTIVITY_EVENT activeEvent = PowerState::WaitForEvent(dwTimeout ,dwNumOfExternEvent, pExternEventArray) ;
        switch (activeEvent) {
            case UserActivity: 
                m_LastNewState = On;
                break;
            case Timeout: {
                switch (TimeoutItem) {
                    case SuspendTimeout:
                        m_LastNewState = Suspend;
                        break;
                    default:
                        ASSERT(FALSE);
                }
                break;
            }
        }
        return activeEvent;
    }
    virtual DWORD  GetState() { return (DWORD)SystemIdle; };
    virtual LPCTSTR GetStateString() { return STRING_SYSTEMIDLE; };
    virtual DWORD StateValidateRegistry(DWORD dwDState , DWORD dwFlag ) {
        return PowerState::StateValidateRegistry(2, 0 );
    }
    
};

class PowerStateSuspended : public PowerState {
public:
    PowerStateSuspended (PowerStateManager *pPwrStateMgr, PowerState * pNextPowerState = NULL )
    :   PowerState(pPwrStateMgr,pNextPowerState)
    {; };
    virtual void EnterState() {
        PmSetSystemPowerState_I ( GetStateString() , 0 , 0, TRUE);
        // Because it wakeup by wakeup source So it automatic enter Resuming State.
        m_LastNewState = Resuming; // Point to Resuming.
        
    }
    virtual PLATFORM_ACTIVITY_EVENT  WaitForEvent(DWORD dwTimeouts = INFINITE , DWORD dwNumOfExternEvent = 0, HANDLE * pExternEventArray = NULL) {
        // Suspend is no wait
        return NoActivity;
    }
    virtual DWORD  GetState() { return (DWORD)Suspend; };
    virtual LPCTSTR GetStateString()  { return STRING_SUSPEND; };
    virtual DWORD StateValidateRegistry(DWORD  , DWORD  ) {
        return PowerState::StateValidateRegistry(3, POWER_STATE_SUSPEND );
    }
    virtual BOOL AppsCanRequestState() { return TRUE; }
};

class PowerStateShutdown : public PowerState {
public:
    PowerStateShutdown (PowerStateManager *pPwrStateMgr, PowerState * pNextPowerState = NULL )
    :   PowerState(pPwrStateMgr,pNextPowerState)
    {; };
    virtual void EnterState() {
        PmSetSystemPowerState_I ( GetStateString() , 0 , 0, TRUE);
        // Because it wakeup by wakeup source So it automatic enter Resuming State.
        m_LastNewState = Resuming; // Point to Resuming.
        
    }
    virtual PLATFORM_ACTIVITY_EVENT  WaitForEvent(DWORD dwTimeouts = INFINITE , DWORD dwNumOfExternEvent = 0, HANDLE * pExternEventArray = NULL) {
        // Suspend is no wait
        return NoActivity;
    }
    virtual DWORD  GetState() { return (DWORD)Shutdown; };
    virtual LPCTSTR GetStateString()  { return STRING_SHUTDOWN; };
    virtual DWORD StateValidateRegistry(DWORD  , DWORD  ) {
        return PowerState::StateValidateRegistry(3, POWER_STATE_OFF );
    }
    virtual BOOL AppsCanRequestState() { return TRUE; }
};

class PowerStateResuming : public PowerState {
public:
    PowerStateResuming  (PowerStateManager *pPwrStateMgr, PowerState * pNextPowerState = NULL )
    :   PowerState(pPwrStateMgr,pNextPowerState)
    {; };
    virtual void EnterState() {
        PowerState::EnterState();
        ((PowerStateManager *)m_pPwrStateMgr)->ReInitTimeOuts();
        // Initial Timeout to Active First.
        if (m_pPwrStateMgr->GetUserActivityTimer()!=NULL)
            m_dwEventArray [ PM_USER_ACTIVITY_EVENT ] = m_pPwrStateMgr->GetUserActivityTimer()->hevActive;
        if (m_pPwrStateMgr->GetSystemActivityTimer()!=NULL)
            m_dwEventArray [ PM_SYSTEM_ACTIVITY_EVENT ] = m_pPwrStateMgr->GetSystemActivityTimer()->hevActive;
        m_pPwrStateMgr->ResetSystemIdleTimeTimeout(TRUE); // This will at least do not folling into suspend directly.
    }
    virtual PLATFORM_ACTIVITY_EVENT  WaitForEvent(DWORD dwTimeouts = INFINITE , DWORD dwNumOfExternEvent = 0, HANDLE * pExternEventArray = NULL)  {
        PLATFORM_ACTIVITY_EVENT activeEvent = PowerState::WaitForEvent(0 ,dwNumOfExternEvent, pExternEventArray) ;
        switch (activeEvent) {
            case  UserActivity:
                m_LastNewState = On;
                break;
            case  SystemActivity:
                m_LastNewState = SystemIdle;
                break;
            case Timeout: {
                m_LastNewState = On;                
                break;
            }
        }
        return activeEvent;
    }
    virtual DWORD  GetState() { return (DWORD)Resuming; };
    virtual LPCTSTR GetStateString() { return STRING_RESUMING; };
    virtual DWORD StateValidateRegistry(DWORD , DWORD  ) {
        return PowerState::StateValidateRegistry(2, 0 );
    }
};

class PowerStateColdReboot : public PowerState {
public:
    PowerStateColdReboot (PowerStateManager *pPwrStateMgr, PowerState * pNextPowerState = NULL )
    :   PowerState(pPwrStateMgr,pNextPowerState)
    {; };
    virtual void EnterState() {
        PmSetSystemPowerState_I ( GetStateString() , 0 , 0, TRUE);
        // Because it wakeup by wakeup source So it automatic enter Resuming State.
    }
    virtual PLATFORM_ACTIVITY_EVENT  WaitForEvent(DWORD dwTimeouts = INFINITE , DWORD dwNumOfExternEvent = 0, HANDLE * pExternEventArray = NULL) {
        // Suspend is no wait
        return NoActivity;
    }
    virtual DWORD  GetState() { return (DWORD)ColdReboot; };
    virtual DWORD  GetLastNewState() {  return (DWORD)ColdReboot;; };
    virtual LPCTSTR GetStateString()  { return STRING_ColdReboot; };
    virtual DWORD StateValidateRegistry(DWORD  , DWORD  ) {
        return PowerState::StateValidateRegistry(4, POWER_STATE_RESET );
    }
    virtual BOOL AppsCanRequestState() { return TRUE; }
};

class PowerStateReboot : public PowerState {
public:
    PowerStateReboot (PowerStateManager *pPwrStateMgr, PowerState * pNextPowerState = NULL )
    :   PowerState(pPwrStateMgr,pNextPowerState)
    {; };
    virtual void EnterState() {
        PmSetSystemPowerState_I ( GetStateString() , 0 , 0, TRUE);
        // Because it wakeup by wakeup source So it automatic enter Resuming State.
    }
    virtual PLATFORM_ACTIVITY_EVENT  WaitForEvent(DWORD dwTimeouts = INFINITE , DWORD dwNumOfExternEvent = 0, HANDLE * pExternEventArray = NULL) {
        // Suspend is no wait
        return NoActivity;
    }
    virtual DWORD  GetState() { return (DWORD)Reboot; };
    virtual DWORD  GetLastNewState() {  return (DWORD)Reboot;; };
    virtual LPCTSTR GetStateString()  { return STRING_Reboot; };
    virtual DWORD StateValidateRegistry(DWORD  , DWORD  ) {
        return PowerState::StateValidateRegistry(4, POWER_STATE_RESET );
    }
    virtual BOOL AppsCanRequestState() { return TRUE; }
};



BOOL PowerStateManager::CreatePowerStateList()
{
    if (m_pPowerStateList == NULL ) {
        m_pPowerStateList = new PowerStateOn( this, new PowerStateUserIdle( this, new PowerStateSystemIdle(this,  
            new PowerStateResuming(this, new PowerStateSuspended(this, new PowerStateReboot(this, new PowerStateColdReboot(this, new PowerStateShutdown(this))))))));
    }
    if (m_pPowerStateList != NULL) {
        PowerState * pCurState = m_pPowerStateList;
        while (pCurState) {
            if (!pCurState->Init()) {
                ASSERT(FALSE);
                return FALSE;
            }
            pCurState = pCurState->GetNextPowerState();
        }
        return TRUE;
    }
    else
        return FALSE;
}

DefaultPowerStateManager * CreateDefaultPowerManager(PVOID pParm)
{
    return (new PowerStateManager(pParm));
}

