module Language.Lojban.Mlismu 
    (newMlismu
    ,isValidFatci
    ,addFatci
    ,readFatci
    ,randomBridi
    ,randomBridiRel
    ,Mlismu)
    where

import Data.Maybe
import Data.Char
import Language.Lojban.Util
import System.Directory
import System.IO
import System.Process
import Utils

-- | Create a new mlismu handle.
newMlismu :: FilePath -> IO (Either String Mlismu)
newMlismu path = do
  is <- doesFileExist path
  if is
     then do db <- openFile path AppendMode
             return $ Right $ Mlismu path db
     else return $ Left $ "\"" ++ path ++ "\" does not exist"

-- | Is a fatci valid?
isValidFatci :: String -> IO Bool
isValidFatci text = do
--  validLojban <- isValidLojban text
  if True -- validLojban
     then isJust `fmap` mlismuBridi (Right text) Nothing 1
     else return False

mlismuBridi :: (Either FilePath String) -> Maybe String -> Int -> IO (Maybe [String])
mlismuBridi path selbri lines' = do
  out <- run ("mlismu -n " ++ show lines' ++  " -f " ++ path' ++ selbri') input
  case out of
    Right ("",good@(_:_)) 
        | Just good' /= selbri -> return $ Just $ lines $ good 
        where good' = list "" (head . lines) good
    _                         -> return Nothing
  where selbri' = maybe "" (" "++) selbri
        path' = either id (const "/dev/stdin") path
        input = either (const "") (++"\n") path

-- | Return a random bridi for a (maybe) given selbri.
randomBridi :: Mlismu -> Maybe String -> IO (Maybe String)
randomBridi mli bridi = start `fmap` mlismuBridi (Left $ mliFile mli) bridi 1
    where start = (>>= list Nothing (Just . head))

-- | Try to return a random bridi for one of the given selbri.
randomBridiRel :: Mlismu -> [String] -> IO (Maybe String)
randomBridiRel mli bridis = findM bridis where
    findM []     = randomBridi mli Nothing
    findM (x:xs) = do
      randomBridi mli (Just x) >>= maybe (findM xs) (return . Just)

-- | Add a new fatci.
addFatci :: Mlismu -> String -> IO Bool
addFatci mli fatci = do
  is <- isValidFatci fatci
  if is
     then do hPutStrLn (mliDB mli) fatci
             hFlush (mliDB mli)
             return True
     else return False

-- | Add any valid fatci from a set of utterances.
readFatci :: Mlismu -> String -> IO ()
readFatci mli = mapM_ (addFatci mli) . splitBridis

splitBridis :: String -> [String]
splitBridis = map unwords . splitBy ((=="i") . filter isLetter) . words

data Mlismu = Mlismu
    { mliFile   :: FilePath
    , mliDB     :: Handle
    }