.packageName <- "GOSim"
.First.lib <- function(lib, pkgname, where) {
  library.dynam(pkgname, pkgname, lib)
  initialize()   
}
# evaluate a given clustering of genes or terms (e.g. terms significantly overrepresented in certain clusters of genes)  by means of the GO gene or term similarities
evaluateClustering<-function(clust, Sim){
	clus<-unique(clust)
	ncl<-length(clus)
	cluststats<-matrix(0,nrow=ncl,ncol=2)
	rownames(cluststats)<-clus
	colnames(cluststats)<-c("median within cluster similarity", "similarity mad")	
	for(c in 1:ncl){
		cl<-which(clust == clus[c])		
		S<-Sim[cl,cl]								
		cluststats[c,1]<-median(as.vector(S))
		cluststats[c,2]<-mad(as.vector(S))
	}
	sil<-silhouette(clust, as.dist(1-Sim))	
	return(list(clusterstats=cluststats,clustersil=sil))
}
# get GO information for a list of genes
getGOInfo<-function(geneIDs){
	if(!exists("GOSimEnv")) initialize()	
	ontology<-get("ontology",env=GOSimEnv)
	gomap<-get("gomap",env=GOSimEnv)
	goids<-as.list(GOTERM)
	goids<-goids[sapply(goids, function(x) Ontology(x) == ontology)]
	anno<-gomap[as.character(geneIDs)]
	goterms<-sapply(anno,function(x) names(x))		
	if(class(goterms)=="list"){		
		goterms<- sapply(goterms,function(x) intersect(names(goids),x))
		info<-sapply(goterms, function(x) goids[x])
	}
	else{		
		goterms<-intersect(goterms, names(goids))
		info<-goids[goterms]
	}	
	return(info)
}

# filter out genes not mapping to the category in question	
filterGO<-function(genelist){	
	if(!exists("GOSimEnv")) initialize()	
	IC<-get("IC", envir=GOSimEnv)
	ids<-names(IC[IC != Inf]) # only consider GO terms with some known annotation   
	gomap<-get("gomap",env=GOSimEnv)
	k<-1
	allgenes<-list()
	for(i in 1:length(genelist)){		
		annoi<-gomap[[as.character(genelist[i])]]						
		annoi<-intersect(names(annoi), as.character(ids))				
		if(length(annoi) > 0){
			allgenes[[k]]<-list(annotation=annoi,genename=as.character(genelist[i]))
			k<-k + 1
		}
	}	
	return(allgenes)		
}

# precompute term similarities for all pairs of GO terms belonging to the annotated genelists x (and y)
precomputeTermSims<-function(x, y=NULL, similarityTerm="JiangConrath", verbose=TRUE){ 	
	if(verbose)
		print("precomputing term similarities ...")	
	gotermsx<-unique(unlist(sapply(x, function(xx) xx$annotation)))
	if(!is.null(y)){      
		gotermsy<-unique(unlist(sapply(y, function(xx) xx$annotation)))		
		STerm<-matrix(0, nrow=length(gotermsx), ncol=length(gotermsy))
		rownames(STerm)=gotermsx
		colnames(STerm)=gotermsy
		for(i in 1:length(gotermsx)){						
			for(j in 1:length(gotermsy)){          
			STerm[i,j]<-calcTermSim(gotermsx[i],gotermsy[j], similarityTerm, verbose)
			}			
		}		
	} else{
		STerm<-matrix(0, nrow=length(gotermsx), ncol=length(gotermsx))
		rownames(STerm)<-gotermsx
		colnames(STerm)<-gotermsx
		for(i in 1:length(gotermsx)){
			STerm[i,i]<-calcTermSim(gotermsx[i], gotermsx[i], similarityTerm, verbose)
			if(i > 1){
				for(j in 1:(i-1)){					
					STerm[i,j]<-calcTermSim(gotermsx[i], gotermsx[j], similarityTerm, verbose)
					STerm[j,i]<-STerm[i,j]
				}
			}
		}
	}	
	return(STerm)
}

