{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE DeriveGeneric #-}

module Quenya.Web where
import GHC.Generics
import Web.Scotty
import Quenya.Conjugator (conjugate)
import qualified Quenya.Conjugator as C
import Quenya.Conversion
import Quenya.Arguments (getArgs)
import Data.Monoid (mconcat)
import Data.Aeson hiding (json, object)
import qualified Data.Aeson as A (object)
import Data.Maybe (fromMaybe)
import Control.Monad
import Control.Applicative ((<$>), (<*>), pure)
import qualified Data.ByteString.Lazy as BS
import Network.Wai.Handler.Warp
import Network.Wai (Application(..))
import Safe (atMay)
import qualified Data.Map as M (fromList, Map(..))
import qualified Data.Text as T
import qualified Data.Text.Lazy.IO as T
import Data.Word (Word16(..))
import Network.Socket
import Control.Monad.IO.Class (liftIO)
import Network
import Data.IP
import Network.Wai.Middleware.RequestLogger
import Network.Wai.Middleware.Static

-- | Runs 'application' as a Warp app
main :: IO ()
main = do
  (port, addr, logging) <- getArgs
  let sett = {-setHost (addr :: HostPreference) $-} setPort port defaultSettings
  app <- application logging
  runSettings sett app

-- | Converts the Scotty app to a Warp app, for ease of deployment
application :: Bool -> IO Application
application logging = scottyApp $ do
  i <- liftIO (T.readFile "index.html")
  if logging then middleware logStdoutDev else return ()
  middleware $ staticPolicy (hasPrefix "static")
  post "/api/verb" $ do
    b <- body
    json $ respond b
  get "/" $ html i

-- | Takes the raw body of a request and returns a JSONable response
respond :: BS.ByteString -> M.Map String String
respond b = M.fromList [("conjugated_verb", conjugate $ toVerb $ fromMaybe defaultStringVerb $ (decode b :: Maybe StringVerb))]

-- | The "raw" (i.e. without ADTs) verb data type. Only use for interacting with the user.
data StringVerb = StringVerb { stem :: String
                             , tense :: String
                             , subject :: String
                             , object :: String
                             } deriving (Show, Generic)

instance FromJSON StringVerb

-- | Arbitrary default verb, meaning "I love you"
defaultStringVerb :: StringVerb
defaultStringVerb = StringVerb "mel" "aorist" "you" "me"

-- | Converts a 'StringVerb' to a 'C.Verb' using the functions in 'Quenya.Conversion'
toVerb :: StringVerb -> C.Verb
toVerb sv = C.Verb st te su ob
    where st = makeStem $ stem sv
          te = fromMaybe C.Present $ makeTense $ tense sv
          su = fromMaybe C.FstSg $ makePerson $ subject sv
          ob = fromMaybe C.SndFamiliarSg $ makePerson $ object sv