{-# LANGUAGE DeriveDataTypeable, NoImplicitPrelude, PackageImports #-}
{- |

client-side half of a typed AJAX communication channel.

To use this library, you could start by defining a type in a file that
can be shared between the Haskell Server and Fay client. For example:

@
    data Command
        = SendGuess Guess (ResponseType (Maybe Row))
        | FetchBoard (ResponseType (Maybe Board))
        deriving (Read, Show, Data, Typeable)
    instance Foreign Command
@

The 'ResponseType' argument specifies what type each command should
return. Using GADTs would be cleaner, but Fay does not support GADTs
yet.

To execute a remote function we use the 'call' function:

@
      call "/ajax" FetchBoard $ \mboard -> ...
@

Due to the single-threaded nature of Javascript, we do not want to
block until the 'call' returns a value, so we perform the AJAX request
asynchronously. The third argument to 'call' is the callback function
to run when the response is received.

-}
module AJAX where

import "fay-base" Data.Data
import FFI
import JQuery
import ResponseType
import "fay-base" Prelude

-- | Asynchronously call a command
--
-- Note: if the server returns 404 or some other non-success exit
-- code, the callback function will never be run.
--
-- This function is just a wrapper around 'ajaxCommand' which uses the
-- 'ResponseType res' phantom-typed parameter for added type safety.
call :: String                    -- ^ URL to 'POST' AJAX request to
     -> (ResponseType res -> cmd) -- ^ AJAX command to send to server
     -> (res -> Fay ())           -- ^ callback function to handle response
     -> Fay ()
call uri f g = ajaxCommand uri (f ResponseType) g

-- | Run the AJAX command. (internal)
--
-- You probably want to use 'call' which provides additional
-- type-safety.
--
-- Note: if the server returns 404 or some other non-success exit
-- code, the callback function will never be run.
--
-- see also: 'call'
ajaxCommand :: String -> Automatic cmd -> (Automatic res -> Fay ()) -> Fay ()
ajaxCommand =
    ffi "jQuery['ajax']({'url': %1, 'type': 'POST', 'data': { 'json' : JSON.stringify(%2) }, 'dataType': 'json', 'success' : %3 })"