{-# LANGUAGE TypeSynonymInstances, FlexibleInstances, MultiParamTypeClasses #-}

module FRP.Netwire.Input.JavaScript (
        JSInputState,
        JSInputControl,
        JSInput,
        JSInputT,
        Key(..),
        MouseButton(..),
        mkInputControl,
        initialInputState,
        pollJavaScript,
        cursorLocked,
        lockCursor,
        unlockCursor
) where

import Control.Applicative
import Control.Wire
import FRP.Netwire.Input hiding (Key, MouseButton)
import qualified FRP.Netwire.Input

import Control.Monad.Trans.State
import JavaScript.Input

instance FRP.Netwire.Input.Key Key
instance FRP.Netwire.Input.MouseButton MouseButton

instance Monad m => MonadMouse MouseButton (JSInputT m) where
        setCursorMode cm = setCursorModeM $
                case cm of
                     CursorMode'Enabled -> (Just False, Just False)
                     CursorMode'Hidden -> (Just False, Just True)
                     _ -> (Just True, Nothing)
        mbIsPressed = mbIsPressedM
        releaseButton = releaseButtonM
        cursor = cursorM
        scroll = scrollM

instance Monad m => MonadKeyboard Key (JSInputT m) where
        keyIsPressed = keyIsPressedM
        releaseKey = releaseKeyM

-- | In JavaScript, you can lock the pointer only after the user releases a
-- mouse button or a key. This means that 'cursorMode' (with 'CursorMode'Reset')
-- and 'mouseMickies' will not actually lock the pointer, but will schedule
-- the pointer lock request for the next interaction from the user.
-- In particular, 'mouseMickies' will behave like 'mouseCursor' if the pointer
-- is not locked.
--
-- This wire, which inhibits if the pointer is not locked, is
-- useful if you want to know if you're still waiting for the user to lock the
-- pointer, and if the user manually unlocked it.
cursorLocked :: (Monoid e, Monad m) => Wire s e (JSInputT m) a a
cursorLocked = mkGen_ $ \x -> boolToEither x <$> lockedCursorM
        where boolToEither _ False = Left mempty
              boolToEither x True = Right x