{-# LANGUAGE AllowAmbiguousTypes #-}

module Mischief.Animation.Animator where

import Data.Data
import Data.Kind (Type)
import Data.Maybe
import GHC.Stack (HasCallStack)
import Mischief.Animation.Spritesheet
import Mischief.Assets
import Mischief.ECS

data AnimationStatus = Finished | Running

class (Typeable (Input a), Typeable a, Typeable (State a), Typeable (Shift a)) => AnimatorTag a where
  data State a :: Type
  data Input a :: Type
  data Shift a :: Type

  transition :: State a -> Input a -> Maybe (Shift a) -> AnimationStatus -> Maybe (State a)
  transition State a
_ Input a
_ Maybe (Shift a)
_ AnimationStatus
_ = Maybe (State a)
forall a. Maybe a
Nothing

  defInput :: Input a
  default defInput :: (Default (Input a)) => Input a
  defInput = Input a
forall a. Default a => a
def

  animation :: (HasCallStack) => State a -> AssetRef Animation

  start :: State a

data TransitionType = SoftTransition | HardTransition deriving (TransitionType -> TransitionType -> Bool
(TransitionType -> TransitionType -> Bool)
-> (TransitionType -> TransitionType -> Bool) -> Eq TransitionType
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: TransitionType -> TransitionType -> Bool
== :: TransitionType -> TransitionType -> Bool
$c/= :: TransitionType -> TransitionType -> Bool
/= :: TransitionType -> TransitionType -> Bool
Eq)

data Transition state input shift = Transition
  { forall state input shift.
Transition state input shift -> TransitionType
transType :: TransitionType,
    forall state input shift. Transition state input shift -> state
transTo :: state,
    forall state input shift.
Transition state input shift -> Condition input shift
transCond :: Condition input shift
  }

to :: state -> Condition input shift -> Transition state input shift
to :: forall state input shift.
state -> Condition input shift -> Transition state input shift
to state
b Condition input shift
c = Transition {transType :: TransitionType
transType = TransitionType
SoftTransition, transTo :: state
transTo = state
b, transCond :: Condition input shift
transCond = Condition input shift
c}

to' :: state -> Condition input shift -> Transition state input shift
to' :: forall state input shift.
state -> Condition input shift -> Transition state input shift
to' state
b Condition input shift
c = Transition {transType :: TransitionType
transType = TransitionType
HardTransition, transTo :: state
transTo = state
b, transCond :: Condition input shift
transCond = Condition input shift
c}

data Condition input shift = WhenCondition (input -> Bool) | ShiftCondition shift

when :: (input -> Bool) -> Condition input shift
when :: forall input shift. (input -> Bool) -> Condition input shift
when = (input -> Bool) -> Condition input shift
forall input shift. (input -> Bool) -> Condition input shift
WhenCondition

on :: shift -> Condition input shift
on :: forall shift input. shift -> Condition input shift
on = shift -> Condition input shift
forall input shift. shift -> Condition input shift
ShiftCondition

type IsFinished = Bool

checkTransitions :: forall a. (AnimatorTag a) => State a -> Input a -> Maybe (Shift a) -> AnimationStatus -> Maybe (State a)
checkTransitions :: forall {k} (a :: k).
AnimatorTag a =>
State a
-> Input a -> Maybe (Shift a) -> AnimationStatus -> Maybe (State a)
checkTransitions = State a
-> Input a -> Maybe (Shift a) -> AnimationStatus -> Maybe (State a)
forall {k} (a :: k).
AnimatorTag a =>
State a
-> Input a -> Maybe (Shift a) -> AnimationStatus -> Maybe (State a)
transition