{-# LANGUAGE OverloadedStrings #-}
module Main where
import Network.Wai.Handler.CGI
import Network.Wai
import Control.Applicative ((<$>))
import Data.Maybe (mapMaybe, fromMaybe)
import Network.HTTP.Types.Status (status200)
import Network.HTTP.Types.Header (hContentType)
import Network.HTTP.Types.URI (queryToQueryText)
import Text.Pandoc
import Text.Pandoc.Error (PandocError)
import Text.Pandoc.Shared (tabFilter)
import Text.Highlighting.Kate (pygments)
import Data.Aeson
import qualified Data.Text as T
import Data.Text (Text)

main :: IO ()
main = run app

app :: Application
app req respond = do
  let query = queryToQueryText $ queryString req
  let getParam x = maybe (error $ T.unpack x ++ " paramater not set")
                       return $ lookup x query
  text <- getParam "text" >>= checkLength . fromMaybe T.empty
  fromFormat <- fromMaybe "" <$> getParam "from"
  toFormat <- fromMaybe "" <$> getParam "to"
  reader <- maybe (error $ "could not find reader for " ++ T.unpack fromFormat)              return
             $ lookup fromFormat fromFormats
  let writer = maybe (error $ "could not find writer for " ++ T.unpack toFormat) id
             $ lookup toFormat toFormats
  let result = case reader $ tabFilter 4 $ T.unpack text of
                    Right doc -> T.pack $ writer doc
                    Left  err -> error (show err)
  let output = encode $ object [ T.pack "result" .= result
                               , T.pack "name" .=
                                  if fromFormat == "markdown_strict"
                                     then T.pack "pandoc (strict)"
                                     else T.pack "pandoc"
                               , T.pack "version" .= pandocVersion]
  respond $ responseLBS status200 [(hContentType,"text/json; charset=UTF-8")] output

checkLength :: Text -> IO Text
checkLength t =
  if T.length t > 10000
     then error "exceeds length limit of 10,000 characters"
     else return t

writerOpts :: WriterOptions
writerOpts = def { writerReferenceLinks = True,
                   writerEmailObfuscation = NoObfuscation,
                   writerHTMLMathMethod = MathJax "http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML",
                   writerHighlight = True,
                   writerHighlightStyle = pygments }

readerOpts :: ReaderOptions
readerOpts = def { readerParseRaw = True,
                   readerSmart = True }

fromFormats :: [(Text, String -> Either PandocError Pandoc)]
fromFormats = [
            ("native"       , readNative)
           ,("json"         , Text.Pandoc.readJSON readerOpts)
           ,("markdown"     , readMarkdown readerOpts)
           ,("markdown_strict" , readMarkdown readerOpts{
                    readerExtensions = strictExtensions,
                    readerSmart = False })
           ,("markdown_phpextra" , readMarkdown readerOpts{
                    readerExtensions = phpMarkdownExtraExtensions })
           ,("markdown_github" , readMarkdown readerOpts{
                    readerExtensions = githubMarkdownExtensions })
           ,("markdown_mmd",  readMarkdown readerOpts{
                    readerExtensions = multimarkdownExtensions })
           ,("rst"          , readRST readerOpts)
           ,("mediawiki"    , readMediaWiki readerOpts)
           ,("docbook"      , readDocBook readerOpts)
           ,("opml"         , readOPML readerOpts)
           ,("t2t"          , readTxt2TagsNoMacros readerOpts)
           ,("org"          , readOrg readerOpts)
           ,("textile"      , readTextile readerOpts) -- TODO : textile+lhs
           ,("html"         , readHtml readerOpts)
           ,("latex"        , readLaTeX readerOpts)
           ,("haddock"      , readHaddock readerOpts)
           ]

toFormats :: [(Text, Pandoc -> String)]
toFormats = mapMaybe (\(x,y) ->
                       case y of
                         PureStringWriter w -> Just (T.pack x, w writerOpts{
                             writerExtensions =
                               case x of
                                  "markdown_strict" -> strictExtensions
                                  "markdown_phpextra" -> phpMarkdownExtraExtensions
                                  "markdown_mmd" -> multimarkdownExtensions
                                  "markdown_github" -> githubMarkdownExtensions
                                  _ -> pandocExtensions
                                 })
                         _                  ->
                            case x of
                                 "rtf"     -> Just (T.pack x, writeRTF writerOpts)
                                 _         -> Nothing) writers

