{-# LANGUAGE FlexibleInstances, OverloadedStrings #-}
module Web.REST
  ( REST(..), RESTController, rest, routeREST
  , index, show, create, update, delete
  , edit, new
  ) where

import Prelude hiding (show)

import Control.Monad
import Control.Monad.Trans.State
import Data.Functor.Identity
import Web.Simple.Responses
import Web.Simple.Controller
import Network.HTTP.Types

data REST r = REST
  { restIndex   :: Controller r ()
  , restShow    :: Controller r ()
  , restCreate  :: Controller r ()
  , restUpdate  :: Controller r ()
  , restDelete  :: Controller r ()
  , restEdit    :: Controller r ()
  , restNew     :: Controller r ()
  }

defaultREST :: REST r
defaultREST = REST
  { restIndex   = respond $ notFound
  , restShow    = respond $ notFound
  , restCreate  = respond $ notFound
  , restUpdate  = respond $ notFound
  , restDelete  = respond $ notFound
  , restEdit    = respond $ notFound
  , restNew     = respond $ notFound
  }

type RESTControllerM r a = StateT (REST r) Identity a

rest :: RESTControllerM r a -> REST r
rest rcontroller = snd . runIdentity $ runStateT rcontroller defaultREST

routeREST :: REST r -> Controller r ()
routeREST rst = do
  routeMethod GET $ do
    routeTop $ restIndex rst
    routeName "new" $ restNew rst
    routeVar "id" $ do
      routeTop $ restShow rst
      routeName "edit" $ restEdit rst

  routeMethod POST $ routeTop $ restCreate rst

  routeMethod DELETE $ routeVar "id" $ restDelete rst

  routeMethod PUT $ routeVar "id" $ restUpdate rst

type RESTController r = RESTControllerM r ()

index :: Controller r a -> RESTController r
index route = modify $ \controller ->
  controller { restIndex = void route }

create :: Controller r a -> RESTController r
create route = modify $ \controller ->
  controller { restCreate = void route }

edit :: Controller r a -> RESTController r
edit route = modify $ \controller ->
  controller { restEdit = void route }

new :: Controller r a -> RESTController r
new route = modify $ \controller ->
  controller { restNew = void route }

show :: Controller r a -> RESTController r
show route = modify $ \controller ->
  controller { restShow = void route }

update :: Controller r a -> RESTController r
update route = modify $ \controller ->
  controller { restUpdate = void route }

delete :: Controller r a -> RESTController r
delete route = modify $ \controller ->
  controller { restDelete = void route }