module Termbox.Internal.Event
  ( Event (..),
    poll,
  )
where

import Data.Int (Int32)
import GHC.Generics (Generic)
import qualified Termbox.Bindings.Hs
import Termbox.Internal.Key (Key (KeyChar), parseKey)
import Termbox.Internal.Mouse (Mouse (..), MouseButton (..))
import Termbox.Internal.Pos (Pos (..))
import Termbox.Internal.Size (Size (..))
import Prelude hiding (mod)

-- | An input event.
data Event e
  = -- | Key event
    EventKey !Key
  | -- | Resize event
    EventResize !Size
  | -- | Mouse event
    EventMouse !Mouse
  | -- | User event
    EventUser !e
  deriving stock (Event e -> Event e -> Bool
forall e. Eq e => Event e -> Event e -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Event e -> Event e -> Bool
$c/= :: forall e. Eq e => Event e -> Event e -> Bool
== :: Event e -> Event e -> Bool
$c== :: forall e. Eq e => Event e -> Event e -> Bool
Eq, forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
forall e x. Rep (Event e) x -> Event e
forall e x. Event e -> Rep (Event e) x
$cto :: forall e x. Rep (Event e) x -> Event e
$cfrom :: forall e x. Event e -> Rep (Event e) x
Generic, Int -> Event e -> ShowS
forall e. Show e => Int -> Event e -> ShowS
forall e. Show e => [Event e] -> ShowS
forall e. Show e => Event e -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Event e] -> ShowS
$cshowList :: forall e. Show e => [Event e] -> ShowS
show :: Event e -> String
$cshow :: forall e. Show e => Event e -> String
showsPrec :: Int -> Event e -> ShowS
$cshowsPrec :: forall e. Show e => Int -> Event e -> ShowS
Show)

-- | Poll for an event.
poll :: IO (Event e)
poll :: forall e. IO (Event e)
poll =
  forall e. IO (Either () (Event e))
poll_ forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
    Left () -> forall e. IO (Event e)
poll
    Right Event e
event -> forall (f :: * -> *) a. Applicative f => a -> f a
pure Event e
event

poll_ :: IO (Either () (Event e))
poll_ :: forall e. IO (Either () (Event e))
poll_ = do
  Either () Tb_event
result <- IO (Either () Tb_event)
Termbox.Bindings.Hs.tb_poll_event
  forall (f :: * -> *) a. Applicative f => a -> f a
pure (forall e. Tb_event -> Event e
parseEvent forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Either () Tb_event
result)

-- Parse an Event from a TbEvent.
parseEvent :: Termbox.Bindings.Hs.Tb_event -> Event e
parseEvent :: forall e. Tb_event -> Event e
parseEvent
  Termbox.Bindings.Hs.Tb_event
    { Tb_event_type
$sel:type_:Tb_event :: Tb_event -> Tb_event_type
type_ :: Tb_event_type
Termbox.Bindings.Hs.type_,
      $sel:mod:Tb_event :: Tb_event -> Tb_event_mod
Termbox.Bindings.Hs.mod = Tb_event_mod
_,
      Tb_key
$sel:key:Tb_event :: Tb_event -> Tb_key
key :: Tb_key
Termbox.Bindings.Hs.key,
      Char
$sel:ch:Tb_event :: Tb_event -> Char
ch :: Char
Termbox.Bindings.Hs.ch,
      Int32
$sel:w:Tb_event :: Tb_event -> Int32
w :: Int32
Termbox.Bindings.Hs.w,
      Int32
$sel:h:Tb_event :: Tb_event -> Int32
h :: Int32
Termbox.Bindings.Hs.h,
      Int32
$sel:x:Tb_event :: Tb_event -> Int32
x :: Int32
Termbox.Bindings.Hs.x,
      Int32
$sel:y:Tb_event :: Tb_event -> Int32
y :: Int32
Termbox.Bindings.Hs.y
    } =
    case Tb_event_type
type_ of
      Tb_event_type
Termbox.Bindings.Hs.TB_EVENT_KEY -> forall e. Key -> Event e
EventKey (if Char
ch forall a. Eq a => a -> a -> Bool
== Char
'\0' then Tb_key -> Key
parseKey Tb_key
key else Char -> Key
KeyChar Char
ch)
      Tb_event_type
Termbox.Bindings.Hs.TB_EVENT_RESIZE ->
        forall e. Size -> Event e
EventResize
          Size
            { $sel:width:Size :: Int
width = forall a b. (Integral a, Num b) => a -> b
fromIntegral @Int32 @Int Int32
w,
              $sel:height:Size :: Int
height = forall a b. (Integral a, Num b) => a -> b
fromIntegral @Int32 @Int Int32
h
            }
      Tb_event_type
Termbox.Bindings.Hs.TB_EVENT_MOUSE ->
        forall e. Mouse -> Event e
EventMouse
          Mouse
            { $sel:button:Mouse :: MouseButton
button = Tb_key -> MouseButton
MouseButton Tb_key
key,
              $sel:pos:Mouse :: Pos
pos =
                Pos
                  { $sel:row:Pos :: Int
row = forall a b. (Integral a, Num b) => a -> b
fromIntegral @Int32 @Int Int32
y,
                    $sel:col:Pos :: Int
col = forall a b. (Integral a, Num b) => a -> b
fromIntegral @Int32 @Int Int32
x
                  }
            }