## R GUI supplementary code and tools (loaded since R 2.9.0)

## target environment for all this
.e <- attach(NULL, name = "tools:RGUI")

if (getRversion() < "3.0.0") error(" NOTE: your R version is too old")

add.fn <- function(name, FN) {
    assign(name, FN, .e)
    environment(.e[[name]]) <- .e
}


## print.hsearch is our way to display search results internally
add.fn("print.hsearch", function (x, ...)
{
    if (.Platform$GUI == "AQUA") {
        db <- x$matches
        rows <- NROW(db)
        if (rows == 0) {
            writeLines(strwrap(paste("No help files found matching",
                                     sQuote(x$pattern), "using", x$type, "matching\n\n")))
        } else {
	    ## someone changed the case of some variables in R 3.2.0 so we have to ignore it
	    names(db) <- tolower(names(db))
            url = character(rows)
            for (i in 1:rows) {
		lib <- dirname(db[i, "libpath"])
                tmp <- as.character(help(db[i, "topic"],
                                         package = db[i, "package"],
                                         lib.loc = lib, help_type = 'html'))
                if (length(tmp) > 0)
                    url[i] <- gsub(lib, '/library', tmp, fixed = TRUE)
            }
            wtitle <- paste("Help topics matching", sQuote(x$pattern))
            showhelp <- which(.Call("hsbrowser", db[, "topic"],
                                    db[, "package"], db[, "title"],
                                    wtitle, url))
            for (i in showhelp)
                print(help(db[i, "topic"], package = db[i, "package"]))
        }
        invisible(x)
    }
    else utils:::printhsearchInternal(x, ...)
})

## --- the following functions are compatibility functions that wil go away very soon!

add.fn("browse.pkgs", function (repos = getOption("repos"), contriburl = contrib.url(repos, type), type = getOption("pkgType"))
{
    if (.Platform$GUI != "AQUA")
        stop("this function is intended to work with the Aqua GUI")
    x <- installed.packages()
    i.pkgs <- as.character(x[, 1])
    i.vers <- as.character(x[, 3])
    label <- paste("(", type, ") @", contriburl)
    y <- available.packages(contriburl = contriburl)
    c.pkgs <- as.character(y[, 1])
    c.vers <- as.character(y[, 2])
    idx <- match(i.pkgs, c.pkgs)
    vers2 <- character(length(c.pkgs))
    xx <- idx[which(!is.na(idx))]
    vers2[xx] <- i.vers[which(!is.na(idx))]
    i.vers <- vers2
    want.update <- rep(FALSE, length(i.vers))
    .Call("pkgbrowser", c.pkgs, c.vers, i.vers, label, want.update)
})

add.fn("Rapp.updates", function ()
{
    if (.Platform$GUI != "AQUA")
        stop("this function is intended to work with the Aqua GUI")
    cran.ver <- readLines("http://cran.r-project.org/bin/macosx/VERSION")
    ver <- strsplit(cran.ver, "\\.")
    cran.ver <- as.numeric(ver[[1]])
    rapp.ver <- paste(R.Version()$major, ".", R.version$minor, sep = "")
    ver <- strsplit(rapp.ver, "\\.")
    rapp.ver <- as.numeric(ver[[1]])
    this.ver <- sum(rapp.ver * c(10000, 100, 1))
    new.ver <- sum(cran.ver * c(10000, 100, 1))
    if (new.ver > this.ver) {
        cat("\nThis version of R is", paste(rapp.ver, collapse = "."))
        cat("\nThere is a newer version of R on CRAN which is",
            paste(cran.ver, collapse = "."), "\n")
        action <- readline("Do you want to visit CRAN now? ")
        if (substr(action, 1, 1) == "y")
            system("open http://cran.r-project.org/bin/macosx/")
    } else cat("\nYour version of R is up to date\n")
})

add.fn("package.manager", function ()
{
    if (.Platform$GUI != "AQUA")
        stop("this function is intended to work with the Aqua GUI")
    loaded.pkgs <- .packages()
    x <- library()
    x <- x$results[x$results[, 1] != "base", ]
    pkgs <- x[, 1]
    pkgs.desc <- x[, 3]
    is.loaded <- !is.na(match(pkgs, loaded.pkgs))
    pkgs.status <- character(length(is.loaded))
    pkgs.status[which(is.loaded)] <- "loaded"
    pkgs.status[which(!is.loaded)] <- " "
    pkgs.url <- file.path(find.package(pkgs, quiet=TRUE), "html", "00Index.html")
    load.idx <-
        .Call("pkgmanager", is.loaded, pkgs, pkgs.desc, pkgs.url)
    toload <- which(load.idx & !is.loaded)
    tounload <- which(is.loaded & !load.idx)
    for (i in tounload) {
        cat("unloading package:", pkgs[i], "\n")
        do.call("detach", list(paste("package", pkgs[i], sep = ":")))
    }
    for (i in toload) {
        cat("loading package:", pkgs[i], "\n")
        library(pkgs[i], character.only = TRUE)
    }
})

add.fn("rcompgen.completion", function (x)
{
    utils:::.assignLinebuffer(x)
    utils:::.assignEnd(nchar(x))
    utils:::.guessTokenFromLine()
    utils:::.completeToken()
    utils:::.CompletionEnv[["comps"]]
})