# compute gene similarity for a pair of genes having GO terms anno1 and anno2
getGSim<-function(anno1, anno2, similarity="max", similarityTerm="JiangConrath", STerm=NULL, verbose=TRUE){	  
  if(length(anno1) < length(anno2)){
	a1<-anno1
	a2<-anno2
	swap<-FALSE
  }
  else{
	a1<-anno2
	a2<-anno1
	swap<-TRUE
  }		
  if(!is.null(STerm)){ # use precomputed similarity values
	if(!swap)
		ker<-STerm[a1,a2]
	else
		ker<-STerm[a2,a1]		
	if(length(a1) == 1)
		ker<-t(as.matrix(ker))		
	if(is.null(ker) || is.null(nrow(ker))){
		warning(paste("No GO information for",a1,a2,". Similarity set to NaN."))		
		return(NaN)
	}	
	if(nrow(ker) > ncol(ker))
		ker<-t(ker)
  }
  else{ 
	# calculate term similarity
	ker<-matrix(0,nrow=length(a1),ncol=length(a2))	
	for(i in 1:length(a1)){
		for(j in 1:length(a2))
			ker[i,j]<-calcTermSim(a1[i],a2[j], similarityTerm, verbose)		
	}
  }  
  if(length(a1)*length(a2) > 0){
	if(similarity == "OA"){				
		res<-.C("OAWrapper", ker, nrow(ker), ncol(ker), as.integer(1), ret=double(1),PACKAGE="GOSim")$ret
		return(res)
	}
	else if(similarity == "max"){				
		return(max(ker))
	}
	else if(similarity == "mean"){				
		return(mean(ker))
	}  
	else
		stop(paste("getGSim: Unknown gene similarity",similarity,"!"))
  }
  else{	
	warning(paste("No GO information for",a1,a2,". Similarity set to NaN."))		
	return(NaN)
  }
}

# compute GO gene similarity for a list of genes
getGeneSim<-function(genelist, similarity="OA", similarityTerm="JiangConrath", normalization=TRUE, verbose=TRUE){
	genelist <- unique(genelist)
	if(length(genelist) < 2)
		stop("Gene list should contain more than 2 elements!")
	allgenes<-filterGO(genelist)	
	if(length(allgenes) > 1){	
		STerm<-precomputeTermSims(x=allgenes, similarityTerm=similarityTerm, verbose=verbose) # precompute term similarities => speed up!		
		if(verbose)
			print(paste("Calculating similarity matrix with similarity measure",similarity))
		Ker<-matrix(0,nrow=length(allgenes),ncol=length(allgenes))
		colnames(Ker)<-sapply(allgenes,function(x) x$genename)
		rownames(Ker)<-colnames(Ker)
		for(i in 1:length(allgenes)){
			annoi<-(allgenes[[i]]$annotation)		
			Ker[i,i]<-getGSim(annoi,annoi, similarity, similarityTerm, STerm=STerm, verbose)
			if(i > 1){
				for(j in 1:(i-1)){
					annoj<-(allgenes[[j]]$annotation)
	# 			        print(paste(allgenes[[i]]$genename,allgenes[[j]]$genename))
					Ker[i,j]<-getGSim(annoi,annoj, similarity, similarityTerm, STerm=STerm, verbose)
					Ker[j,i]<-Ker[i,j]
				}
			}
		}			
		if(normalization){
			Kd<-sqrt(diag(Ker))
			Ker<-Ker/(Kd%*%t(Kd))
		}			
	}
	else{
		if(length(allgenes) == 0)
			stop("No gene has GO information!")					
		else if(length(allgenes) == 1)
			stop(paste("Only gene",allgenes," has GO information!"))					
	}
	return(Ker)
}

