{-# LINE 1 "Text/NME.hsc" #-}
{-# LANGUAGE ForeignFunctionInterface #-}
{-# LINE 2 "Text/NME.hsc" #-}

module Text.NME where

import Foreign
import Foreign.C.Types
import Foreign.C.String

import qualified Data.ByteString as BS
import qualified Data.ByteString.UTF8 as BS (toString, fromString)

-- | Takes a string and options, returns Either an error code or a string
--   in the specified format
process :: String -> [ProcessOpt] -> String -> Ptr OutputFormat -> Int -> Either Err String
process [] _ _ _ _ = Right []
process input options eol outputFormat fontSize = unsafeLocalState $
	io_process input options eol outputFormat fontSize

newtype OutputFormat = OutputFormat (Ptr OutputFormat)

foreign import ccall unsafe "NME.h &NMEOutputFormatText"
	outputFormatText ::
	Ptr OutputFormat

foreign import ccall unsafe "NME.h &NMEOutputFormatTextCompact"
	outputFormatTextCompact ::
	Ptr OutputFormat

foreign import ccall unsafe "NME.h &NMEOutputFormatDebug"
	outputFormatDebug ::
	Ptr OutputFormat

foreign import ccall unsafe "NME.h &NMEOutputFormatNull"
	outputFormatNull ::
	Ptr OutputFormat

foreign import ccall unsafe "NME.h &NMEOutputFormatNME"
	outputFormatNME ::
	Ptr OutputFormat

foreign import ccall unsafe "NME.h &NMEOutputFormatHTML"
	outputFormatHTML ::
	Ptr OutputFormat

foreign import ccall unsafe "NME.h &NMEOutputFormatRTF"
	outputFormatRTF ::
	Ptr OutputFormat

foreign import ccall unsafe "NME.h &NMEOutputFormatLaTeX"
	outputFormatLaTeX ::
	Ptr OutputFormat

foreign import ccall unsafe "NME.h &NMEOutputFormatMan"
	outputFormatMan ::
	Ptr OutputFormat

foreign import ccall unsafe "NME.h NMEProcess"
	c_nmeProcess ::
	CString -> CInt -> CString -> CInt -> CInt -> CString ->
	Ptr OutputFormat -> CInt -> Ptr CString -> Ptr CInt -> Ptr CInt ->
	IO Err

io_process :: String -> [ProcessOpt] -> String -> Ptr OutputFormat -> Int -> IO (Either Err String)
io_process input options eol outputFormat fontSize =
	BS.useAsCStringLen (BS.fromString input) (\ (c_input, c_input_len) ->
		BS.useAsCString (BS.fromString eol) (\ c_eol ->
			alloca (\ c_output ->
				alloca (\ c_output_len -> do
					let try_nmeProcess buf bufLen = do
						err <- c_nmeProcess c_input (fromIntegral c_input_len)
						       buf (fromIntegral bufLen) c_options c_eol
						       outputFormat (fromIntegral fontSize) c_output
						       c_output_len nullPtr
						case err of
							Err 1 -> do
								buf <- reallocBytes buf (bufLen * 2)
								try_nmeProcess buf (bufLen * 2);
							Err 0 -> do
								output <- peek c_output
								bs_output <- BS.packCString output
								free buf
								return . Right $ BS.toString bs_output
							_ -> do
								free buf
								return . Left $ err

					let bufLen = c_input_len * 2
					buf <- mallocBytes bufLen
					try_nmeProcess buf bufLen
				)
			)
		)
	)
	where
	c_options = foldr (\(ProcessOpt o) acc -> acc .|. o) 0 options

-- WARNING: If the NME enum definitions change, then these have to change

newtype Err = Err CInt deriving (Show, Eq)
kNMEErrOk  :: Err
kNMEErrOk  = Err 0
kNMEErrNotEnoughMemory  :: Err
kNMEErrNotEnoughMemory  = Err 1
kNMEErrBadMarkup  :: Err
kNMEErrBadMarkup  = Err 2
kNMEErrInternal  :: Err
kNMEErrInternal  = Err 3
kNMEErr1stNMEOpt  :: Err
kNMEErr1stNMEOpt  = Err 4
kNMEErr1stUser  :: Err
kNMEErr1stUser  = Err 10000

{-# LINE 107 "Text/NME.hsc" #-}

newtype ProcessOpt = ProcessOpt CInt deriving (Show, Eq)
kNMEProcessOptDefault  :: ProcessOpt
kNMEProcessOptDefault  = ProcessOpt 0
kNMEProcessOptNoPreAndPost  :: ProcessOpt
kNMEProcessOptNoPreAndPost  = ProcessOpt 1
kNMEProcessOptNoH1  :: ProcessOpt
kNMEProcessOptNoH1  = ProcessOpt 4
kNMEProcessOptH1Num  :: ProcessOpt
kNMEProcessOptH1Num  = ProcessOpt 8
kNMEProcessOptH2Num  :: ProcessOpt
kNMEProcessOptH2Num  = ProcessOpt 16
kNMEProcessOptNoDL  :: ProcessOpt
kNMEProcessOptNoDL  = ProcessOpt 32
kNMEProcessOptNoIndentedPar  :: ProcessOpt
kNMEProcessOptNoIndentedPar  = ProcessOpt 64
kNMEProcessOptNoMultilinePar  :: ProcessOpt
kNMEProcessOptNoMultilinePar  = ProcessOpt 128
kNMEProcessOptNoEscape  :: ProcessOpt
kNMEProcessOptNoEscape  = ProcessOpt 256
kNMEProcessOptNoHRule  :: ProcessOpt
kNMEProcessOptNoHRule  = ProcessOpt 512
kNMEProcessOptNoLink  :: ProcessOpt
kNMEProcessOptNoLink  = ProcessOpt 1024
kNMEProcessOptNoImage  :: ProcessOpt
kNMEProcessOptNoImage  = ProcessOpt 2048
kNMEProcessOptNoTable  :: ProcessOpt
kNMEProcessOptNoTable  = ProcessOpt 4096
kNMEProcessOptNoUnderline  :: ProcessOpt
kNMEProcessOptNoUnderline  = ProcessOpt 8192
kNMEProcessOptNoMonospace  :: ProcessOpt
kNMEProcessOptNoMonospace  = ProcessOpt 16384
kNMEProcessOptNoSubSuperscript  :: ProcessOpt
kNMEProcessOptNoSubSuperscript  = ProcessOpt 32768
kNMEProcessOptNoBold  :: ProcessOpt
kNMEProcessOptNoBold  = ProcessOpt 65536
kNMEProcessOptNoItalic  :: ProcessOpt
kNMEProcessOptNoItalic  = ProcessOpt 131072
kNMEProcessOptNoPlugin  :: ProcessOpt
kNMEProcessOptNoPlugin  = ProcessOpt 262144
kNMEProcessOptVerbatimMono  :: ProcessOpt
kNMEProcessOptVerbatimMono  = ProcessOpt 1048576
kNMEProcessOptXRef  :: ProcessOpt
kNMEProcessOptXRef  = ProcessOpt 2097152

{-# LINE 131 "Text/NME.hsc" #-}