{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE PatternSynonyms #-}
module SDL.Power
  ( -- * Power Status
    getPowerInfo
  , PowerState(..)
  , BatteryState(..)
  , Charge(..)
  ) where

import Control.Applicative
import Control.Monad.IO.Class (MonadIO, liftIO)
import Data.Data (Data)
import Data.Typeable
import Foreign.C.Types
import Foreign.Marshal.Alloc
import Foreign.Marshal.Utils
import Foreign.Storable
import GHC.Generics (Generic)

import qualified SDL.Raw as Raw

-- | Current power supply details.
--
-- Throws 'SDLException' if the current power state can not be determined.
--
-- See @<https://wiki.libsdl.org/SDL_GetPowerInfo SDL_GetPowerInfo>@ for C documentation.
getPowerInfo :: (Functor m, MonadIO m) => m PowerState
getPowerInfo =
  liftIO $
  alloca $ \secsPtr ->
  alloca $ \pctPtr -> do
    state <- Raw.getPowerInfo secsPtr pctPtr
    let peekCharge = liftA2 Charge (maybePeek peek secsPtr) (maybePeek peek pctPtr)
    case state of
     Raw.SDL_POWERSTATE_ON_BATTERY -> fmap (Battery Draining) peekCharge
     Raw.SDL_POWERSTATE_CHARGING -> fmap (Battery Charging) peekCharge
     Raw.SDL_POWERSTATE_CHARGED -> fmap (Battery Charged) peekCharge
     Raw.SDL_POWERSTATE_NO_BATTERY -> pure Mains
     _ -> pure UnknownPowerState

-- | Information about the power supply for the user's environment
data PowerState
  = Battery BatteryState Charge
    -- ^ The user is on a battery powered device. See 'BatteryState' for charge information, and 'Charge' for charge information
  | Mains
    -- ^ The user is on a device connected to the mains.
  | UnknownPowerState
    -- ^ SDL could not determine the power for the device.
  deriving (Eq, Generic, Ord, Read, Show, Typeable)

-- | Information on battery consumption for battery powered devices
data BatteryState
  = Draining
    -- ^ The battery is currently being drained.
  | Charged
    -- ^ The battery is fully charged.
  | Charging
    -- ^ The device is plugged in and the battery is charging.
  deriving (Bounded, Data, Enum, Eq, Generic, Ord, Read, Show, Typeable)

-- | Information about how much charge a battery has.
data Charge =
  Charge {chargeSecondsLeft :: Maybe CInt -- ^ How many seconds of battery life is left
         ,chargePercent :: Maybe CInt -- ^ The percentage of battery charged
         }
  deriving (Eq, Generic, Ord, Read, Show, Typeable)