# compute GO gene feature representation
getGeneFeaturesPrototypes<-function(genelist, prototypes=NULL, similarity="max", similarityTerm="JiangConrath", pca=TRUE, normalization=TRUE, verbose=TRUE){
	genelist<-unique(genelist)
	if(is.null(prototypes))
		prototypes<-selectPrototypes(verbose=verbose)
	allgenes<-filterGO(genelist)	
	proto<-filterGO(prototypes)
	if(length(proto) == 0)
		stop("getGeneFeaturesPrototypes: Number of prototypes equals zero after filtering!")	
	STerm<-precomputeTermSims(x=allgenes,y=proto,similarityTerm=similarityTerm,verbose=verbose)  # precompute term similarities => speed up!
	if(verbose)
		print(paste("calculating feature vectors with",length(proto),"prototypes"))
	PHI<-matrix(0,nrow=length(allgenes),ncol=length(proto))
	for(i in 1:length(allgenes)){		
		for(j in 1:length(proto)){
			annoi<-(allgenes[[i]]$annotation)		
			annoj<-(proto[[j]]$annotation)			
			PHI[i,j]<-getGSim(annoi,annoj, similarity, similarityTerm, STerm=STerm, verbose)
		}
	}			
	rownames(PHI)<-sapply(allgenes,function(x) x$genename)
	colnames(PHI)<-sapply(proto,function(x) x$genename)	
	if(pca){    
		pcares<-selectPrototypes(method="pca",data=PHI,verbose=verbose)		
		PHI<-pcares$features
		proto<-pcares$pcs    
	}
	if(normalization)
		PHI<-t(apply(PHI,1,function(x) return(x/(norm(x)+1e-10))))		  
	return(list(features=PHI,prototypes=proto))
}

# compute GO gene similarity using the feature representation
getGeneSimPrototypes<-function(genelist, prototypes=NULL, similarity="max", similarityTerm="JiangConrath", pca=TRUE, normalization=TRUE, verbose=TRUE){
	genelist<-unique(genelist)	
	if(length(genelist) < 2)
		stop("Gene list should contain more than 2 elements!")
	res<-getGeneFeaturesPrototypes(genelist, prototypes, similarity, similarityTerm, pca, normalization, verbose)
	PHI<-res$features		
	Ker<-PHI%*%t(PHI)
	if(normalization)
		Ker<-(Ker + 1)/2 # scale to [0,1]
	return(list(similarity=Ker,prototypes=res$prototypes,features=res$features))
}

# method to a) select prototype genes b) to perform subselection of prototypes via i) PCA ii) clustering
selectPrototypes<-function(n=250, method="frequency", data=NULL, verbose=TRUE){
	if(!exists("GOSimEnv")) initialize()	
	ontology<-get("ontology",env=GOSimEnv)  
	if(method == "frequency"){
		if(verbose)
			print("Automatic determination of prototypes using most frequent genes ...")
		locus<-as.list(GOENTREZID)
		goids<-as.list(GOTERM)
		goids<-goids[sapply(goids, function(x) Ontology(x) == ontology)]		
		locusnames<-intersect(names(locus),names(goids))
		locus<-locus[locusnames]
		lt<-table(unlist(locus))
		res<-sort(lt,decreasing=TRUE)
		prototypes<-names(res)[1:n]
		return(prototypes)
	}
	else if(method == "random"){
		if(verbose)		
			print("Automatic determination of prototypes using random genes ...")
		locus<-as.list(GOENTREZID)
		goids<-as.list(GOTERM)
		goids<-goids[sapply(goids, function(x) Ontology(x) == ontology)]		
		locusnames<-intersect(names(locus),names(goids))
		locus<-locus[locusnames]
		lt<-names(table(unlist(locus)))
		set.seed(0)
		ridx<-round(runif(n,min=1,max=length(lt)))
		prototypes<-lt[ridx]		
		return(prototypes)
	}
	else if(method == "pca"){
		if(is.null(data))
			stop("You need to specify a data matrix with feature vectors")
		pcares<-pca(data)
		if(verbose)
			print(paste("PCA: dimension reduced to",ncol(pcares$features),"principal components (95% total variance explained)"))
		return(pcares)
	}
	else if(method == "clustering"){    
		if(is.null(data))
			stop("You need to specify a data matrix with feature vectors")
		if(verbose)
			print("Clustering feature vectors ...")
		res<-Mclust(t(data),2,n)
		return(res$mu)
	}
	else
	stop(paste("selectPrototypes: Unknown method",method,"!"))
}