add.fn("data.manager", function ()
{
    if (.Platform$GUI != "AQUA")
        stop("this function is intended to work with the Aqua GUI")
    data.by.name <- function(datanames) {
        aliases <- sub("^.+ +\\((.+)\\)$", "\\1", datanames)
        data(list = ifelse(aliases == "", datanames, aliases))
    }
    x <- suppressWarnings(data(package = .packages(all.available = TRUE)))
    dt <- x$results[, 3]
    pkg <- x$results[, 1]
    desc <- x$results[, 4]
    len <- NROW(dt)
    url <- character(len)
    for (i in 1:len) {
        tmp <- as.character(help(dt[i], package = pkg[i], help_type = "html"))
        if (length(tmp) > 0)
            url[i] <- tmp
    }
    as.character(help("BOD", package = "datasets", help_type = "html"))
    load.idx <- which(.Call("datamanager", dt, pkg, desc, url))
    for (i in load.idx) {
        cat("loading dataset:", dt[i], "\n")
        data.by.name(dt[i])
    }
})

# added "interactive" argument to "prompt(...)"
# if interactive == TRUE the generated Rd doc will be opened in R.app
#   for filename = NA or filename == NULL -> an untitled new Rd doc for passed function
#   for filename = a_path -> a_path will be opened for passed function

add.fn("prompt", function (object, filename = NULL, name = NULL, interactive = FALSE, ...)
{
    if(interactive == FALSE) {
        ## call default prompt()
        ## the name setting here is necessary to avoid taking 'object'
        ## as passed name - TODO has to be improved
        if(missing(name))
            name <- if(is.character(object))
                object
            else {
                name <- substitute(object)
                if(is.name(name))
                    as.character(name)
                else if(is.call(name)
                        && (as.character(name[[1L]]) %in% c("::", ":::", "getAnywhere"))) {
                    name <- as.character(name)
                    name[length(name)]
                }
                else
                    stop("cannot determine a usable name")
            }
        return(utils:::prompt(object, filename = filename, name= name, ...))
    } else {
        ## let R.app handle the result of prompt()
        isTempFile <- FALSE
        if(is.null(filename) || is.na(filename)) {
            ## if no filename was passed we do it on a temporary file
            ## which will be removed by 'RappPrompt->RController.handlePromptRdFileAtPath
            isTempFile <- TRUE
            filename <- tempfile()
        }
        ## call default prompt() by suppressing the outputted messages since
        ## we're in interactive mode
        suppressMessages(utils:::prompt(object=object, filename = filename, name = name, ...))
        ## let RappPrompt - defined in main.m - handle the generated Rd file
        invisible(.Call("RappPrompt", filename, isTempFile))
    }
})

## we catch q/quit to make sure users don't use it inadvertently
if (!isTRUE(getOption("RGUI.base.quit"))) {
add.fn("q", function (save = "default", status = 0, runLast = TRUE)
       .Call("RappQuit", save, status, runLast))
add.fn("quit", function (save = "default", status = 0, runLast = TRUE)
       .Call("RappQuit", save, status, runLast))
}

.e[[".__RGUI__..First"]] <- .GlobalEnv$.First


add.fn("aqua.browser", function(x, ...) {
    ## El Capitan has a bug in ATS that makes it impossible to white-list 127.0.0.1 so we have to use localhost
    x <- gsub("http://127.0.0.1", "http://localhost", x, fixed=TRUE)
    .Call("aqua.custom.print", "help-files", x)
    invisible(x)})

add.fn("main.help.url", function() help.start(browser = aqua.browser))

add.fn("wsbrowser", function(IDS, IsRoot, Container, ItemsPerContainer,
                            ParentID, NAMES, TYPES, DIMS)
{
    .Call("wsbrowser", as.integer(IDS), IsRoot, Container,
          as.integer(ItemsPerContainer), as.integer(ParentID),
          NAMES, TYPES, DIMS)
    invisible()
})

## As from R 2.15.x the BioC version cannot be determined algorithmically

add.fn("setBioCversion", function()
{
    old <- getOption('BioC.Repos')
    if(!is.null(old)) return(old)
    mirror <- getOption("BioC_mirror", "http://www.bioconductor.org")
    ## as of R 3.2.0 it is a function and not a scalar
    ver <- as.character(if (is.function(tools:::.BioC_version_associated_with_R_version)) tools:::.BioC_version_associated_with_R_version() else tools:::.BioC_version_associated_with_R_version)
    options("BioC.Repos" = paste(mirror, "packages",
            ver, c("bioc", "data/annotation", "data/experiment", "extra"),
            sep = "/"))
    getOption('BioC.Repos')
})

if (nzchar(Sys.getenv("R_GUI_APP_VERSION"))) {
    cat("[R.app GUI ",
        Sys.getenv("R_GUI_APP_VERSION")," (",
        Sys.getenv("R_GUI_APP_REVISION"),") ",
        R.version$platform,"]\n\n", sep = '')
} else {
    cat("[Warning: GUI-tools are intended for internal use by the R.app GUI only]\n")
}