{-# LANGUAGE Rank2Types #-}

module Options where

import System.Environment (getArgs)
import System.Console.GetOpt
import Control.Monad

import Bio.Util (countIO)

htmldir :: String
htmldir = "blast.d"

getOptions :: IO Options
getOptions  = do as <- getArgs
                 let (optf,non,err) = getOpt Permute options as
                 when (not (null err)) $ error ("Usage: "++usage err)
                 if (null non && null as)
                     then error $ usageInfo ("Usage: "++usagemsg++synopsis) options
                     else do opt <- parseargs optf
                             return opt { inputs = non }

usage :: [String] -> String
usage errs = usageInfo (concat errs ++ usagemsg) options

usagemsg, synopsis :: String
usagemsg = "xml2x [options] blast.xml\n"
synopsis = "Convert BLASTX XML files to CSV or HTML\n"
           ++ "optionally adding GO annotations.\n"

data Options = Opts { godef, goann :: Maybe FilePath
                    , ko :: [FilePath]  -- multiple species allowed
                    , format :: Format
                    , output :: String -> IO ()
                    , inputs :: [FilePath]

                    -- verbosity/progress reporting
                    , verb   :: Bool
                    , count  :: forall a . Int -> String -> [a] -> IO [a]

                    -- output filtering
                    , select :: Select
                    }

data Format = Csv | Html deriving Eq
data Select = All | Top | Reg deriving Eq

options :: [OptDescr (Options -> IO Options)]
options = [Option [] ["ontology"]     (ReqArg (\arg opt -> return opt { godef = Just arg }) "File")
                      "GO ontology definition (.obo file)"
          ,Option [] ["annotations"] (ReqArg (\arg opt -> return opt { goann = Just arg }) "File")
                      "GOA associations"

          ,Option ['k'] ["kegg-organism"]     (ReqArg (\arg opt -> return opt { ko = arg : ko opt }) "File")
                      "Organism prefix for KEGG"

          -- Verbosity
          ,Option ['v'] ["verbose"]
                      (NoArg (\opt -> return opt {verb = True, count = \n msg -> countIO msg " ..done!\n" n }))
                      "Display progress"
          ,Option ['q'] ["quiet"]   (NoArg (\opt -> return opt {verb = False, count = \_ _ -> return . id}))
                      "Don't display progress"

          -- Output formats
          ,Option ['H'] ["html-output"] (NoArg (\opt -> return opt { format = Html }))
                      "Output HTML"
          ,Option ['C'] ["csv-output"]  (NoArg (\opt -> return opt { format = Csv }))
                      "Output comma-separated values"
          ,Option ['o'] ["output-file"] (ReqArg (\arg opt -> return opt { output = writeFile arg }) "File")
                  "Output file"
          ,Option ['1'] ["top"] (NoArg (\opt -> return opt { select = Top }))
                  "Output only best BLAST hit"
          ,Option [] ["all"] (NoArg (\opt -> return opt { select = All }))
                  "Output all BLAST hits"
          ,Option [] ["regions"] (NoArg (\opt -> return opt { select = Reg }))
                  "Output distinct BLAST hit regions"
          ]

defaultopts :: Options
defaultopts = Opts { godef = Nothing, goann = Nothing, format = Csv
                   , ko = []
                   , output = putStr, verb = False, inputs = []
                   , count = \_ _ -> return . id, select = All }

parseargs :: [Options -> IO Options] -> IO Options
parseargs args = foldl (>>=) (return defaultopts) args >>= verify
    where verify = return . id  -- todo: check that files are correctly specified,
                                -- godef only makes sense with goann