initialize<-function(){
	print("initializing GOSim package ...")
	assign("GOSimEnv",new.env(parent=globalenv()),envir=.GlobalEnv)  
  	setEvidenceLevel("all")
  	setOntology("BP")
  	print("finished.")
}

getOffsprings<-function(){
  if(!exists("GOSimEnv")) initialize()
  ontology<-get("ontology",envir=GOSimEnv)
  if(ontology == "BP")
    res<-as.list(GOBPOFFSPRING)
  else if(ontology == "MF")
    res<-as.list(GOMFOFFSPRING)
  else if(ontology == "CC")
    res<-as.list(GOCCOFFSPRING)
  else
    stop(paste("ontology", ontology, "not known!"))
  return(res)
}

getAncestors<-function(){
  if(!exists("GOSimEnv")) initialize()
  ontology<-get("ontology",envir=GOSimEnv)
  if(ontology == "BP")
    res<-as.list(GOBPANCESTOR)
  else if(ontology == "MF")
    res<-as.list(GOMFANCESTOR)
  else if(ontology == "CC")
    res<-as.list(GOCCANCESTOR)
  else
    stop(paste("ontology", ontology, "not known!"))
  return(res)
}

getParents<-function(){
  if(!exists("GOSimEnv")) initialize()
  ontology<-get("ontology",envir=GOSimEnv)
  if(ontology == "BP")
    res<-as.list(GOBPPARENTS)
  else if(ontology == "MF")
    res<-as.list(GOMFPARENTS)
  else if(ontology == "CC")
    res<-as.list(GOCCPARENTS)
  else
    stop(paste("ontology", ontology, "not known!"))
  return(res)
}

getChildren<-function(){
  if(!exists("GOSimEnv")) initialize()
  ontology<-get("ontology",envir=GOSimEnv)
  if(ontology == "BP")
    res<-as.list(GOBPCHILDREN)
  else if(ontology == "MF")
    res<-as.list(GOMFCHILDREN)
  else if(ontology == "CC")
    res<-as.list(GOCCCHILDREN)
  else
    stop(paste("ontology", ontology, "not known!"))
  return(res)
}

# filter GO mapping for given evidence levels
setEvidenceLevel<-function(evidences="all"){	
        if(!exists("GOSimEnv")) initialize()	
	assign("evidences", evidences, envir=GOSimEnv)	
	gomap<-as.list(GOENTREZID2GO)	
	if((length(evidences) > 1) || (evidences!="all")){
		gomap<-sapply(gomap,function(x) sapply(x,function(y) y$Evidence %in% evidences))
		gomap<-sapply(gomap, function(x) x[which(x)])
		gomap<-gomap[sapply(gomap,function(x) length(x) > 0)]
	}
	assign("gomap", gomap, envir=GOSimEnv)
}

