{-# LANGUAGE EmptyDataDecls    #-}

-- | Document object model functions. Most of this doesn't have
-- anything to do with the DOM and is actually ECMA library stuff, but
-- I'll leave it in for now.

module DOM where

import FFI
import Prelude

--------------------------------------------------------------------------------
-- Foreign Data Declarations.

data Document
data Element
data Event
data Global
data NodeList
data Timer
data XMLHttpRequest

--------------------------------------------------------------------------------
-- Browser globals

getWindow :: Fay Global
getWindow = ffi "window"

getDocument :: Fay Document
getDocument = ffi "window.document"

addEvent :: String -> Fay f -> Fay ()
addEvent = ffi "window['addEventListener'](%1,%2)"

--------------------------------------------------------------------------------
-- Events.

stopProp :: Event -> Fay ()
stopProp = ffi "%1['stopPropagation']()"

preventDefault :: Event -> Fay ()
preventDefault = ffi "%1['preventDefault']()"

--------------------------------------------------------------------------------
-- Element accessors.

createElement :: String -> Fay Element
createElement = ffi "window['document']['createElement'](%1)"

appendChild :: Element -> Element -> Fay ()
appendChild = ffi "%1.appendChild(%2)"

removeChild :: Element -> Element -> Fay ()
removeChild = ffi "%1.removeChild(%2)"

parentNode :: Element -> Fay Element
parentNode = ffi "%1.parentNode"

children :: Element -> Fay NodeList
children = ffi "%1.children"

--------------------------------------------------------------------------------
-- Timers

-- | setInterval except the calling function gets the timer as an
-- | argument so the interval can be cancelled from within it.
setInterval :: Double -> (Timer -> Fay ()) -> Fay Timer
setInterval = ffi "(function (f,i) { var id = window['setInterval'](function () { f(id); }, i); })(%2,%1)"

clearInterval :: Timer -> Fay ()
clearInterval = ffi "window['clearInterval'](%1)"

setTimeout :: Double -> (Timer -> Fay ()) -> Fay Timer
setTimeout = ffi "window['setTimeout'](%2,%1)"

--------------------------------------------------------------------------------
-- XMLHttpRequest

data RequestMethod = GET | POST | PUT | HEAD

data ReadyState = UNSENT | OPENED | HEADERS_RECEIVED | LOADING | DONE

xmlHttpRequest :: Fay XMLHttpRequest
xmlHttpRequest = ffi "(function(window) { if(window['XMLHttpRequest']) return new XMLHttpRequest(); else return new ActiveXObject('Microsoft.XMLHTTP'); })(window)"

open :: RequestMethod -> String -> XMLHttpRequest -> Fay XMLHttpRequest
open = ffi "(function(method, url, xhr) { xhr['open'](method['instance'], url, true); return xhr; })(%1, %2, %3)"

send :: XMLHttpRequest -> Fay ()
send = ffi "%1['send']()"

setReadyStateHandler :: (XMLHttpRequest -> Fay ()) -> XMLHttpRequest -> Fay XMLHttpRequest
setReadyStateHandler = ffi "(function(handler, xhr) { xhr['onreadystatechange'] = function() { handler(xhr); }; return xhr; })(%1, %2)"

readyState :: XMLHttpRequest -> Fay ReadyState
readyState = ffi "{ instance: ['UNSENT', 'OPENED', 'HEADERS_RECEIVED', 'LOADING', 'DONE'][%1['readyState']] }"

responseText :: XMLHttpRequest -> Fay String
responseText = ffi "%1['responseText']"

status :: XMLHttpRequest -> Fay Int
status = ffi "%1['status']"