geneBounds <- function(txdb)
{
    if (!is(txdb, "TranscriptDb")) 
        stop("'txdb' must be a TranscriptDb object")
    genes <- transcriptsBy(txdb, "gene")
    elementMetadata(genes@unlistData) <- NULL
    empty <- which(elementLengths(genes) == 0L)
    if (length(empty) > 0)
        genes <- genes[- empty]
    ranges <- unlist(reduce(ranges(genes)))
    genes <-
      unlist(seqselect(genes, rep(IntegerList(1L), length(genes))),
             use.names=FALSE)
    genes@ranges <- ranges
    genes
}

geneIntrons <- function(txdb)
{
    if (!is(txdb, "TranscriptDb")) 
        stop("'txdb' must be a TranscriptDb object")
    genes <- exonsBy(txdb, "gene")
    elementMetadata(genes@unlistData) <- NULL
    empty <- which(elementLengths(genes) == 0L)
    if (length(empty) > 0)
        genes <- genes[- empty]
    ranges <- gaps(ranges(genes))
    first <- unlist(genes[rep(IntegerList(1L), length(genes))])
    seqnames <- Rle(as.vector(seqnames(first)), elementLengths(ranges))
    strand <- Rle(as.vector(strand(first)), elementLengths(ranges))
    granges <-
      GRanges(seqnames = seqnames, ranges = unlist(ranges, use.names=FALSE),
              strand = strand)
    new("GRangesList", unlistData = granges,
        partitioning = ranges@partitioning,
        elementMetadata = new("DataFrame", nrows = length(ranges)))
}

countExonIdsByTxOverlaps <- function(txdb, subject)
{
    if (!is(txdb, "TranscriptDb")) 
        stop("'txdb' must be a TranscriptDb object")
    exons <- exons(txdb)
    exonCounts <- countOverlaps(exons, subject)
    names(exonCounts) <- as.character(values(exons)[["exon_id"]])
    exonsByTx <- exonsBy(txdb, "tx")

    exonIdsByTxCounts <-
      new("CompressedIntegerList",
          unlistData =
          unname(exonCounts[as.character(values(exonsByTx@unlistData)[["exon_id"]])]),
          partitioning = exonsByTx@partitioning)
    exonIdsByTxCounts <-
      exonIdsByTxCounts[order(sum(exonIdsByTxCounts), decreasing=TRUE)]
    
    tx <- transcripts(txdb, columns = c("tx_id", "gene_id"))
    geneMapping <- unlist(values(tx)[["gene_id"]])[names(exonIdsByTxCounts)]
    geneMapping <- factor(geneMapping, levels = unique(geneMapping))
    split(DataFrame(tx_id = as.integer(names(exonIdsByTxCounts)),
                    exon_counts = exonIdsByTxCounts,
                    total_count = sum(exonIdsByTxCounts)),
          geneMapping)
}


rpkm <- function(count, ranges)
{
    if (missing(ranges))
        stop("'ranges' must be a GRanges or GRangesList object")
    else if (is(ranges, "GRanges"))
        numBases <- width(ranges)
    else if (is(ranges, "GRangesList"))
        numBases <- sum(width(ranges))
    else
        stop("'ranges' must be a GRanges or GRangesList object")

    geneLengthsInKB <- numBases / 1000
    millionsMapped <- sum(count) / 1000000
    rpm <- count / millionsMapped
    rpm / geneLengthsInKB
}