setOntology<-function(ont="BP"){
	if(!exists("GOSimEnv")) initialize()
	assign("ontology", ont, envir=GOSimEnv)		
	ontology<-get("ontology",envir=GOSimEnv)
	evidences<-get("evidences",envir=GOSimEnv)	
	data(list=paste("ICs",ontology,paste(evidences,collapse="_"),sep=""),envir=GOSimEnv)	
	IC<-get("IC",envir=GOSimEnv)
	IC<-IC/max(IC[IC!=Inf])
	IC["all"]=0
	assign("IC", IC, envir=GOSimEnv)
 	assign("ancestor", getAncestors(), envir=GOSimEnv) 	
 	assign("children", getChildren(), envir=GOSimEnv)
 	assign("parents", getParents(), envir=GOSimEnv) 
 	children<-get("children",envir=GOSimEnv) 	
 	parents<-get("parents",envir=GOSimEnv) 	
 	assign("nchildren", sapply(children,length) , envir=GOSimEnv)
 	assign("nparents", sapply(parents,length), envir=GOSimEnv)
 	nchildren<-get("nchildren",envir=GOSimEnv) 	
 	nparents<-get("nparents",envir=GOSimEnv) 	
 	assign("Eavg", (sum(nchildren) + sum(nparents))/ length(union(names(nchildren), names(nparents))), envir<-GOSimEnv)
  	assign("alphaParam", 0.5, envir=GOSimEnv)
  	assign("betaParam", 0.5, envir=GOSimEnv)  	    	
}
norm = function(x,p=2) {
  return(dist(rbind(x,double(length(x))),method="minkowski",p=p))
}
#  perform PCA on data matrix X
# n<-number of PCs to extract (if not provided, use as many PCs as explain 95% of overall variance)
pca<-function(X, n=NULL){
  res<-eigen(cov(X), symmetric<-TRUE)
  lam<-res$values
  V<-res$vectors
  if(is.null(n)){
    n<-min(which(cumsum(lam)/sum(lam) >= 0.95))
    res<-sort(lam, index.return=TRUE, decreasing=TRUE)
  }
  V<-V[,res$ix[1:n]]
  return(list(features=X%*%V,pcs=V,lambda=lam[1:n]))
}
setEnrichmentFactors<-function(alpha=0.5, beta=0.5){
	if(!exists("GOSimEnv")) initialize()
	assign("alphaParam",alpha, envir=GOSimEnv)
	assign("betaParam",beta, envir=GOSimEnv)
}

getGOGraph<-function(term){
	if(!exists("GOSimEnv")) initialize()
	ontology<-get("ontology",env=GOSimEnv)
	if(ontology == "BP")
		G<-GOGraph(term,GOBPPARENTS)
	else if(ontology == "MF")
		G<-GOGraph(term,GOMFPARENTS)
	else if(ontology == "CC")
		G<-GOGraph(term,GOCCPARENTS)
	else
		stop(paste("ontology", ontology, "not known!"))
	return(G)
}

calcICs<-function(){
	if(!exists("GOSimEnv")) initialize()
	evidences<-get("evidences", envir=GOSimEnv)
	ontology<-get("ontology",envir=GOSimEnv)
	print(paste("calculating information contents for ontology", ontology, "using evidence codes", paste(evidences,collapse=", "), "..."))	
	ids<-as.list(GOTERM)
	ids<-names(ids[sapply(ids, function(x) Ontology(x) == ontology)])
	offspring<-getOffsprings()	
	gomap<-get("gomap",env=GOSimEnv)	
	goterms<-unlist(sapply(gomap, function(x) names(x))) # all GO terms appearing in an annotation
	goterms<-goterms[goterms %in% ids] # this is to ensure that we only get GO terms mapping to the given ontology
	tab<-table(goterms)
	na<-names(tab)			
	s<-setdiff(ids, na)  #ensure that GO terms NOT appearing in the annotation have 0 frequency
	m<-double(length(s))
	names(m)<-s
	tab<-as.vector(tab)
	names(tab)<-na
	tab<-c(tab,m)	
	ta<-sapply(ids,function(x){ t=tab[unlist(offspring[x])]; tab[x]+sum(t[!is.na(t)])})		
	names(ta)<-ids
	IC<- -log(ta/sum(ta))	
	save(IC,file=paste("ICs",ontology,paste(evidences,collapse="_"),".rda",sep=""))
	print("done")			
}

