{-# LANGUAGE TypeSynonymInstances, FlexibleInstances  #-}

module Hack where

import Data.Default
import System.IO
import qualified Data.ByteString.Lazy as L
import qualified Data.ByteString as B

type Application = Env -> IO Response
type Middleware  = Application -> Application

data RequestMethod =
     OPTIONS
  |  GET
  |  HEAD
  |  POST
  |  PUT
  |  DELETE
  |  TRACE
  |  CONNECT
  deriving (Show, Read, Eq)

data Hack_UrlScheme = HTTP | HTTPS deriving (Show, Eq)

type HackErrors = String -> IO ()

instance Show HackErrors where
  show _ = "Error Stream"

data Env = Env 
  {  requestMethod  :: RequestMethod
  ,  scriptName     :: String
  ,  pathInfo       :: String
  ,  queryString    :: String
  ,  serverName     :: String
  ,  serverPort     :: Int
  ,  http           :: [(String, String)]
  ,  hackVersion    :: [Int]
  ,  hackUrlScheme  :: Hack_UrlScheme
  ,  hackInput      :: L.ByteString
  ,  hackErrors     :: HackErrors
  ,  hackHeaders    :: [(String, String)]
  ,  hackCache      :: [(B.ByteString, B.ByteString)]
  ,  remoteHost     :: String
  }
  deriving (Show)

data Response = Response
  {  status   :: Int
  ,  headers  :: [(String, String)]
  ,  body     :: L.ByteString
  }
  deriving (Show)

instance Default RequestMethod where
  def = GET

instance Default Hack_UrlScheme where
  def = HTTP

instance Default Response where
  def = Response def def L.empty

instance Default Env where
  def = Env {
        requestMethod = def
      , scriptName    = def
      , pathInfo      = def
      , queryString   = def
      , serverName    = def
      , serverPort    = def
      , http          = def
      , hackVersion   = currentVersion
      , hackUrlScheme = def
      , hackInput     = L.empty
      , hackErrors    = defaultErrorStream
      , hackHeaders   = def
      , hackCache     = def
      , remoteHost    = def
      }
    where
      defaultErrorStream = (hPutStr stderr)
      currentVersion = [2009, 10, 30]