#==========================================================================
# JGR - Java Gui for R
# Package version: 1.6-5
#
# $Id$
# (C)Copyright 2004-2009 Markus Helbig
# (C)Copyright 2009 Ian Fellows
# (C)Copyright 2004,2006,2007 Simon Urbanek
# Licensed under GPL v2

#==========================================================================
# initialization
#==========================================================================


# library initialization:
.First.lib <- function(lib, pkg) {
  library(utils)
  ##cat("\nLoading additional JGR support...\n")
  library(rJava)
  je <- as.environment(match("package:JGR", search()))
  assign(".jgr.pkg.path", paste(lib,pkg,sep=.Platform$file.sep), je)
  assign(".jgr.works", FALSE, je)
  #assign(".jgr.env", new.env(), .je)
  
  ## we supply our own JavaGD class
  .setenv <- if (exists("Sys.setenv")) Sys.setenv else Sys.putenv
  .setenv("JAVAGD_CLASS_NAME"="org/rosuda/JGR/toolkit/JavaGD")

  ## now load rJava for callbacks
  ## strictly speaking we should not need to add JGR, because
  ## the launcher must set the correct classpath anyway
  cp <- paste(lib, pkg, "java", "JGR.jar",sep=.Platform$file.sep)
  .jinit(cp)

  ## next make sure and JRI and iBase are present
  add.classes <- character()
  if (is.jnull(.jfindClass("org/rosuda/JRI/REXP",silent=TRUE)))
    add.classes <- paste(installed.packages()["rJava","LibPath"],"rJava","jri","JRI.jar",sep=.Platform$file.sep)
  if (is.jnull(.jfindClass("org/rosuda/ibase/Common",silent=TRUE)))
    add.classes <- c(add.classes,paste(installed.packages()["iplots","LibPath"],"iplots","java","iplots.jar",sep=.Platform$file.sep))

  ## if any classes are missing or JGR was not started using main method, get out
  ## this should be true only if JGR was loaded into a "regular" R
  if (length(add.classes)>0 || !.jcall("org/rosuda/JGR/JGR","Z","isJGRmain")) {
    cat("\nPlease use the corresponding JGR launcher to start JGR.\nRun JGR() for details. You can also use JGR(update=TRUE) to update JGR.\n\n")
    return(TRUE)
  }

  ## JGR actually works
  assign(".jgr.works", TRUE, je)

	# set JGR options unless the user doesn't want us to
	if (Sys.getenv("JGR_NO_OPTIONS")=="")
    	jgr.set.options()

	# set RHome Path in JGR
	invisible(.jcall("org/rosuda/JGR/JGR","V","setRHome",as.character(R.home())))
			
	invisible(.jcall("org/rosuda/JGR/JGR","V","setRLibs",as.character(.libPaths())))
			
	invisible(.jcall("org/rosuda/JGR/JGR","V","setKeyWords",as.character(.refreshKeyWords())))
			
	invisible(.jcall("org/rosuda/JGR/JGR","V","setObjects",as.character(.refreshObjects())))
	
	# set repos
	if (options("repos")=="@CRAN@") options(repos="http://cran.r-project.org")
			
	# set Path to helpFiles
	.refreshHelpFiles()

  	# add PackageInstaller
	# jgr.addMenuItem("Packages","Package Installer","installPackages()")
}


package.manager <- function() {
  if (!.jgr.works) { cat("package.manager() cannot be used outside JGR.\n"); return(invisible(NULL)) }
	f <- .jcall("org/rosuda/JGR/JGRPackageManager",,"showInstance")
}

installPackages <- function (contriburl = NULL, type = getOption("pkgType")) 
{
    if (!.jgr.works) {
        cat("installPackages() cannot be used outside JGR.\n")
        return(invisible(NULL))
    }
    if (type == "mac.binary") {
        if (R.version$major >= 2 && R.version$minor >= 2) 
            a <- available.packages(contriburl = contrib.url(getOption("repos"), 
															 type = "mac.binary"))
				else if (R.version$major >= 2 && R.version$minor >= 1) 
					a <- CRAN.packages(contriburl = contrib.url(getOption("repos"), 
																type = "mac.binary"))
						else a <- CRAN.packages(contriburl = contrib.url(getOption("CRAN"), 
																		 type = "mac.binary"))
    }
		else if (!is.null(contriburl)) 
			if (R.version$major >= 2 && R.version$minor >= 2) 
				a <- available.packages(contriburl = contriburl)
			else a <- CRAN.packages(contriburl = contriburl)
		else if (R.version$major >= 2 && R.version$minor >= 2) 
			a <- available.packages()
		else a <- CRAN.packages()
		pkgs <- a[, 1]
		if (length(pkgs) > 0) {
			invisible( .jcall("org/rosuda/JGR/JGRPackageInstaller",,"instAndDisplay",pkgs, 
								type))
		}
}