getMinimumSubsumer<-function(term1, term2){	
	if(!exists("GOSimEnv")) initialize()
	ancestor<-get("ancestor",envir=GOSimEnv)
	if(term1 == term2){
		ms<-term1	
		return(ms)
	}
	an1<-unlist(ancestor[names(ancestor) == term1])
	an2<-unlist(ancestor[names(ancestor) == term2])
	case1<-which(an2 == term1)  # term1 is the ms of term2
	case2<-which(an1 == term2) # term2 is the ms of term1	  
	if(length(case1) > 0){
		ms<-term1	
	} else if(length(case2) > 0) {
		ms<-term2	
	} else {
		# find common ancestor with maximal information content
		anall<-intersect(an1, an2) 
		IC<-get("IC", envir=GOSimEnv)			
		ms<-anall[which.max(IC[anall])]
	}		
	return(ms)
}

# get FuSSiMeg density factor
getDensityFactor<-function(term){
	if(!exists("GOSimEnv")) initialize()
	nchildren<-get("nchildren",env=GOSimEnv)
	nparents<-get("nparents",env=GOSimEnv)
	e<-nchildren[term] + nparents[term]	  
	betaParam<-get("betaParam",envir=GOSimEnv)
	E<-(1-betaParam)*get("Eavg",env=GOSimEnv)/e + betaParam
	return(E)
}

# get FuSsiMeg depth factor
getDepthFactor<-function(term,G){	
	if(!exists("GOSimEnv")) initialize()	
	d<-sp.between(G,term,"all")[[1]]$length  	
    	D<-((d+1)/d)^get("alphaParam",envir=GOSimEnv)
    	return(D)
}

# compute FuSSiMeg enriched term similarity
getEnrichedSim<-function(term1, term2){   
    if(!exists("GOSimEnv")) initialize() 
    ms<-getMinimumSubsumer(term1,term2)
    IC<-get("IC", envir=GOSimEnv)
    if(term1 != term2){    	    	
    	G<-getGOGraph(c(term1,term2))
        if(term1 != ms){
		path1=sp.between(G,term1,ms)[[1]]$path # path to ms                
		len<-length(path1)
		delta1<-sum(sapply(path1[2:len],getDepthFactor,G)*sapply(path1[2:len],getDensityFactor)*(-diff(IC[path1])))
	}
	else
		delta1<-0
	if(term2 != ms){
		path2<-sp.between(G,term2,ms)[[1]]$path # path to ms    	
		len<-length(path2)
		delta2<-sum(sapply(path2[2:len],getDepthFactor,G)*sapply(path2[2:len],getDensityFactor)*(-diff(IC[path2])))
	}
	else
		delta2<-0
	delta<-delta1 + delta2		
	sim<-1 - min(1, delta)
    }
    else
    	sim<-1 
    sim<-sim * IC[term1] * IC[term2]  # correction given in equation (11) of the FuSSiMeg paper
    names(sim)<-c()   
    return(sim)
}

# get GraSM disjunctive ancestors of a set of terms with ancestors an
getDisjAnc<-function(term, an){		
	G<-getGOGraph(term)	
	disan<-matrix(0,ncol=2,nrow=0)
	for(n1 in 1:length(an)){
		if(n1 > 1){
			for(n2 in 1:(n1-1)){
				if(!separates(term, an[n1], an[n2], G) && !separates(term, an[n2], an[n1], G))
					disan<-rbind(disan,c(an[n1], an[n2]))
			}
		}
	}
	return(disan)
}

