
module Options where

import System.IO
import System.Console.GetOpt
import System.Environment (getArgs)
import System.Exit
import Control.Monad (when)
import qualified Data.ByteString.Char8 as BC

import Bio.Sequence.SFF
import Bio.Sequence

import Generations.GenBase
import Generations.GS20

data Opts = O { input :: IO [Sequence Nuc]
              , output :: SFF -> IO ()
              , gen :: Generation
              }

defaultopts :: Opts
defaultopts = O { input = error "no input file specified"
                , output = writeSFF' "output.sff"
                , gen = gs20
                }

getOptions :: IO Opts
getOptions  = do
  (os,ns,es) <- getArgs >>= (return . getOpt Permute options)
  os' <- foldl (>>=) (return defaultopts) os
  case es of 
     [] -> return $ os' { input = map castToNuc `fmap` 
                                   if ns == ["-"] then (putStrLn "Reading from stdin" >> hReadFasta stdin)
                                   else concat `fmap` mapM readFasta ns
                                }
     _ -> error (unlines es)

generations = [("GS20",gs20)]

options :: [OptDescr (Opts -> IO Opts)]
options =
    [ Option ['G'] ["generation"] (ReqArg set_gen "string") "Select 454 Generation"
    , Option ['n'] ["num_reads"] (ReqArg set_reads "int") "Number of reads to generate"
    , Option ['f'] ["flows"] (ReqArg set_flows "int") "Number of flows used for each reads"
    , Option ['h'] ["help"] (NoArg (\_ -> do putStrLn (usageInfo usage options)
                                             putStrLn generation_info
                                             exitWith ExitSuccess)) "Display help"
    ]

usage, generation_info :: String
usage = "Usage: pyrosim [-G gen] [-n nreads] [-f nflows] [<input.fasta>]\n"

generation_info = "Valid generations are: "++unwords (map fst generations)

set_gen, set_reads, set_flows :: String -> Opts -> IO Opts
set_gen str opt = case lookup str generations of Just g -> return opt {gen = g }
                                                 Nothing -> error ("Unknown generation '"++str++"' specified\n"
                                                                   ++generation_info)

set_reads str opts = case reads str of [(i,"")] -> do
                                          let ch = (commonhd (gen opts)) { num_reads = i }
                                              g = (gen opts) { commonhd = ch }
                                          return opts { gen = g }
                                       _ -> error ("Can't parse '"++str++"' as <int>.")

set_flows str opts = case reads str of [(i,"")] -> do
                                         when (i `mod` 4 /= 0) $ error "Number of flows must be divisible by four"
                                         let ch = (commonhd (gen opts)) { flow_length = fromIntegral i
                                                                        , flow = BC.concat $ replicate (i `div` 4) $ key ch
                                                                        }
                                             g = (gen opts) { commonhd = ch }
                                         return opts { gen = g }
                                       _ -> error ("Can't parse '"++str++"' as <int>.")