object.browser <- function() {
  if (!.jgr.works) { cat("object.browser() cannot be used outside JGR.\n"); return(invisible(NULL)) }
	f <- .jcall("org/rosuda/JGR/JGRObjectManager",,"showInstance")
}

jgr.pager <- function(file, header, title, delete.file) {
  if (!.jgr.works) { cat("jgr.pager() cannot be used outside JGR.\n"); return(invisible(NULL)) }
	invisible(.jcall("org/rosuda/JGR/toolkit/TextPager",,"launchPager",as.character(file), as.character(header), as.character(title), as.logical(delete.file)))
}

jgr.set.options <- function(..., useJavaGD=TRUE, useJGRpager=TRUE) {
  if (!.jgr.works) { cat("jgr.set.options() cannot be used outside JGR.\n"); return(invisible(NULL)) }
	if (useJavaGD) {
    	require(JavaGD)
		options(device="JavaGD")
	}
	if (useJGRpager) {
    	options(pager=jgr.pager)
	}
}

# add new menus at runtime to JGR Console

jgr.addMenu <- function(name) {
  if (!.jgr.works) { cat("jgr.addMenu() cannot be used outside JGR.\n"); return(invisible(NULL)) }
	invisible(.jcall("org/rosuda/JGR/JGR","V","addMenu",as.character(name)))
}

jgr.addMenuItem <- function(menu, name, command) {
  if (!.jgr.works) { cat("jgr.addMenuItem() cannot be used outside JGR.\n"); return(invisible(NULL)) }
  if (is.function(command))
    command <- .jgr.register.function(command)
  invisible(.jcall("org/rosuda/JGR/JGR","V","addMenuItem",as.character(menu),as.character(name),as.character(command)))
}

jgr.addMenuSeparator <- function(menu) {
  if (!.jgr.works) { cat("jgr.addMenuSeparator() cannot be used outside JGR.\n"); return(invisible(NULL)) }
	invisible(.jcall("org/rosuda/JGR/JGR","V","addMenuSeparator",as.character(menu)))
}

# creates a 'command' based on a function by calling the function without arguments
.jgr.register.function <- function(fun) {
  if (is.null(.GlobalEnv$.jgr.user.functions)) .GlobalEnv$.jgr.user.functions <- list()
  fnc <- length(.GlobalEnv$.jgr.user.functions)+1
  .GlobalEnv$.jgr.user.functions[[fnc]] <- fun
  paste(".jgr.user.functions[[",fnc,"]]()",sep='')
}

#'internal' functions for JGR, without them JGR is not able to survive

.completeCommand <- function (x) 
{
    result <- c()
    if (regexpr('\\$$', x) > -1) {
         r <- names(get(sub('\\$', '', x)))
         for (i in 1:length(r)) {
             result <- c(result,r[i])
         }    
    }
    else if (regexpr('\\$', x) > -1) {
        r <- names(get(substr(x,0,gregexpr("\\$",x)[[1]][1]-1)))        
        for (i in 1:length(r)) {
            if (regexpr(strsplit(x,'\\$')[[1]][2],r[i]) > -1)
            result <- c(result,r[i])
        }
    }
    else {
        n <- length(search())
        patt <- paste("^", as.character(x), ".*", sep = "")
        for (i in 1:n) {
            result <- c(result, ls(pos = i, all.names = TRUE, 
                pattern = patt))
        }
    }
    sort(result)
}

.refresh <- function() {
  if (!.jgr.works) { cat(".refresh() cannot be used outside JGR.\n"); return(invisible(NULL)) }
	invisible(.jcall("org/rosuda/JGR/JGR","V","setRLibs",as.character(.libPaths())))
	invisible(.jcall("org/rosuda/JGR/JGR","V","setKeyWords",as.character(.refreshKeyWords())))
	invisible(.jcall("org/rosuda/JGR/JGR","V","setObjects",as.character(.refreshObjects())))
	try(.refreshHelpFiles(TRUE),silent=TRUE)
}

