module Mischief.ECS.Time where

import Control.Monad.IO.Class
import GHC.Records (HasField (getField))
import Mischief.ECS.App
import Mischief.ECS.App.Plugins
import Mischief.ECS.App.Schedules
import Mischief.ECS.Components
import Mischief.ECS.Resources
import Mischief.ECS.Systems qualified as Systems
import Mischief.ECS.Tables
import Mischief.ECS.Utils
import Mischief.ECS.World
import Mischief.ECS.World.Insert
import Mischief.ECS.World.Modify
import Mischief.ECS.World.Query
import Mischief.ECS.World.Query.Queryable
import System.Clock

data Time = Time
  { Time -> TimeSpec
delta :: TimeSpec,
    Time -> TimeSpec
elapsed :: TimeSpec
  }
  deriving (Int -> Time -> ShowS
[Time] -> ShowS
Time -> String
(Int -> Time -> ShowS)
-> (Time -> String) -> ([Time] -> ShowS) -> Show Time
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Time -> ShowS
showsPrec :: Int -> Time -> ShowS
$cshow :: Time -> String
show :: Time -> String
$cshowList :: [Time] -> ShowS
showList :: [Time] -> ShowS
Show, Typeable Time
Set DefaultComponentType
Hooks Time
IsExclusive (RelExclusivity Time)
(Typeable Time, IsExclusive (RelExclusivity Time)) =>
Set DefaultComponentType -> Hooks Time -> Component Time
forall c.
(Typeable c, IsExclusive (RelExclusivity c)) =>
Set DefaultComponentType -> Hooks c -> Component c
$crequired :: Set DefaultComponentType
required :: Set DefaultComponentType
$chooks :: Hooks Time
hooks :: Hooks Time
Component)

time :: System Time
time :: System Time
time = Maybe Time -> Time
forall a. HasCallStack => Maybe a -> a
unwrap (Maybe Time -> Time) -> System (Maybe Time) -> System Time
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall c. QueryType c => System (Maybe c)
res @Time

deltaTime :: System Float
deltaTime :: System Float
deltaTime = Time -> Float
deltaSecs (Time -> Float) -> System Time -> System Float
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> System Time
time

deltaSecs :: Time -> Float
deltaSecs :: Time -> Float
deltaSecs Time {TimeSpec
delta :: Time -> TimeSpec
delta :: TimeSpec
delta} = Int64 -> Float
forall a b. (Integral a, Num b) => a -> b
fromIntegral TimeSpec
delta.sec Float -> Float -> Float
forall a. Num a => a -> a -> a
+ Int64 -> Float
forall a b. (Integral a, Num b) => a -> b
fromIntegral TimeSpec
delta.nsec Float -> Float -> Float
forall a. Fractional a => a -> a -> a
/ Float
1000000000

data TimePlugin = TimePlugin deriving (TimePlugin -> TimePlugin -> Bool
(TimePlugin -> TimePlugin -> Bool)
-> (TimePlugin -> TimePlugin -> Bool) -> Eq TimePlugin
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: TimePlugin -> TimePlugin -> Bool
== :: TimePlugin -> TimePlugin -> Bool
$c/= :: TimePlugin -> TimePlugin -> Bool
/= :: TimePlugin -> TimePlugin -> Bool
Eq)

instance Plugin TimePlugin where
  init :: TimePlugin -> System ()
init TimePlugin
_ = do
    currentTime <- IO TimeSpec -> System TimeSpec
forall a. IO a -> System a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO TimeSpec -> System TimeSpec) -> IO TimeSpec -> System TimeSpec
forall a b. (a -> b) -> a -> b
$ Clock -> IO TimeSpec
getTime Clock
Monotonic
    insertRes $ Time {delta = TimeSpec {sec = 0, nsec = 0}, elapsed = currentTime}
    Systems.add First updateTime

updateTime :: System ()
updateTime :: System ()
updateTime = do
  Just time <- forall c. QueryType c => System (Maybe c)
res @Time
  currentTime <- liftIO $ getTime Monotonic
  insertRes Time {delta = currentTime - time.elapsed, elapsed = currentTime}