# get GraSM common disjunctive ancestors of two terms
getDisjCommAnc<-function(term1, term2){
	if(!exists("GOSimEnv")) initialize()
	ancestor<-get("ancestor",envir=GOSimEnv)
	IC<-get("IC", envir=GOSimEnv)
	if(term1 == term2){
		return(term1)
	}
	else{
		an1<-unlist(ancestor[names(ancestor) == term1])
		an2<-unlist(ancestor[names(ancestor) == term2])
		case1<-which(an2 == term1)  # term1 is an ancestor of term2
		case2<-which(an1 == term2) # term2 is an ancestor of term1
		if(length(case1) > 0){
			ancommon<-an1
			andisj<-getDisjAnc(term1, an1)
		}
		else if(length(case2) > 0){			
			ancommon<-an2
			andisj<-getDisjAnc(term2, an2)			
		}
		else{
			ancommon<-intersect(an1,an2)
			andisj<-getDisjAnc(c(term1,term2), ancommon) # we only need to calculate the disjunctives among the common ancestors!
# 			andisj<-unique(rbind(getDisjAnc(term1,an1), getDisjAnc(term2,an2)))			
		}		
		djca<-c()
		cond1<-sapply(ancommon, function(x) setdiff(ancommon[which(IC[ancommon] >= IC[x])],x)) # which common ancestors are more informative than a_i?
		if(length(cond1) > 0){ # look for those that are disjunctive
			names(cond1)<-ancommon					
			for(i in 1:length(cond1)){
				res<-sapply(cond1[i][[1]],function(x) any(andisj[,1] == names(cond1[i]) & andisj[,2] == x) | any(andisj[,2] == names(cond1[i]) & andisj[,1] == x))				
				if(all(res))
					djca<-c(djca, names(cond1[i]))
			}
			djca= unique(djca)			
		}	
		if(length(djca)==0)
			djca<-ancommon[which.max(IC[ancommon])]# take minimum subsumer otherwise		
		return(djca)		
	}	
}
	
# get GraSM similarity of common disjunctive ancestors of two terms
getDisjCommAncSim<-function(term1, term2, method="JiangConrath"){
	if(!exists("GOSimEnv")) initialize()
	IC<-get("IC", envir=GOSimEnv)
	djca<-getDisjCommAnc(term1, term2)	
	ICdjca<-IC[djca]	
	ICdjca<-ICdjca[!is.na(ICdjca)]							
	ICshare<-mean(ICdjca)		
	if(method == "JiangConrath")
		return(1-min(1,-2*ICshare + IC[term1] + IC[term2]))
	else if(method == "Resnik")
		return(ICshare)
	else if(method == "Lin")
		return(2*ICshare/(IC[term1]+IC[term2]))
	else
		stop(paste("getDisjCommAnc: Unknown term similarity",method))
}

# basic term similarity for index i and j in GOIDs ids
calcTermSim<-function(ids, i, j, method="JiangConrath"){	
  	return(calcTermSim(ids[i],ids[j], method))
}

# basic term similarity between term1 and term2
calcTermSim<-function(term1, term2, method="JiangConrath", verbose=TRUE){
	if(!exists("GOSimEnv")) initialize()
	IC<-get("IC", envir=GOSimEnv)
	if(verbose)
		print(paste("Terms:",term1,",",term2,"( method:",method,")"))	
	if(method== "Resnik")
		return(IC[getMinimumSubsumer(term1,term2)])   
	else if(method == "JiangConrath")
		return(1 - min(1, -2*IC[getMinimumSubsumer(term1,term2)] + IC[term1] + IC[term2]) )	
	else if(method == "Lin")
		return(2*IC[getMinimumSubsumer(term1,term2)]/(IC[term1]+IC[term2]))	
	else if(method== "CoutoEnriched")
		return(getEnrichedSim(term1, term2))
	else if(method == "CoutoResnik")  
		return(getDisjCommAncSim(term1,term2, "Resnik"))
	else if(method == "CoutoJiangConrath")  
		return(getDisjCommAncSim(term1,term2, "JiangConrath"))
	else if(method == "CoutoLin")  
		return(getDisjCommAncSim(term1,term2, "Lin"))
	else
		stop(paste("calcTermSim: Unknown term similarity",method))
}

# calculate term similarities for a list of GO terms
getTermSim<-function(termlist, method="JiangConrath", verbose=TRUE){
	S<-matrix(0,nrow=length(termlist),ncol=length(termlist))
	colnames(S)<-termlist
	rownames(S)<-termlist
	for(i in 1:length(termlist)){
		S[i,i]<-1
		if(i > 1){
			for(j in 1:(i-1)){
				S[i,j]<-calcTermSim(termlist[i],termlist[j], method, verbose)
				S[j,i]<-S[i,j]
			}
		}
	}
	return(S)
}