.refreshHelpFiles <- function(silent=FALSE) {
	if (.Platform$OS.type == "windows") {
		try(make.packages.html(.libPaths()))
		try(make.search.html(.libPaths()))
		try(fixup.libraries.URLs(.libPaths()))
	}
	else {
    	if (!silent)
		cat("Creating per-session help links...\n")
		.Script("sh", "help-links.sh", paste(tempdir(), paste(.libPaths(), collapse = " ")))
		make.packages.html()
	}
}

# refresh KeyWords (used by SyntaxHighlighting)

.refreshKeyWords <- function() {
    n <- length(search())
    result <- c()
    for (i in 2:n) {
    	result <- c(result,ls(pos=i,all.names=TRUE))
    }
    result
}

# refresh Objects (used by SyntaxHighlighting and ObjectManager)

.refreshObjects <- function() {
	# currently only use the objects we find in pos=1
	result <- c(ls(pos=1,all.names=TRUE))
	result
}

.getModels <- function() {
    objects <- ls(pos=1)
    result <- c();
    if (length(objects) > 0) for (i in 1:length(objects)) {
    	model <- get(objects[i])
        cls <- class(model)
        if (cls[1] == "lm" || cls[1] == "glm") result <- c(result,c(objects[i],cls[1]))
    }
    result
}

.getFunctionsInWS <- function() {
    objects <- ls(pos=1)
    result <- c();
    if (length(objects) > 0) for (i in 1:length(objects)) {
    	cls <- class(get(objects[i]))[1]
        if (cls == "function") result <- c(result,objects[i])
    }
    result
}

.getDataObjects <- function() {
    objects <- ls(pos=1)
    result <- c();
    if (length(objects) > 0) for (i in 1:length(objects)) {
    	d <- get(objects[i])
    	cls <- class(d)[1]
        if (cls == "data.frame" || cls == "table") result <- c(result,objects[i],cls)
    }
    result
}

.getOtherObjects <- function() {
    objects <- ls(pos=1)
    result <- c();
    if (length(objects) > 0) for (i in 1:length(objects)) {
    	if (objects[i] != "last.warning" && objects[i] != "*tmp*") {
	    	cls <- class(get(objects[i]))[1]
   			if (cls != "data.frame" && cls != "table" && cls != "function") result <- c(result,objects[i],cls)
        }
    }
    result
}

.getContent <- function (o, p = NULL)
{
    result <- c()
    if (class(o) == "table")
        o <- dimnames(o)
    if (class(p) == "table") {
        dn <- o
        for (i in 1:length(dn)) {
            try(result <- c(result, dn[i], class((dn[[i]]))[1]),
                silent = TRUE)
        }
    }
    else if (class(o) == "matrix") {
    	colnames <- colnames(o)
    	for (i in 1:dim(o)[2]) {
    		xname <- colnames[i]
    		if (is.null(xname)) xname <- "null"
            try(result <- c(result, xname, class((o[,i]))[1]),
                silent = TRUE)
        }

    }
    else {
        if (mode(o)=="list") {
	        for (i in 1:length(o)) {
		  		xname <- names(o)[i]
				if (is.null(xname)) xname <- "null"
            	try(result <- c(result, xname, class((o[[i]]))[1]), silent = TRUE)
	        }
        }
    }
    result
}

# copy the content of the specified JavaGD device to another device
.jgr.save.JavaGD.as <- function(useDevice, source, file=NULL, usefile=TRUE, ...)
{
  if (usefile && is.null(file)) {
    file<-file.choose(TRUE)
    if (is.null(file)) return(FALSE)
  }
  if (usefile)
    .javaGD.copy.device(source, useDevice, file=file, ...)
  else
    .javaGD.copy.device(source, useDevice, ...)
  invisible(NULL)
}

