module Main
where
import Control.Applicative
import Control.Monad.Reader
import qualified Data.ByteString.Char8 as BS
import Data.Maybe
import System.Console.GetOpt
import System.Environment
import System.IO
import Bio.SeqLoc.Bed
import Bio.SeqLoc.GTF
import qualified Bio.SeqLoc.Location as Loc
import Bio.SeqLoc.LocRepr
import Bio.SeqLoc.Strand
import Bio.SeqLoc.Transcript
main :: IO ()
main = getArgs >>= handleOpt . getOpt RequireOrder optDescrs
where handleOpt (_, _, errs@(_:_)) = usage (unlines errs)
handleOpt (args, [gtf], []) = either usage (doGtfToBed gtf) $ argsToConf args
handleOpt (_, _, []) = usage "Specify exactly one GTF file"
usage errs = do prog <- getProgName
hPutStr stderr $ usageInfo prog optDescrs
hPutStrLn stderr errs
doGtfToBed :: FilePath -> Conf -> IO ()
doGtfToBed gtf conf = readGtfTranscriptsErr gtf >>= handleErrors >>= writeTranscriptsOut . map adjustStop
where writeTranscriptsOut trxs = withOutHandle conf $ \h ->
mapM_ (BS.hPutStrLn h . transcriptToBedStd) trxs
adjustStop = if confStopIncluded conf then removeDoubleStop else id
removeDoubleStop trx = trx { cds = cds trx >>= shortenLoc }
shortenLoc l = Loc.clocOutof (Loc.fromBoundsStrand 0 end Plus) l
where end = max 0 $ Loc.length l - 4
handleErrors (trxs, errs) = do maybe putErrs filePutErrs $ confBadTranscripts conf
return trxs
where putErrs = hPutErrs stderr
filePutErrs badtx = withFile badtx WriteMode hPutErrs
hPutErrs h = hPutStr h (unlines errs)
withOutHandle :: Conf -> (Handle -> IO a) -> IO a
withOutHandle conf m = maybe (m stdout) (\outname -> withFile outname WriteMode m) $ confOutput conf
data Conf = Conf { confOutput :: !(Maybe FilePath)
, confBadTranscripts :: !(Maybe FilePath)
, confStopIncluded :: !Bool
} deriving (Show)
data Arg = ArgOutput { unArgOutput :: !String }
| ArgBadTranscripts { unArgBadTranscripts :: !String }
| ArgStopIncluded
deriving (Show, Read, Eq, Ord)
argOutput :: Arg -> Maybe String
argOutput (ArgOutput del) = Just del
argOutput _ = Nothing
argBadTranscripts :: Arg -> Maybe String
argBadTranscripts (ArgBadTranscripts bad) = Just bad
argBadTranscripts _ = Nothing
optDescrs :: [OptDescr Arg]
optDescrs = [ Option ['o'] ["output"] (ReqArg ArgOutput "OUTFILE") "Output filename"
, Option ['b'] ["bad-transcripts"] (ReqArg ArgBadTranscripts "BADFILE") "Write bad transcript list to file"
, Option ['s'] ["stop-included"] (NoArg ArgStopIncluded) "GTF file includes stop codon in CDS"
]
argsToConf :: [Arg] -> Either String Conf
argsToConf = runReaderT conf
where conf = Conf <$>
findOutput <*>
findBadTranscripts <*>
(ReaderT $ return . elem ArgStopIncluded)
findOutput = ReaderT $ return . listToMaybe . mapMaybe argOutput
findBadTranscripts = ReaderT $ return . listToMaybe . mapMaybe argBadTranscripts