packages feed

typed-fsm-0.1.0.0: examples/ATM/Handler.hs

{-# LANGUAGE DataKinds #-}
{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE QualifiedDo #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UndecidableInstances #-}

module Handler where

import Control.Monad.State
import Data.IFunctor (At (..), IMonad (..), returnAt)
import qualified Data.IFunctor as I
import Data.Singletons (SingI (sing))
import Lens.Micro.Mtl (use, (-=), (.=))
import Type
import TypedFsm.Core
import TypedFsm.Driver

checkResult
  :: forall n
   . (SingI n, Less3 n)
  => Int
  -> Operate (StateT InternalState IO) CheckPINResult (CheckPin n)
checkResult i = I.do
  At userPin <- liftm $ use pin
  if i == userPin
    then LiftM $ pure (ireturn Correct)
    else LiftM $ pure (ireturn (Incorrect @n))

checkPinFun
  :: forall (n :: N)
   . (SingI n)
  => Int
  -> Operate (StateT InternalState IO) CheckPINResult (CheckPin (n :: N))
checkPinFun i = I.do
  case sing @n of
    SS SZ -> checkResult i
    SS (SS SZ) -> checkResult i
    sn@(SS (SS (SS SZ))) -> I.do
      At userPin <- liftm $ use pin
      if i == userPin
        then LiftM $ pure (ireturn Correct)
        else LiftM $ do
          liftIO $ putStrLn "-> test 3 times, eject card!"
          pure (ireturn (EjectCard sn))
    _ -> error "np"

readyHandler :: Op ATMSt InternalState IO () Exit Ready
readyHandler = I.do
  msg <- getInput
  case msg of
    InsertCard -> cardInsertedHandler
    ExitATM -> returnAt ()

cardInsertedHandler
  :: (SingI n)
  => Op ATMSt InternalState IO () Exit (CardInserted n)
cardInsertedHandler = I.do
  msg <- getInput
  case msg of
    CIEject -> I.do
      readyHandler
    CheckPIN i -> I.do
      res <- checkPinFun i
      case res of
        EjectCard _ -> readyHandler
        Incorrect -> cardInsertedHandler
        Correct -> I.do
          liftm $ amountLabel . label .= ("Amount: -- ")
          sessionHandler

sessionHandler :: Op ATMSt InternalState IO () Exit Session
sessionHandler = I.do
  msg <- getInput
  case msg of
    GetAmount -> I.do
      liftm $ do
        am <- use amount
        amountLabel . label .= ("Amount: " <> show am)
        liftIO $ putStrLn ("-> User Amount: " <> show am)
      sessionHandler
    Dispense i -> I.do
      liftm $ do
        amount -= i -- need to check amount is enough?
        liftIO $ putStrLn ("-> Use dispense " ++ show i)
        am <- use amount
        amountLabel . label .= ("Now Amount: " <> show am)
        liftIO $ putStrLn ("-> Now User Amount: " <> show am)
      sessionHandler
    SEject -> readyHandler