-- A contrived WAI application which does not make use of
-- wai-routing, but instead works directly on WAI Request.
-- It exposes a single route "eval" to evaluate a small
-- expression which is passed in as query parameters.
--
-- You need wai-extra whic containes the RequestLogger to
-- compile this example.
--
-- The file "eval-routing.hs" does the same but using wai-routing.

module Main (main) where

import Control.Monad
import Data.Attoparsec.ByteString.Char8
import Data.ByteString (ByteString)
import Data.ByteString.From
import Data.String
import Network.HTTP.Types
import Network.Wai
import Network.Wai.Handler.Warp
import Network.Wai.Middleware.RequestLogger

import qualified Data.ByteString.Lazy as Lazy

-- The operations we want to support in expressions.
data Op = Add | Sub | Mul | Div

instance FromByteString Op where
    parser = anyChar >>= \c -> case c of
        '+' -> return Add
        '-' -> return Sub
        '*' -> return Mul
        '/' -> return Div
        _   -> fail $ "Invalid operation: " ++ show c

main :: IO ()
main = run 8080 $ logStdout start

start :: Application
start r = case pathInfo r of
    "eval":[] ->
        let x = join $ lookup "x" (queryString r)
            y = join $ lookup "y" (queryString r)
            f = join $ lookup "f" (queryString r)
        in either (respond status400 . fromString)
                  (respond status200 . fromString . show)
                  (eval f x y)
    _ -> respond status404 ""

eval :: Maybe ByteString -> Maybe ByteString -> Maybe ByteString -> Either String Int
eval (Just f) (Just x) (Just y) = do
    x' <- parseOnly parser x
    y' <- parseOnly parser y
    f' <- parseOnly parser f
    case f' of
        Add -> return (x' + y')
        Sub -> return (x' - y')
        Mul -> return (x' * y')
        Div -> return (x' `div` y')
eval _ _ _ = Left "invalid arguments"

respond :: Monad m => Status -> Lazy.ByteString -> m Response
respond s = return . responseLBS s []