module Main where import Control.Applicative import Control.Monad.Reader import Data.Maybe import System.Console.GetOpt import System.Environment import System.IO import qualified Data.Iteratee as Iter import qualified Bio.SamTools.Bam as Bam import qualified Bio.SamTools.Iteratee as Bam main :: IO () main = getArgs >>= handleOpt . getOpt RequireOrder optDescrs where handleOpt (_, _, errs@(_:_)) = usage (unlines errs) handleOpt (args, [bam], []) = either usage (doBamFilter bam) $ argsToConf args handleOpt (_, _, []) = usage "Specify exactly one BAM input" usage errs = do prog <- getProgName hPutStr stderr $ usageInfo prog optDescrs hPutStrLn stderr errs doBamFilter :: FilePath -> Conf -> IO () doBamFilter bam conf = Bam.withBamInFile bam $ \hin -> Bam.withBamOutFile (confOutput conf) (Bam.inHeader hin) $ \hout -> let bamiter = Iter.joinI $ Iter.filter (wanted conf) $ Iter.mapM_ (Bam.put1 hout) in Bam.enumInHandle hin bamiter >>= Iter.run wanted :: Conf -> Bam.Bam1 -> Bool wanted conf | confPerfect conf = maybe False (== 0) . Bam.nMismatch | otherwise = const True data Conf = Conf { confOutput :: !FilePath , confPerfect :: !Bool } deriving (Show) data Arg = ArgOutput { unArgOutput :: !String } | ArgPerfect deriving (Show, Read, Eq, Ord) argOutput :: Arg -> Maybe String argOutput (ArgOutput del) = Just del argOutput _ = Nothing optDescrs :: [OptDescr Arg] optDescrs = [ Option ['o'] ["output"] (ReqArg ArgOutput "OUTFILE") "Output filename" , Option [] ["perfect"] (NoArg ArgPerfect) "Filter perfect (NM:i:0) reads" ] argsToConf :: [Arg] -> Either String Conf argsToConf = runReaderT conf where conf = Conf <$> findOutput <*> (ReaderT $ return . elem ArgPerfect) findOutput = ReaderT $ maybe (Left "No output file") return . listToMaybe . mapMaybe argOutput