.generate.run.script <- function(target=NULL) {
  jri.jar <- system.file("jri","JRI.jar",package="rJava")
  if (nchar(jri.jar) == 0) stop("JRI is required but missing! Make sure R was configured with --enable-R-shlib and rJava was compiled with JRI support.")
  run.template <- paste(.jgr.pkg.path,"scripts","run.in",sep=.Platform$file.sep)
  rt <- readLines(run.template)
  settings <- c("R_SHARE_DIR", "R_INCLUDE_DIR", "R_DOC_DIR", "R_LIBS", 
                "R_HOME", "JAVA_HOME", "JAVA_LD_PATH", "JAVA_PROG", "RJAVA")
  sl <- list()
  for (i in settings) sl[[i]] <- Sys.getenv(i)
  if (nchar(sl[['JAVA_PROG']])==0) {
    if (nchar(sl[['JAVA_HOME']])>0) {
      jc <- paste(sl[['JAVA_HOME']],"bin","java",sep=.Platform$file.sep)
      if (file.exists(jc)) sl[['JAVA_PROG']] <- jc
    } else sl[['JAVA_PROG']] <- "java"
  }
  if (nchar(sl[['JAVA_LD_PATH']])==0) {
    sl[['JAVA_LD_PATH']] <- Sys.getenv("R_JAVA_LD_LIBRARY_PATH")
    if (nchar(sl[['JAVA_LD_PATH']])==0) {
      sl[['JAVA_LD_PATH']] <- Sys.getenv("LD_LIBRARY_PATH")
    }
  }
  sl[['JAVA_LD_PATH']] <- paste(sl[['JAVA_LD_PATH']],system.file("jri",package="rJava"),sep=.Platform$path.sep)

  sl[['JGR_JAR']] <- system.file("java","JGR.jar",package="JGR")
  sl[['JRI_JAR']] <- system.file("jri","JRI.jar",package="rJava")
  sl[['IPLOTS_JAR']] <- system.file("java","iplots.jar",package="iplots")
  sl[['RJAVA']] <- system.file(package='rJava')
  ## do all the substitutions
  for (i in names(sl))
    rt <- gsub(paste('@',i,'@',sep=''), sl[[i]], rt)

  ## return back the entire file if there is no target
  if (is.null(target)) return(rt)
  
  ## otherwise save into resulting file
  writeLines(rt, target)
}


JGR <- function(update=FALSE)
  {
    if (!update && .jgr.works && .jcall("org/rosuda/JGR/JGR","Z","isJGRmain")) {
      cat("JGR is already running. If you want to re-install or update JGR, use JGR(update=TRUE).\n")
      return(invisible(FALSE))
    }

    if (update) {
      # Win & OS X lanchers insist on site library
      lt <- paste(R.home(),"library",sep=.Platform$file.sep)
      if (.Platform$OS.type == "unix" && .Platform$pkgType != "mac.binary")
        lt <- .libPaths()[1]
      cran <- getOption("repos")
      if (cran == "@CRAN@") cran <- "http://cran.r-project.org/"
      return (install.packages(c("JGR","rJava","JavaGD","iplots"), lt, c(cran,"http://www.rforge.net/")))
    }
    
    # FIXME: we should invoke a start script ...
    if (.Platform$OS.type == "windows") {
      cat("On Windows JGR must be started using the JGR.exe launcher.\nPlease visit http://www.rosuda.org/JGR/ to download it.\n")
      return(invisible(FALSE))
    }

    if (length(grep("darwin",R.version$os))>0) {
      cat("Please use JGR.app launcher to start JGR.\nIt can be downloaded from http://www.rosuda.org/JGR/\n")
      return(invisible(FALSE))
    }

    runs <- paste(.jgr.pkg.path, "scripts", "run", sep=.Platform$file.sep)
    if (file.exists(runs)) {
      cat("Starting JGR ...\n(You can use",runs,"to start JGR directly)\n")
      system(paste("sh ",runs,"&"))
    } else {
      rs <- .generate.run.script()
      wl <- try(writeLines(rs, runs),silent=TRUE)
      if (inherits(wl,"try-error")) {
        cat("Please consider running JGR() as root to create a start script in",runs,"automatically.\n")
        fn <- tempfile("jgrs")
        wl <- try(writeLines(rs, fn),silent=TRUE)
        if (inherits(wl,"try-error"))
          stop("Cannot create JGR start script. Please run JGR() as root to create a start script ",runs)
        system(paste("chmod a+x '",fn,"'",sep=''))
        cat("Starting JGR ...\n")
        system(paste("sh ",fn,"&"))
        system("sh -c 'sleep 3'") # give the shell some time to read the script
        unlink(fn)
      } else {
        cat("Starting JGR run script. This can be done from the shell as well, just run\n",runs,"\n\n")
        system(paste("chmod a+x '",runs,"'",sep=''))
        system(paste("sh ",runs,"&"))
      }
    }
  }