module SodCurses.SodCurses where

import SodCurses.Canvas

import Control.Concurrent
import Control.Monad
import FRP.Sodium
import UI.HSCurses.Curses
import UI.HSCurses.CursesHelper

-- | Takes a function that takes a event that fires on each tick and one which fires on events
-- and produces a tuple of a behaviour of when to stop and a behaviour of what to draw.
-- The system will refresh 10 times a second, drawing the canvas in the second term until
-- the first term is false.
run :: (Event () -> Event Key -> IO (Behaviour Bool, Behaviour Canvas)) -> IO ()
run f = do
    (eTick,tickID)  <- tickEvent $ 10^5
    (eKey,keyID) <- keyEvent
    f eTick eKey >>= uncurry setup 
    killThread tickID
    killThread keyID

-- | Does the house keeping for making the program run. Runs runLoop as well.
setup :: Behaviour Bool -> Behaviour Canvas -> IO ()
setup bCont bCanvas = do
    start
    cursSet CursorInvisible
    w <- initScr
    wclear w
    runLoop w bCont bCanvas 
    cursSet CursorVisible
    end

-- | Draws the Canvas every 100 miliseconds (roughly) until the first behaviour
-- is false
runLoop :: Window -> Behaviour Bool -> Behaviour Canvas -> IO ()
runLoop w bCont bCanv = do
    erase
    sync (sample bCanv) >>= drawCanvas w
    wRefresh w
    c <- sync $ sample bCont
    when c $ timeout (10^2) >> runLoop w bCont bCanv
    
-- | Produces and event which ticks every t micro seconds
tickEvent :: Int -> IO (Event (), ThreadId)
tickEvent t = do
    (eTick,pushTick) <- sync newEvent
    i <- forkIO $ forever ( sync (pushTick ()) >> threadDelay t)
    return (eTick,i)

-- | Produces and event which fires when a key is pressed
keyEvent :: IO (Event Key, ThreadId)
keyEvent = do
    (eKey,pushKey) <- sync newEvent
    i <- forkIO $ forever (getCh >>= sync . pushKey)
    return (eKey,i)
