library(XML)
library(R2HTML)
library(snow)

##################################################################################
#Function Name: apLCMS.align 
#Description: Call apLCMS function, cdf.to.ftr, at different parameter settings
##cdfloc: The folder where all CDF files to be processed are located. For example "C:/CDF/"
##apLCMS.outloc: The folder where alignment output will be written. For example "C:/CDFoutput/"
##min.run.list: List of values for min.run parameter, eg: c(3,6) would run the cdf.to.ftr function at min.run=3 and min.run=6
##min.pres.list: List of values min.pres, eg: c(0.3,0.8) would run the cdf.to.ftr function at min.run=3 and min.run=6
##minexp: If a feature is to be included in the final feature table, it must be present in at least this number of samples, eg: 2
##subs: If not all the CDF files in the folder are to be processed, the user can define a subset using this parameter. For example, subs=15:30, or subs=c(2,4,6,8)
##run.order.file: Name of a tab-delimited file that includes sample names sorted by the order in which they were run (sample names must match the CDF file names)


apLCMS.align<-function(cdfloc, apLCMS.outloc,min.run.list=c(3), min.pres.list=c(0.3,0.8), minexp=2, mztol=0.001, alignmztol=NA, numnodes=NA, run.order.file=NA,subs=NA)
{
        setwd(cdfloc)
	  cdf.files=list.files(cdfloc,".cdf")
	  cdf.files=tolower(cdf.files)
        if(is.na(subs[1])==FALSE)
        {
                numsamp=length(subs)
		    cdf.files=cdf.files[subs]
		    print(cdf.files)
        }
        else
        {
                
                numsamp=length(cdf.files)
        }
        for(r in 1:length(min.run.list))
        {
		    runval=min.run.list[r]
                for(p in 1:length(min.pres.list))
                {
                        features<-new("list")
                        
                        presval=min.pres.list[p]
			
                        if(is.na(subs[1])==FALSE)
                        {
					  if(is.na(numnodes)==FALSE)
					  {
						print(paste("minexp is ", minexp))
						print(paste("minrun is ", runval))
						print(paste("numnodes is ",numnodes))
						#aligned<-cdf.to.ftr(cdfloc,subs=subs,min.exp=minexp,min.run=runval,min.pres=presval, mz.tol=mztol, align.mz.tol=alignmztol, n.nodes=numnodes)
						if(is.na(mztol)==FALSE && is.na(alignmztol)==FALSE)
					  	{
							aligned<-cdf.to.ftr(cdfloc,subs=subs,min.exp=minexp,min.run=runval,min.pres=presval,mz.tol=mztol, align.mz.tol=alignmztol, n.nodes=numnodes)
						}
						else
						{
							aligned<-cdf.to.ftr(cdfloc,subs=subs,min.exp=minexp,min.run=runval,min.pres=presval, n.nodes=numnodes)
						}

					  }
					  else
					  {
						if(is.na(mztol)==FALSE && is.na(alignmztol)==FALSE)
					  	{
							aligned<-cdf.to.ftr(cdfloc,subs=subs,min.exp=minexp,min.run=runval,min.pres=presval,mz.tol=mztol, align.mz.tol=alignmztol)
						}
						else
						{
							aligned<-cdf.to.ftr(cdfloc,subs=subs,min.exp=minexp,min.run=runval,min.pres=presval)
						}
				        }
                        }
                        else
                        {
					  if(is.na(numnodes)==FALSE)
					  {
						if(is.na(mztol)==FALSE && is.na(alignmztol)==FALSE)
					  	{
							aligned<-cdf.to.ftr(cdfloc,min.exp=minexp,min.run=runval,min.pres=presval,mz.tol=mztol, align.mz.tol=alignmztol, n.nodes=numnodes)
						}
						else
						{
							aligned<-cdf.to.ftr(cdfloc,min.exp=minexp,min.run=runval,min.pres=presval, n.nodes=numnodes)
						}

												
					  }
					  else
					  {
						
					  	if(is.na(mztol)==FALSE && is.na(alignmztol)==FALSE)
					  	{
							aligned<-cdf.to.ftr(cdfloc,min.exp=minexp,min.run=runval,min.pres=presval,mz.tol=mztol, align.mz.tol=alignmztol)
						}
						else
						{
							aligned<-cdf.to.ftr(cdfloc,min.exp=minexp,min.run=runval,min.pres=presval)
						}

					  }                        
                        }
	
			fname<-paste(apLCMS.outloc, "/apLCMS_aligned", "_pres", presval, "_run", runval,"_", minexp, "exppostrecovery.txt", sep="")
                        finalfeatmat=aligned$final.ftrs

                        cnames<-colnames(finalfeatmat[,-c(1:4)])
                        cnames<-tolower(cnames)
                        cnames<-gsub(".cdf", "", cnames)

                        if(is.na(run.order.file)==FALSE)
                        {
                                fileorder=read.table(run.order.file, header=FALSE)
                                fileorder=apply(fileorder,1,tolower)
				cnames=tolower(cnames)
                                ordlist=sapply(1:length(fileorder),function(i){which(cnames==fileorder[i])})
                                ordlist=unlist(ordlist)
                                ordlist=ordlist+4
                                finalfeatmat=finalfeatmat[,c(1:4,ordlist)]
                        }
                        write.table(finalfeatmat,fname,sep="\t",col.name=T,row.names=F)
			fname<-paste(apLCMS.outloc, "/apLCMS_aligned", "_pres",  presval, "_run", runval,"_", minexp, "exppostrecovery.Rda", sep="")
			save(aligned,file=fname)
                }
        }
}


#################################################################################
##Function: XCMS.align
##Description: Runs XCMS wrapper function, cdf.to.ftr, at different parameter settings
##cdfloc: The folder where all CDF files to be processed are located. For example "C:/CDF/"
##XCMS.outloc: The folder where alignment output will be written. For example "C:/CDFoutput/"
##step.list: list containing values for the step size
##mz.diff.list: list containing values for the minimum difference for features with
#	  retention time overlap
##sn.thresh.list: list containing values for signal to noise ratio cutoff variable
##max.list: list containing values for maxnimum number of peaks per EIC variable
##bw.val: bandwidth value
##minfrac.val:  minimum fraction of samples necessary in at least one of the sample
#         groups for it to be a valid group
##minsamp.val: minimum number of samples necessary in at least one of the sample
#          groups for it to be a valid group
##mzwid.val: width of overlapping m/z slices to use for creating peak density chromatograms
#         and grouping peaks across samples
##max.val: maximum number of groups to identify in a single m/z slice
##sleep.val: seconds to pause between plotting successive steps of the
#          peak grouping algorithm. peaks are plotted as points showing
#          relative intensity. identified groups are flanked by dotted
#          vertical lines.
#
##subs: If not all the CDF files in the folder are to be processed, the user can define
# a subset using this parameter. For example, subs=15:30, or subs=c(2,4,6,8)
##run.order.file: Name of a tab-delimited file that includes sample names sorted by the
# order in which they were run (sample names must match the CDF file names)
###################################################################################
XCMS.align<-function(cdfloc, XCMS.outloc,step.list=c(0.001), mz.diff.list=c(0.1), sn.thresh.list=c(3), max.list=c(5), bw.val=10, minfrac.val=0.5, minsamp.val=2, mzwid.val=0.25, sleep.val=0, run.order.file=NA,subs=NA)
{

        setwd(cdfloc)
        cdf_files=list.files(cdfloc,".cdf")
        if(is.na(subs[1])==FALSE)
        {
                cdf_files=cdf_files[subs]
                numsamp=length(subs)


        }
        else
        {

                numsamp=length(cdf_files)
        }

        for(t in sn.thresh.list)
        {
                for(s in step.list)
                {
                        for(m in mz.diff.list)
                        {
                                for(maxl in max.list)
                                {
                                        xset=xcmsSet(cdf_files, step=s,snthresh=t,mzdiff=m,max=maxl)

                                        xset<-group(xset)
                                        xset2 <- retcor(xset, family = "symmetric", plottype = "mdevden")

                                        ###  Group peaks together across samples, set bandwitdh, change important m/z parameters here
                                        ###  Syntax: group(object, bw = 30, minfrac = 0.5, minsamp= 1,  mzwid = 0.25, max = 5, sleep = 0)
                                        xset2 <- group.density(xset2, bw=bw.val, minfrac=minfrac.val, minsamp=minsamp.val,  mzwid=mzwid.val, max=maxl, sleep=sleep.val)

                                        #xset3=fillPeaks(xset2)
       					xset3=suppressWarnings(fillPeaks(xset2))                                 
					gt=groups(xset3)

					print("Getting sample intensities")
                                        finalfeatmat={}
                                                                              
					
					if (dim(xset3@groups)[1] > 0) {
					     groupmat <- groups(xset3)
					     finalfeatmat <- as.data.frame(cbind(groupmat,groupval(xset3, "medret","into")),row.names = NULL)
					     
					  } else{
						if (length(xset3@sampnames) == 1)
						{
							finalfeatmat  <- xset3@peaks
						}else 
						{
							stop ('First argument must be a xcmsSet with group information or contain only one sample.')
						 }
					}


                                        fname=paste(XCMS.outloc, "/XCMS_aligned","_thresh", t,"_step", s, "_mzdiff", m,"_max",maxl,".txt", sep="")
                                        cnames=colnames(finalfeatmat)
                                        cnames[1]="mz"
                                        cnames[4]="time"
                                        colnames(finalfeatmat)=c(cnames[1:8],cdf_files)
                                        cnames<-tolower(cnames)
                                        cnames<-gsub(".cdf", "", cnames)

                                        if(is.na(run.order.file)==FALSE)
                                        {
                                                fileorder=read.table(run.order.file, header=FALSE)
                                                fileorder=apply(fileorder,1,tolower)
                                                ordlist=sapply(1:length(fileorder),function(i){which(cnames==fileorder[i])})
                                                ordlist=unlist(ordlist)
                                                ordlist=ordlist+4
                                                finalfeatmat=finalfeatmat[,c(1:8,ordlist)]
                                        }

                                        write.table(finalfeatmat,file=fname,sep="\t",row.names=FALSE)
                                }
                        }
                }
        }
}


#################################################################
#Function: evaluate.Samples
#Description: Evaluate sample consistency based on Pearson Correlation
#curdata: feature alignment output matrix from apLCMS or XCMS with
# 	  intensities
#numreplicates: number of replicates per sample
#alignment.tool: name of the feature alignment tool eg: "apLCMS" or "XCMS"
##################################################################
evaluate.Samples<-function(curdata, numreplicates, alignment.tool, cormethod="pearson")
{

        if(alignment.tool=="apLCMS")
        {
              col_end=4
        }
        else
        {
              if(alignment.tool=="XCMS")
              {
                    col_end=8
              }
              else
              {
                    stop(paste("Invalid value for alignment.tool. Please use either \"apLCMS\" or \"XCMS\"", sep=""))
              }
        }
       
	rnames<-colnames(curdata)
        rnames<-rnames[-c(1:col_end)]
        rnames=rnames[seq(1,length(rnames),numreplicates)]
        finalmat={}
 
        curdata_int=curdata[,-c(1:col_end)]
        numsamp=dim(curdata_int)[2]
       
        for(samp in seq(1,numsamp,numreplicates))
        {
                samp_rep_last=samp+numreplicates-1
                subdata=curdata_int[,samp:samp_rep_last]
                if(FALSE){
		missing.val.index<-apply(subdata,1,function(x){which(x==0)})
		bad.features<-{}
		for(m in 1:length(missing.val.index)){
			bad.features<-rbind(bad.features,missing.val.index)
		}
		if(length(missing.val.index)>0){
			subdata<-subdata[-bad.features,]
		}
		}
		rmat=cor(subdata, method=cormethod)
		
                rmat_upper=rmat[upper.tri(rmat)]
		
		if(numreplicates==2)
		{
			finalmat<-rbind(finalmat, mean(rmat_upper))
		}
		else
		{
			if(numreplicates>2)
			{
				rmat_vec=c(rmat_upper,mean(rmat_upper))
				finalmat<-rbind(finalmat,rmat_vec)
			}
			
		}
		
	}
	if(numreplicates==2)
		{
			colnames(finalmat)<-c(paste(cormethod,"Correlation",sep=""))
			cnames<-"PearsonCorrelation"
		}
		else
		{
			if(numreplicates>2)
			{
	
				cnames={}
				for(repnum in seq(1,numreplicates-1,1))
				{
					for(r1 in seq(repnum+1,numreplicates,1))
					{
						cnames<-c(cnames,paste("rep",repnum,"vs","rep",r1,sep=""))
					}
				}	
				cnames<-c(cnames,paste("mean","Correlation",sep=""))
			}
		}
	colnames(finalmat)<-cnames
        rownames(finalmat)<-rnames
        return(finalmat)
}

#################################################################
#Function: evaluate.Features
#Description: Evaluate feature consistency based on PID or CV
#curdata: feature alignment output matrix from apLCMS or XCMS with
#         intensities
#numreplicates: number of replicates per sample
#alignment.tool: name of the feature alignment tool eg: "apLCMS" or "XCMS"
##################################################################
evaluate.Features<-function(curdata,numreplicates,alignment.tool,  impute.bool)
{
        if(numreplicates==2)
        {
		print("**calculating percent intensity difference**")
                eval.feat.results<-getPID(curdata, alignment.tool)
        }
        else
        {
                  if(numreplicates>2)
                  {
			  print("**calculating CV**")
                          eval.feat.results<-getCVreplicates(curdata, alignment.tool, numreplicates,impute.bool)
                  }
        
        }
	return(eval.feat.results)
}

#################################################################
#Function: getPID
#Description: Evaluate feature consistency based on PID
#curdata: feature alignment output matrix from apLCMS or XCMS with
#         intensities
#alignment.tool: name of the feature alignment tool eg: "apLCMS" or "XCMS"
##################################################################
getPID<-function(curdata, alignment.tool)
{
        mean_replicate_difference<-{}
        sd_range_duplicate_pairs<-{}
        if(alignment.tool=="apLCMS")
        {
              col_end=4
        }
        else
        {
              if(alignment.tool=="XCMS")
              {
                    col_end=8
              }
              else
              {
                    stop(paste("Invalid value for alignment.tool. Please use either \"apLCMS\" or \"XCMS\"", sep=""))
              }
        }
        curdata_mz_rt_info=curdata[,c(1:col_end)]
        curdata=curdata[,-c(1:col_end)]
        numfeats=dim(curdata)[1]
        numsamp=dim(curdata)[2]
        rnames<-colnames(curdata)
        rnames<-gsub(".cdf", "", rnames, ignore.case=TRUE)
        quantcolnames=c("min", "first_quartile", "median", "mean", "third_quartile", "max")
	
        resvec_1<-lapply(1:numfeats,function(r)
        {
                newrow={}
                finalmat={}
		no_value=0
                for(samp in seq(1,(numsamp),2))
                {
                        i=samp
                        j=i+1
                        int1=curdata[r,i]
                        int2=curdata[r,j]
			
			curdata_int=curdata[r,c(i:j)]
                        check_zeros=which(curdata_int==0)

                        
			 if(length(check_zeros)>0)
                        {
                                                 
                                replicate_diff<-NA
				no_value<-no_value+1
                        }
                        else
                        {
                                #calculate PID
                                replicate_diff<-100*(abs(int1-int2)/mean(c(int1,int2)))
                        }
                        newrow<-cbind(newrow,replicate_diff)
                }

                #get indices of the PIDs that are NA
                na_ind=which(is.na(newrow)==TRUE)

                #get quantile summary of the percent intensity difference (PID) vector
                #using only the non-NA values
                if(length(na_ind)>0)
                {
                        sumrow=summary(as.vector(newrow[-na_ind]))
                }
                else
                {
                        sumrow=summary(as.vector(newrow))
                }

                #if quantile values are set  to NA
                if(length(sumrow)<6)
                {
                        for(i in 1:6)
                        {
                                sumrow[i]=200
                        }
                }
                names(sumrow)=quantcolnames
                finalmat<-rbind(finalmat, unlist(sumrow))
                return(finalmat)
        })
        final_set={}
        for(i in 1:length(resvec_1)){
                if(length(resvec_1[[i]])>1)
                {
                        final_set<-rbind(final_set,resvec_1[[i]])
                }
        }

        final_set<-as.data.frame(final_set)
        rownames(final_set)=NULL
	final_set<-apply(final_set,2,as.numeric)
	final_set<-as.data.frame(final_set)
        return(final_set)
}


#################################################################
#Function: getCVreplicates
#Description: Evaluate feature consistency based on coefficient of
# 	   Variation
#curdata: feature alignment output matrix from apLCMS or XCMS with
#         intensities
#numreplicates: number of replicates per sample
#alignment.tool: name of the feature alignment tool eg: "apLCMS" or "XCMS"
##################################################################
getCVreplicates<-function(curdata,alignment.tool,numreplicates, impute.bool)
{
        mean_replicate_difference<-{}
        sd_range_duplicate_pairs<-{}
	
        if(alignment.tool=="apLCMS")
        {
              col_end=4
        }
        else
        {
              if(alignment.tool=="XCMS")
              {
                    col_end=8
              }
              else
              {
                    stop(paste("Invalid value for alignment.tool. Please use either \"apLCMS\" or \"XCMS\"", sep=""))
              }
        }
        
        curdata_mz_rt_info=curdata[,c(1:col_end)]
        curdata=curdata[,-c(1:col_end)]
	
	#curdata<-curdata[1:10,]
        numfeats=dim(curdata)[1]
        numsamp=dim(curdata)[2]
        rnames<-colnames(curdata)
        rnames<-gsub(".cdf", "", rnames, ignore.case=TRUE)
	quantcolnames=c("min", "first_quartile", "median", "mean", "third_quartile", "max")
	if(impute.bool==TRUE)
	{
		min.samp.percent=0.60
	}
	else
	{
		min.samp.percent=1
	}

        
                newrow={}
                finalmat={}
		
		
		cl<-makeCluster(5)
			
		
		
		clusterExport(cl, "getCVreplicates.child") 
		#clusterExport(cl, "numsamp")
		#clusterExport(cl, "numreplicates")
		#clusterExport(cl, "min.samp.percent")
		#clusterExport(cl, "impute.bool")
		#clusterExport(cl, "alignment.tool")
		
		cv.res<-parRapply(cl,curdata,getCVreplicates.child,numsamp=numsamp,numreplicates=numreplicates,min.samp.percent=min.samp.percent,impute.bool=impute.bool)
		
	dim(cv.res)=dim(matrix(nrow=6,ncol=numfeats))
	#cv.res<-t(cv.res)
			
		
	stopCluster(cl)
        final_set<-as.data.frame(cv.res)
        rownames(final_set)=NULL
	final_set<-apply(final_set,2,as.numeric)
	final_set<-as.data.frame(t(final_set))
	colnames(final_set)<-quantcolnames
        return(final_set)
}

getCVreplicates.child<-function(curdata,numsamp,numreplicates,min.samp.percent,impute.bool)
{
	
			newrow={}
			#numsamp=length(curdata)
			for(samp in seq(1,numsamp,numreplicates))
			{
				i=samp
				j=i+numreplicates-1
				
				curdata_int=curdata[c(i:j)]
				check_zeros=which(curdata_int==0)
				
				na_thresh=round(min.samp.percent*numreplicates)
				
				if(length(check_zeros)>=na_thresh)
				{
					cvval<-NA
					#newrow<-cbind(newrow,cvval)
				
				}
				else
				{
					#temporarily replace the missing intensities, set to 0 in apLCMS,
					#with mean intensity value of the corresponding replicates (with non-zero values)
					if(length(check_zeros)>0){
					if(impute.bool==TRUE){
						curdata_int[check_zeros]=mean(t(curdata_int[-c(check_zeros)]))
					}
					}
					sdval<-sd(curdata_int)
					meanval<-mean(t(curdata_int))
					cvval<-100*(sdval/meanval)
					newrow<-cbind(newrow,cvval)
				}
			}
			if(length(newrow)>0)
			{
				na_ind=which(is.na(newrow)==TRUE)
			
				if(length(na_ind)>0)
				{
					sumrow=summary(as.vector(newrow[-na_ind]))
				}
				else
				{
					sumrow=summary(as.vector(newrow))
				}
			}
			else{sumrow<-{}}
			if(length(sumrow)<6)
			{
				for(i in 1:6)
				{
				 sumrow[i]=200
				}
			}
			finalmat<-{}
			
			finalmat<-rbind(finalmat, unlist(sumrow))
			return(finalmat)

}
#################################################################
#Function: Function that merges results from different parameter settings
#Description: Evaluate feature consistency based on PID or CV
#curdata_a: feature alignment output matrix from apLCMS or XCMS with
#         intensities at parameter settings P1
#curdata_b: feature alignment output matrix from apLCMS or XCMS with
#         intensities at parameter settings P2
##max.mz.diff: +/- mz tolerance in ppm for feature matching
##max.rt.diff: retention time tolerance for feature matching
##tstatistic: Threshold for defining signifcance level of the paired t-test
#numreplicates: number of replicates per sample
#alignment.tool: name of the feature alignment tool eg: "apLCMS" or "XCMS"
##################################################################
get.Unique.mzs<-function(curdata_a, curdata_b, max.mz.diff=5, tstatistic.thresh=3,alignment.tool)
{
	
        curdata_a<-rbind(curdata_a,curdata_b)
        curdata_a<-unique(curdata_a)
        curdata_a<-curdata_a[order(curdata_a$mz),]
        curdata_b<-as.data.frame(curdata_a)
        diff_mz_num=1
        unique_mz={}
        ppm_v={}
        rt_v={}
	cnames=colnames(curdata_a)
	if(is.na(alignment.tool)==FALSE){
	 if(alignment.tool=="apLCMS")
        {
              sample.col.start=5
	      cnames[1]="mz"
	      
        }else{
              if(alignment.tool=="XCMS")
              {
                    sample.col.start=9
		    cnames[1]="mz"

		    cnames[4]="time"
		    colnames(curdata_a)=cnames
		    colnames(curdata_b)=cnames
              }
        }}else{
		cnames[1]="mz"
	}
	
	
	colnames(curdata_b)=cnames
	diffmat=data.frame()
        #Step 1 Group features by m/z
        for(j in 1:dim(curdata_b)[1])
	{
                                                           
                                ppmb=(max.mz.diff)*(curdata_b$mz[j]/1000000)
                                getbind_same<-which(abs(curdata_b$mz-curdata_b$mz[j])<=ppmb)
				
				checkmz<-which(abs(diffmat$mz-curdata_b$mz[j])<=ppmb)
				
				if((length(checkmz)<1))
				{
				
					diffmat=rbind(diffmat,curdata_b[j,])
                                }
				
                                
        }
      
        diffmat=unique(diffmat)
        return(diffmat)
}


#################################################################
#Function: Function that merges results from different parameter settings
#Description: Evaluate feature consistency based on PID or CV
#curdata_a: feature alignment output matrix from apLCMS or XCMS with
#         intensities at parameter settings P1
#curdata_b: feature alignment output matrix from apLCMS or XCMS with
#         intensities at parameter settings P2
##max.mz.diff: +/- mz tolerance in ppm for feature matching
##max.rt.diff: retention time tolerance for feature matching
##tstatistic: Threshold for defining signifcance level of the paired t-test
#numreplicates: number of replicates per sample
#alignment.tool: name of the feature alignment tool eg: "apLCMS" or "XCMS"
##################################################################
merge.Results<-function(curdata_a, curdata_b, max.mz.diff=5, max.rt.diff=300, tstatistic.thresh=3,alignment.tool)
{
	curdata_a<-unique(curdata_a)
        curdata_a<-curdata_a[order(curdata_a$mz),]
	curdata_b<-unique(curdata_b)
        curdata_b<-curdata_b[order(curdata_b$mz),]
	sub_data_a<-list()
	sub_data_b<-list()
	lindex<-1
	min_mz<-min(curdata_a[,1],curdata_b[,1])
	max_mz<-max(curdata_a[,1],curdata_b[,1])

	mz_group<-ceiling(max_mz/min_mz)
	
	for(i in seq(min_mz,max_mz,mz_group))
	{
		stopmz<-i+mz_group
		if(stopmz>max_mz)
		{
			stopmz<-max_mz
		}
		sub_data_a[[lindex]]<-rbind(curdata_a[which(curdata_a$mz>=i & curdata_a$mz<stopmz),],curdata_b[which(curdata_b$mz>=i & curdata_b$mz<stopmz),])
		#sub_data_b[[lindex]]<-
		lindex<-lindex+1
		
	}
	print(max.mz.diff)

	cl<-makeCluster(12)
	clusterEvalQ(cl, "merge.Results.child")

        merge.res<-parLapply(cl,sub_data_a,merge.Results.child,max.mz.diff=max.mz.diff, max.rt.diff=max.rt.diff, tstatistic.thresh=3,alignment.tool=alignment.tool)
	stopCluster(cl)
   
	final.res={}
	for(s in 1:length(merge.res))
	{	

		final.res<-rbind(final.res,merge.res[[s]])
	}
	return(final.res)
	
}



merge.Results.child<-function(curdata_a, max.mz.diff=15, max.rt.diff=300, tstatistic.thresh=20,alignment.tool)
{
    
        diff_mz_num=1
        unique_mz={}
        ppm_v={}
        rt_v={}
        cnames=colnames(curdata_a)
        curdata_a<-as.data.frame(curdata_a)

         if(alignment.tool=="apLCMS")
        {
              sample.col.start=5
        }
        else
        {
              if(alignment.tool=="XCMS")
              {
                    sample.col.start=9
                    cnames[1]="mz"

                    cnames[4]="time"
                    colnames(curdata_a)=cnames
                    
              }
              else
              {
                    stop(paste("Invalid value for alignment.tool. Please use either \"apLCMS\" or \"XCMS\"", sep=""))
              }
        }



        #Step 1 Group features by m/z
        mz_groups<-lapply(1:dim(curdata_a)[1],function(j){
                                commat={}
                                diffmz=new("list")
                                ppmb=(max.mz.diff)*(curdata_a$mz[j]/1000000)
                                getbind_same<-which(abs(curdata_a$mz-curdata_a$mz[j])<=ppmb)
                                diffmz[[diff_mz_num]]=curdata_a[getbind_same,]
                                diff_mz_num=diff_mz_num+1
                                return(diffmz)
          })
        #Step 2 Sub-group features from Step 1 by Retention time
        #find the features with RT values within the defined range as compared to the query feature
        diffmat={}
        for(j in 1:length(mz_groups))
        {
                temp_diff={}
                if(dim(mz_groups[[j]][[1]])[1]>1)
                {
                                tempdata=mz_groups[[j]][[1]]
                                for(d in 1:dim(tempdata)[1])
                                {
                                        tempdata=mz_groups[[j]][[1]]
                                        cur_feat=tempdata[d,]
                                        other_feats=tempdata
                                        getbind_rtsame<-which(abs(other_feats$time-cur_feat$time)<=max.rt.diff)
                                        commat={}
                                        if(length(getbind_rtsame)>1)
                                        {
                                                other_feats<-other_feats[getbind_rtsame,]

                                                #find the features with RT values within the defined range as compared to the query feature
                                                getbind_rtsame_check<-which(abs(temp_diff$time-cur_feat$time)<=50)
						
						if(length(getbind_rtsame_check)<1)
                                                {
                                                       y=cur_feat[sample.col.start:(dim(tempdata)[2]-6)]
                                                       na_indy=which(y==0)
						       
						       
						       if(FALSE){
                                                       #calculate p-value using paired t-test
                                                       #ignore the missing intensities while calculating p-value
                                                       ttest_sum=apply(other_feats[,sample.col.start:(dim(tempdata)[2]-6)],1,function(x)
                                                       {
                                                                na_indx=which(x==0)
                                                                na_ind=c(na_indy,na_indx)
                                                                if(length(na_indx)>1 && length(na_indy)>1)
                                                                {
                                                                        if(length(na_ind)>0)
                                                                        {
                                                                                        if(length(x[-na_ind])>1 && length(y[-na_ind])>1)
                                                                                        {
                                                                                                ttest_res=t.test(t(x[-na_ind]),as.matrix(y[-na_ind]),paired=T)
                                                                                                ttest_res=abs(ttest_res$statistic)
                                                                                        }
                                                                                        else
											{
                                                                                                ttest_res=1
                                                                                        }
                                                                        }
                                                                        else
                                                                        {
                                                                                ttest_res=t.test(t(x), as.matrix(y),paired=T)
                                                                                ttest_res=abs(ttest_res$statistic)
                                                                        }
                                                                }
                                                                else
                                                                {
                                                                        ttest_res=t.test(t(x), as.matrix(y),paired=T)
									ttest_res=abs(ttest_res$statistic)
                                                                }
                                                                return(ttest_res)
                                                        })
							
							}
							
							 #calculate p-value using Welch two sample t-test
                                                        #ignore the missing intensities while calculating p-value
                                                        ttest_sum=apply(other_feats[,sample.col.start:(dim(tempdata)[2]-6)],1,function(x)
                                                        {
                                                                na_indx=which(x==0)
                                                                na_ind=c(na_indy,na_indx)
                                                                if(length(na_ind)>0)
                                                                {
                                                                        #ttest_res=t.test(t(x[-na_ind]),as.matrix(y[-na_ind]),paired=T)
									if(length(x[-na_ind])>1 && length(y[-na_ind])>1)
                                                                                        {
                                                                                                ttest_res=t.test(t(x[-na_ind]),as.matrix(y[-na_ind]),paired=T)
												ttest_res=abs(ttest_res$statistic)
                                                                                        }
                                                                                        else
											{
                                                                                                ttest_res=1
                                                                                        }
                                                                }
                                                                else
                                                                {
                                                                        ttest_res=t.test(t(x), as.matrix(y),paired=T)
									ttest_res=abs(ttest_res$statistic)
                                                                }
                                                                return(ttest_res)
                                                        })
							
                                                        same_feat_ind=which(ttest_sum<tstatistic.thresh)
                                                        same_feat_ind=c(same_feat_ind,which(is.na(ttest_sum)))

                                                        if(length(same_feat_ind)>0)
                                                        {
                                                                commat=other_feats[same_feat_ind,]
                                                                best_level_index=which(as.numeric(commat$median)==min(as.numeric(commat$median)))
                                                                if(length(best_level_index)>0)
                                                                {
                                                                        best_level_index=best_level_index[1]
                                                                }
                                                                best_level_data=commat[best_level_index,]
                                                        }
                                                        else
                                                        {
                                                                best_level_data=cur_feat

                                                        }
                                                        if(dim(best_level_data)[1]>0)
                                                        {
                                                                getbind_rtsame_check<-which(abs(temp_diff$time-best_level_data$time)<=50)

                                                                if(length(getbind_rtsame_check)<1)
                                                                {
                                                                        diffmat=rbind(diffmat, best_level_data)
                                                                        temp_diff=rbind(temp_diff,best_level_data)
                                                                }
                                                        }
                                                }
                                        }
                                        else
                                        {
                                                diffmat<-rbind(diffmat,cur_feat)
                                                temp_diff=rbind(temp_diff,tempdata[d,])
                                        }
                                }
                }
                else
                {
                        diffmat<-rbind(diffmat,as.matrix(mz_groups[[j]][[1]]))
                }
        }
        diffmat=unique(diffmat)
        return(diffmat)
}

                                                 




#################################################################
#Function: feat.batch.annotation
#Description: search m/z in Metlin and KEGG
#mz: single m/z value in ppm (eg: 121.945)
#max.mz.diff: +/- m/z match tolerance in ppm for database matching
#           (eg: 5)
##################################################################
feat.batch.annotation<-function(data_a,max.mz.diff, queryadductlist, xMSanalyzer.outloc)
{
	data_a<-as.data.frame(data_a)
	
	mzlist<-data_a[,1]
	
	dir.create(xMSanalyzer.outloc,showWarnings=FALSE)
	
	adductlist=c(1.00727,22.989171,38.963171,-35.012729,-17.002729,7.01597,18.033871,
	33.033471,42.033871,44.971171,64.015771,-147.531929,-136.540929,-125.549929,-197.044929,
	-189.717629,-182.390329,-19.018429,-1.007229,18.998371,20.974671,34.969371,36.948571,
	44.998171,59.013871,-149.546429,-199.059529)
	names(adductlist)<-c("M+H","M+Na","M+K","M+H-2H2O","M+H-H2O", "M+Li","M+NH4",
	"M+CH3OH+H","M+ACN+H","M+2NA-H","M+ACN+Na","M+2H", "M+H+Na","M+2Na","M+3H",
	"M+2H+Na","M+2Na+H","M-H2O-H", "M-H", "M+F","M+Na-2H","M+Cl","M+K-2H",
	"M+FA-H","M+CH3COO","M-2H","M-3H")
	
	if(queryadductlist[1]=="all")
	{
		queryadductlist<-c("M+H","M+Na","M+K","M+H-2H2O","M+H-H2O", "M+Li","M+NH4",
	"M+CH3OH+H","M+ACN+H","M+2NA-H","M+ACN+Na","M+2H", "M+H+Na","M+2Na","M+3H",
	"M+2H+Na","M+2Na+H","M-H2O-H", "M-H", "M+F","M+Na-2H","M+Cl","M+K-2H",
	"M+FA-H","M+CH3COO","M-2H","M-3H")
	}
	parentres={}
	
	
	for(adnum in 1:length(queryadductlist))
	{
		adductname=queryadductlist[adnum]
		adductmass=adductlist[as.character(adductname)]
		
		print(paste("Query adduct: ",adductname,sep=""))
		cl<-makeCluster(2)
			
		clusterEvalQ(cl, library(XML))
		clusterEvalQ(cl, "feat.batch.annotation.child")
		
		mz.annot.res<-parLapply(cl,mzlist,feat.batch.annotation.child,max.mz.diff=max.mz.diff,adductmass=adductmass)
		
		
		
		stopCluster(cl)
		res={}
		for(mzl in 1:length(mz.annot.res))
		{
			res=rbind(res,mz.annot.res[[mzl]])
			
		}
		adductname=c(rep(adductname,dim(res)[1]))
		tempres<-cbind(adductname,res)
		parentres=rbind(parentres,tempres)
		rm(tempres)
		
	}
	
	res<-parentres[order(parentres[,2]),]
	html_resindex<-c(1,2,5,4,6:7,9,11:12,14,16,18,20,22)
	html_resindex<-html_resindex+1
	html_res<-res[,c(1,html_resindex)]
		
		sernum=seq(1,dim(html_res)[1])
		
		html_res<-cbind(sernum,html_res)
		
		colnames(html_res)=c("","Adduct","Query.m/z", "Search mass \n tolerance range (+/-)", "Metlin.match.ID", "Metlin.match.mass", "Metlin.compound.name", "CASID", "KEGG.Compound.ID", "KEGG.Pathway.name", "KEGG.Pathway.ID", "HMDB.ID", "PubChem.Substance.ID", "PubChem.Compound.ID", "ChEBI.ID", "LIPID.MAPS.ID")
		fname=paste("Annotation_results",sep="")
		HTMLInitFile(filename=fname,Title="Annotation Results", outdir=xMSanalyzer.outloc)
		fname=paste(xMSanalyzer.outloc,"/Annotation_results.html",sep="")
		
		HTML(html_res,file=fname,Border=1,innerBorder=1,useCSS=TRUE)
		HTMLEndFile(file=fname)
		
		
		text_resindex<-c(1,2,3,4,6,7,8,10,11,13,15,17,19,21)
		text_resindex<-text_resindex+1
		text_res<-res[,c(1,text_resindex)]
		
		sernum=seq(1,dim(text_res)[1])
		text_res<-cbind(sernum,text_res)
		
		
		colnames(text_res)=c("","Adduct","Query.m/z", "Search mass \n tolerance range (+/-)", "Metlin.match.ID", "Metlin.match.mass", "Metlin.compound.name", "CASID", "KEGG.Compound.ID", "KEGG.Pathway.ID", "KEGG.Pathway.name", "HMDB.ID", "PubChem.Substance.ID", "PubChem.Compound.ID", "ChEBI.ID", "LIPID.MAPS.ID")

		fname=paste(xMSanalyzer.outloc,"/Annotation_results.txt",sep="")
		write.table(text_res,file=fname,sep="\t",row.names=FALSE)
	
	return(list("text.res"=text_res,"html.res"=html_res))
} 

#################################################################
#Function: feat.batch.annotation.child
#Description: search m/z in Metlin with links to KEGG, HMDB, PubChem, LipidMaps, ChEBI, and CAS 
#mzorig: single m/z value in ppm (eg: 121.945)
#max.mz.diff: +/- m/z match tolerance in ppm for database matching
#           (eg: 5)
#adductmass: mass of the adduct to be selected (eg: 1.00727 for M+H, or -35.012729 for M+H-2H2O)
##################################################################
feat.batch.annotation.child<-function(mz.val,max.mz.diff, adductmass)
{
	
	adductlist=c(1.00727,22.989171,38.963171,-35.012729,-17.002729,7.01597,18.033871,
	33.033471,42.033871,44.971171,64.015771,-147.531929,-136.540929,-125.549929,-197.044929,
	-189.717629,-182.390329,-19.018429,-1.007229,18.998371,20.974671,34.969371,36.948571,
	44.998171,59.013871,-149.546429,-199.059529)
	names(adductlist)<-c("M+H","M+Na","M+K","M+H-2H2O","M+H-H2O", "M+Li","M+NH4",
	"M+CH3OH+H","M+ACN+H","M+2NA-H","M+ACN+Na","M+2H", "M+H+Na","M+2Na","M+3H",
	"M+2H+Na","M+2Na+H","M-H2O-H", "M-H", "M+F","M+Na-2H","M+Cl","M+K-2H",
	"M+FA-H","M+CH3COO","M-2H","M-3H")
	
	#convert to neutral mass
	mz=mz.val-adductmass
	
        delta_ppm=(max.mz.diff)*(mz/1000000)
        min_mz=round((mz-delta_ppm),5)
        max_mz=round((mz+delta_ppm),5)
	 
	
	
	mzorig=round(mz.val,5)
	delta_ppm=round(delta_ppm,5)
	Sys.sleep(0.5)

	search_link=paste("http://metlin.scripps.edu/metabo_list.php?mass_min=",min_mz,"&mass_max=",max_mz,sep="")

     
	html_res={}  
	
        html_res=readHTMLTable(search_link)
        
      
        res={}
	
        #if(length(html_res)[2]>2)
	 if(length(html_res)>2)
	{
			html_res=as.data.frame(html_res[[3]])
                #id_list=html_res[,3]
		id_list=html_res$MID
		id_list<-unique(id_list)
                for(c in 1:length(id_list))
                {
                        html_link=paste("http://metlin.scripps.edu/metabo_info.php?molid=",id_list[c],sep="")

                        if(c>3){
				Sys.sleep(0.2)
				}
			html_res=readHTMLTable(html_link)
			html_res=as.data.frame(html_res)
			CName<-"-"
			casID<-"-"
			keggID<-"-"
			kegglink<-"-"
			keggpathid<-"-"
			keggpathname<-"-"
			keggpathlink<-"-"
			hmdbID<-"-"
			hmdblink<-"-"
			pubchemsid<-"-"
			pubchemslink<-"-"
			pubchemcid<-"-"
			pubchemclink<-"-"
			chebiid<-"-"
			chebilink<-"-"
			lipidmapsid<-"-"
			lipidmapslink<-"-"
			
			keggpathinf<-{}
			html_link=paste("<a href=http://metlin.scripps.edu/metabo_info.php?molid=",id_list[c],">",id_list[c],"</a>",sep="")
			t1<-html_res$NULL.V2
			if(length(t1)>0)
			{
			
			t2<-gregexpr(pattern="}[0-9|A-Z|:punct:|(|:print:][[:punct:]|[:alnum:]|[:blank:]|[:space:]]*{3,}",perl=FALSE,ignore.case=TRUE,text=t1[3])
			t3=t2[[1]]+1
			strlength=attr(t3,"match.length")-2
			t4=strsplit(as.character(t1[3]),"")
			if(length(t3)>0){
				cName<-t4[[1]][t3[1]:(t3[1]+strlength)]
				cname_length<-length(cName)
				cName1<-paste(cName,collapse="",sep="")
				cName<-cName1
				check_badname<-grep("ction OpenLink",cName1)
				if(length(check_badname)>0)
				{
					if(check_badname==1)
					{
						t2<-gregexpr(pattern="}",text=cName1)
						t3=t2[[1]]+1
						#strlength=attr(t3,"match.length")-2
						
						c2<-strsplit(cName1,"")
						c3<-c2[[1]][t3[1]:length(c2[[1]])]
						#cName<-cName[t3[1]:length(cName)]
						cName<-paste(c3,collapse="")
			
					}
				}
			
			}

			t2<-gregexpr(pattern="([0-9]+[.][0-9]*)+",perl=FALSE,text=t1[2])
			t3=t2[[1]]
			strlength=attr(t3,"match.length")-1
			t4=strsplit(as.character(t1[2]),"")
			if(strlength>0){
			mass<-t4[[1]][t3[1]:(t3[1]+strlength)]
			mass<-paste(mass,collapse="")
			}
			
			t2<-gregexpr(pattern="([0-9]+[-][0-9]*)+",perl=FALSE,text=t1[7])
			t3=t2[[1]]
			strlength=attr(t3,"match.length")-1
			t4=strsplit(as.character(t1[7]),"")
			if(strlength>0){
			casID<-t4[[1]][t3[1]:(t3[1]+strlength)]
			casID<-paste(casID,collapse="")
			}
			
			t2<-gregexpr(pattern="C[0-9]{3,5}",perl=FALSE,text=t1[10])
			t3=t2[[1]]
			strlength=attr(t3,"match.length")-1
			t4=strsplit(as.character(t1[10]),"")
			if(strlength>0){
			keggID<-t4[[1]][t3[1]:(t3[1]+strlength)]
			keggID<-paste(keggID,collapse="")
			kegglink<-paste("http://www.genome.jp/dbget-bin/www_bget?cpd:",keggID,sep="")
			html_res=readHTMLTable(kegglink)
			
			
			kegglink<-paste("<a href=http://www.genome.jp/dbget-bin/www_bget?cpd:",keggID,">",keggID,"</a>",sep="")
			if(length(html_res)>1){
				html_res2=as.data.frame(html_res[4])
				pathindex<-which(html_res2[1]=="Pathway")
				if(length(pathindex)>0){
					t2<-gregexpr(pattern="(ko[0-9]+)",perl=FALSE,ignore.case=TRUE,text=as.character(html_res2[pathindex,2]))
					#t2<-gregexpr(pattern="([A-Z]|:punct:|:blank:){3,}",perl=FALSE,ignore.case=TRUE,text=as.character(html_res[pathindex,2]))
					#t2<-gregexpr(pattern="([:alpha:][:punct:][:blank:])+",perl=FALSE,ignore.case=TRUE,text=as.character(html_res2[pathindex,2]))
					split_pathinf<-strsplit(as.character(html_res2[pathindex,2]),"")
					if(t2[[1]][1]>0)
					{
						for(item in 1:length(t2[[1]])){
							
							start_index<-t2[[1]][item]
							
							if(item==length(t2[[1]]))
							{
								next_index=length(split_pathinf[[1]])+1
							}
							else{
								next_index<-t2[[1]][item+1]
							}
							
							keggpathid<-paste(split_pathinf[[1]][start_index:(start_index+6)],collapse="")
							keggpathname<-paste(split_pathinf[[1]][(start_index+6+3):(next_index-1)],collapse="")
							keggpathlink=paste("<a href=http://www.genome.jp/kegg-bin/show_pathway?",keggpathid,"+",keggID,">",keggpathid,"</a>",sep="")
							keggpathinf<-rbind(keggpathinf, c(keggpathid,keggpathname, keggpathlink))
							
							#print(keggpathinf)
						}
					}
				}
				
				otherdbindex<-which(html_res2[1]=="Other DBs")
				if(length(otherdbindex)>0){
					
					t2<-gregexpr(pattern="([A-Z]{3,})*([0-9]{3,})*",perl=FALSE,ignore.case=TRUE,text=as.character(html_res2[otherdbindex,2]))
					if(t2[[1]][1]>0){
						split_pathinf<-strsplit(as.character(html_res2[otherdbindex,2]),"")
						
						
						a1=attr(t2[[1]],"match.length")
						a2=a1[-which(a1==0)]
						if(length(which(a1==0))>0){
							t3=t2[[1]][-which(a1==0)]
						}
						else{
							t3=t2[[1]]
						}
						for(item in 1:length(t3)){
							start_index<-t3[item]
							
							if(item==length(t3))
							{
								next_index=length(split_pathinf[[1]])
							}
							else{
								next_index<-t3[item+1]
							}
							entry<-paste(split_pathinf[[1]][start_index:(start_index+a2[item])],collapse="")
							
							if(entry=="PubChem:")
							{
								pubchemsid<-paste(split_pathinf[[1]][(next_index:(next_index+a2[item+1]-1))],collapse="")
								pubchemslink<-paste("<a href=http://pubchem.ncbi.nlm.nih.gov/summary/summary.cgi?sid=",pubchemsid,">",pubchemsid,"</a>",sep="")
							}
							else
							{
								if(entry=="ChEBI:")
								{
									chebiid<-paste(split_pathinf[[1]][(next_index:(next_index+a2[item+1]-1))],collapse="")
									chebilink<-paste("<a href=http://www.ebi.ac.uk/chebi/searchId.do?chebiId=CHEBI:",chebiid,">",chebiid,"</a>",sep="")
								}else
								{
									if(entry=="LIPIDMAPS:")
									{
										lipidmapsid<-paste(split_pathinf[[1]][(next_index:(next_index+a2[item+1]-1))],collapse="")
										lipidmapslink<-paste("<a href=http://www.lipidmaps.org/data/get_lm_lipids_dbgif.php?LM_ID=",lipidmapsid,">",lipidmapsid,"</a>",sep="")
									}
								}
							}
						}
						
					}
				}
				
			}
			
			}
			
			t2<-gregexpr(pattern="HMDB[0-9]{2,}",perl=FALSE,text=t1[11])
			t3=t2[[1]]
			strlength=attr(t3,"match.length")-1
			t4=strsplit(as.character(t1[11]),"")
			if(strlength>0){
			hmdbID<-t4[[1]][t3[1]:(t3[1]+strlength)]
			hmdbID<-paste(hmdbID,collapse="")
			hmdblink<-paste("<a href=http://www.hmdb.ca/metabolites/",hmdbID,">",hmdbID,"</a>",sep="")
			}
				
				
			t2<-gregexpr(pattern="[}][0-9]{2,}",perl=FALSE,text=t1[12])
			t3=t2[[1]]+1
			strlength=attr(t3,"match.length")-2
			t4=strsplit(as.character(t1[12]),"")
			if(strlength>0){
			pubchemID<-t4[[1]][t3[1]:(t3[1]+strlength)]
			pubchemcid<-paste(pubchemID,collapse="")
			pubchemclink<-paste("<a href=http://pubchem.ncbi.nlm.nih.gov/summary/summary.cgi?cid=",pubchemcid,">",pubchemcid,"</a>",sep="")
			
			}
			
			keggpathinf<-as.data.frame(keggpathinf)
			
			if(dim(keggpathinf)[1]>0)
			{
				for(pid in 1:dim(keggpathinf)[1])
				{
					keggpathid<-as.character(keggpathinf[pid,1])
					keggpathname<-as.character(keggpathinf[pid,2])
					keggpathlink<-as.character(keggpathinf[pid,3])
					
					
					res<-rbind(res,c(mzorig,delta_ppm,as.character(id_list[c]), mass, html_link, cName,casID,keggID,kegglink,keggpathid,keggpathname,keggpathlink,hmdbID,hmdblink,pubchemsid,pubchemslink, pubchemcid,pubchemclink,chebiid,chebilink, lipidmapsid, lipidmapslink))
					
				}
			}
			else
			{
				keggpathid<-"-"
				keggpathname<-"-"
				keggpathlink<-"-"
				
				
				res<-rbind(res,c(mzorig,delta_ppm,as.character(id_list[c]), mass, html_link, cName,casID,keggID,kegglink,keggpathid,keggpathname,keggpathlink,hmdbID,hmdblink,pubchemsid,pubchemslink, pubchemcid,pubchemclink,chebiid,chebilink, lipidmapsid, lipidmapslink))
				
			}
		}
		}

        }else{
                res<-rbind(res,c(mzorig,delta_ppm,"-","-","-","-","-","-","-","-","-","-","-","-","-","-","-","-","-","-","-","-"))
        }
	Sys.sleep(0.2)
        return(res)
}




#########################################################################################
###Function to find metabolic characteristics of individuals
#curdata: output matrix from apLCMS or XCMS
#min.samps: minimum number of samples in which a feature signal 
#	   should be detected in at least min.reps replicates
#min.reps: minimum proportion of replicates in which a signal is present (eg: 0.5 or 1)
#num_replicats: number of replicats for each sample
#alignment.tool: name of feature alignment tool eg: "apLCMS" or "XCMS"
########################################################################################
check.mz.in.replicates<-function(curdata,min.samps,min.reps,num_replicates,alignment.tool)
{
        numfeats=dim(curdata)[1]
        numsamp=dim(curdata)[2]
        textp1=""
        t=1

        if(alignment.tool=="apLCMS")
        {
              col_end=4
	}
        else
        {
                 if(alignment.tool=="XCMS")
                 {
                        col_end=8
                 }
                 else
                 {
                         stop(paste("Invalid value for alignment.tool. Please use either \"apLCMS\" or \"XCMS\"", sep="")) 
                  
                 }
        }
        rnames<-colnames(curdata)
        
        rnames<-rnames[-c(1:col_end)]

        rnames<-gsub("X","",rnames)
        rnames<-gsub("(-|.)[0-9].cdf", "", rnames)
        rnames=rnames[seq(1,length(rnames),2)]
        finalmat={}
        samplerepCVmat<-{}
        replicate_check=0
	
        for(r in 1:numfeats)
        {
                replicate_check=0
		intvec={}
		num.samps.check=0
                for(samp in seq(1,(numsamp-col_end),num_replicates))
                {
                        newrow={}
                	intvec={}
		        for(replicate in 1:num_replicates)
			{ 
				i=col_end+samp+replicate-1
				intvec=c(intvec,curdata[r,i])
				
			}
			if(length(which(intvec>0))>=(min.reps*num_replicates))
			{
                                	replicate_check=1
				 	num.samps.check=num.samps.check+1
			}
                
		}
		if(num.samps.check>min.samps)
		{	
			replicate_check=1
		}
		else
		{
			replicate_check=0
		}
                finalmat<-rbind(finalmat,replicate_check)
        }

        finalmat<-curdata[which(finalmat==1),]
        return(finalmat)

}


#Function:find.Overlapping.mzs
#Description: This function matches features between two or more datasets using the
#following user defined criteria:
#1) Maximum m/z difference (+/-) ppm
#2) Maximum retention time difference in seconds
#Input:
#data_a->apLCMS output for dataset A,
#data_b->apLCMS output for dataset B,
#max.mz.diff->Maximum m/z difference (+/-) ppm
#max.rt.diff->Maximum retention time difference in seconds
#
#Output:
#Data frame that includes mz and retention time of common features
#
#Usage:
#common_features<-matchFeaturesmulti(data_a, data_b, max.mz.diff=10, max.rt.diff=300)
############################################
find.Overlapping.mzs<-function(data_a, data_b, mz.thresh=10, time.thresh=NA, alignment.tool=NA)
{

        data_a<-as.data.frame(data_a)
        data_b<-as.data.frame(data_b)
	data_a<-unique(data_a)
        
        data_b<-unique(data_b)
        
        com_mz_num=1
        unique_mz={}
        ppm_v={}
        rt_v={}

        commat={}

	col.names.dataA=colnames(data_a)
	col.names.dataB=colnames(data_b)

	if(is.na(alignment.tool)==FALSE){
	 if(alignment.tool=="apLCMS")
        {
              sample.col.start=5
        }
        else
        {
              if(alignment.tool=="XCMS")
              {
                    sample.col.start=9
                    col.names.dataA[1]="mz"
                    col.names.dataA[2]="time"
		    col.names.dataB[1]="mz"
                    col.names.dataB[2]="time"
                    colnames(data_a)=col.names.dataA
                    colnames(data_b)=col.names.dataB
              }
	      
	}}else{
                    #stop(paste("Invalid value for alignment.tool. Please use either \"apLCMS\" or \"XCMS\"", sep=""))
		    
		    col.names.dataA[1]="mz"
		    col.names.dataB[1]="mz"
		    colnames(data_a)=col.names.dataA
                    colnames(data_b)=col.names.dataB
	}

       #data_a<-data_a[order(data_a$mz),]
       #data_b<-data_b[order(data_b$mz),]
       data_a<-as.data.frame(data_a)
	data_b<-as.data.frame(data_b)
	colnames(data_a)=col.names.dataA
	colnames(data_b)=col.names.dataB
        #create header for the matrix with common features
	if(is.na(time.thresh)==FALSE){
	mznames=c("index.A","mz.data.A", "time.data.A", "index.B","mz.data.B","time.data.B", "time.difference") 
        }else{
	mznames=c("index.A","mz.data.A", "index.B","mz.data.B") 
	}

        #Step 1 Group features by m/zdim(data_a)[1]
        mz_groups<-lapply(1:dim(data_a)[1],function(j){

                                commat={}
                                commzA=new("list")
                                commzB=new("list")
                                ppmb=(mz.thresh)*(data_a$mz[j]/1000000)

                                getbind_same<-which(abs(data_b$mz-data_a$mz[j])<=ppmb)

                                if(is.na(time.thresh)==FALSE){
                                  if(length(getbind_same)>0)
                                  {
                                          nearest_time_diff=10000
                                          bestmatch={}
					  rnames={}
					  temp={}
					  commat={}
                                          for (comindex in 1:length(getbind_same))
                                          {
						  tempA=cbind(j,data_a[j,c(1,2)])
						  tempB=cbind(getbind_same[comindex],data_b[getbind_same[comindex],c(1,2)])
                                                  temp=cbind(tempA,tempB)
						
                                                  timediff=abs(data_a[j,2]-data_b[getbind_same[comindex],2])
                                                  
						  temp<-cbind(temp,timediff)
						 
                                                  if(timediff<time.thresh && timediff<=nearest_time_diff)
                                                  {
                                                          bestmatch=as.data.frame(temp)
                                                          nearest_time_diff=timediff
							  
							   
							
							 
						   }
					  }
					        rnames<-paste("mz",j,sep="")
                                          
						commat=as.data.frame(bestmatch)
					
						if(length(commat)>=4){
							rownames(commat)=rnames
					        }


                                  }
                                }
                                else
                                {
                                    if(length(getbind_same)>0)
                                    {
                                    for (comindex in 1:length(getbind_same))
                                          {
						  tempA=cbind(j,data_a[j,c(1)])
						  tempB=cbind(getbind_same[comindex],data_b[getbind_same[comindex],c(1)])
                                                  temp=cbind(tempA,tempB)
                                                  #temp=cbind(data_a[j,c(1)],data_b[getbind_same[comindex],c(1)])
                                                 
                                          }
					  commat=as.data.frame(temp)
					  rnames<-paste("mz",j,sep="")
					  rownames(commat)=rnames
					  
                                    }
                                }
                                return(as.data.frame(commat))


                })
		
		
	#Step 2 Sub-group features from Step 1 by Retention time
        #find the features with RT values within the defined range as compared to the query feature

        uniqueinA={}
        uniqueinB={}
        commat=data.frame()

	
	if(length(mz_groups)>0){
        for(j in 1:length(mz_groups))
        {
                temp_diff={}
		
		if(is.list(mz_groups)==TRUE)
		{
			tempdata=mz_groups[[j]]
		}
		else
		{
			tempdata=mz_groups[j]
		}
		
                if(length(tempdata)>1)
                {
			
			colnames(tempdata)=mznames
			tempdata=as.data.frame(t(tempdata))
			
                        temp=tempdata
                        
                        temp=as.data.frame(temp)
			
                        if(is.null(commat)==TRUE)
                        {
                                commat=t(temp)

                        }
                        else
                        {

                                commat=rbind(commat,t(temp))

                        }
			

                }
	

        }

        if(is.null(dim(commat))==FALSE)
        {
                commat=as.data.frame(commat)
        }
	}
	
	
        return(commat)
}

#########################################################
#
#
#
#
#########################################################
getVenn<-function(data_a,name_a, data_b,name_b,mz.thresh=10,alignment.tool, xMSanalyzer.outloc)
{
	dir.create(xMSanalyzer.outloc,showWarnings=FALSE)
	
	data_a<-get.Unique.mzs(data_a,data_a,max.mz.diff=mz.thresh,alignment.tool=alignment.tool)
       
        data_b<-get.Unique.mzs(data_b,data_b,max.mz.diff=mz.thresh,alignment.tool=alignment.tool)
	common<-find.Overlapping.mzs(data_a,data_b,mz.thresh,time.thresh=NA,alignment.tool=alignment.tool)

	rm_index<-which(data_a$mz%in%common$mz.data.A)
	if(length(rm_index)>0){
	uniqueA<-data_a[-rm_index,]
	}
	
	rm_index<-which(data_b$mz%in%common$mz.data.B)
	if(length(rm_index)>0){
	uniqueB<-data_b[-rm_index,]
	}
	num_commonA<-length(unique(common$mz.data.A))
	num_commonB<-length(unique(common$mz.data.B))
	
	num_uniqueA<-dim(uniqueA)[1]
	num_uniqueB<-dim(uniqueB)[1]
	
	g1 <-c(seq(1,(num_commonA+num_uniqueA)))

	g2<-c(seq(1,(num_commonB+num_uniqueB)))

	g1[1:num_commonA]=paste("x_",g1[1:num_commonA],sep="")
	g2[1:num_commonB]=paste("x_",g2[1:num_commonB],sep="")
	g1[(num_commonA+1):(num_commonA+num_uniqueA)]=paste("y_",g1[(num_commonA+1):(num_commonA+num_uniqueA)],sep="")
	g2[(num_commonB+1):(num_commonB+num_uniqueB)]=paste("z_",g2[(num_commonB+1):(num_commonB+num_uniqueB)],sep="")


	set1=as.character(g1)
	set2=as.character(g2)
	universe <- sort(unique( c(set1,set2)))
	Counts <- matrix(0, nrow=length(universe), ncol=2)
	colnames(Counts) <- c(name_a, name_b)
	for (i in 1:length(universe))
	{
		Counts[i,1] <- universe[i] %in% set1
		Counts[i,2] <- universe[i] %in% set2
	}
	fname<-paste(xMSanalyzer.outloc,"/overlapbetween", name_a,"_",name_b,"_",mz.thresh,"ppm.pdf",sep="")
	venn_counts<-vennCounts(Counts)
	pdf(fname)
	vennDiagram(venn_counts)
	dev.off()
	return(list("common"=common,"uniqueA"=uniqueA,"uniqueB"=uniqueB,"vennCounts"=venn_counts))
}

getVennmultiple<-function(data_a,name_a, data_b,name_b,data_c,name_c,mz.thresh=10,alignment.tool=NA, xMSanalyzer.outloc)
{
	dir.create(xMSanalyzer.outloc,showWarnings=FALSE)
	
	data_a<-as.data.frame(data_a)
	data_b<-as.data.frame(data_b)
	data_c<-as.data.frame(data_c)
	data_a<-get.Unique.mzs(data_a,data_a,max.mz.diff=mz.thresh,alignment.tool=alignment.tool)
       
        data_b<-get.Unique.mzs(data_b,data_b,max.mz.diff=mz.thresh,alignment.tool=alignment.tool)
	
	data_c<-get.Unique.mzs(data_c,data_c,max.mz.diff=mz.thresh,alignment.tool=alignment.tool)
        data_a<-as.data.frame(data_a)
	data_b<-as.data.frame(data_b)
	data_c<-as.data.frame(data_c)
	cnamesA<-colnames(data_a)
	cnamesB<-colnames(data_b)
	cnamesC<-colnames(data_c)
	
	cnamesA[1]="mz"
	cnamesB[1]="mz"
	cnamesC[1]="mz"
	
	colnames(data_a)=cnamesA
	colnames(data_b)=cnamesB
	colnames(data_c)=cnamesC
	
	commonAB<-find.Overlapping.mzs(data_a,data_b,mz.thresh,time.thresh=NA,alignment.tool=alignment.tool)
	commonAC<-find.Overlapping.mzs(data_a,data_c,mz.thresh,time.thresh=NA,alignment.tool=alignment.tool)
	commonBC<-find.Overlapping.mzs(data_b,data_c,mz.thresh,time.thresh=NA,alignment.tool=alignment.tool)
	data_ab<-data_a[commonAB$index.A,]
	
	data_ab<-as.data.frame(data_ab)
	
	commonABC<-find.Overlapping.mzs(data_ab,data_c,mz.thresh,time.thresh=NA,alignment.tool=alignment.tool)
	
	data_ba<-data_b[commonAB$index.B,]
	data_ba<-as.data.frame(data_ba)
	
	commonBAC<-find.Overlapping.mzs(data_ba,data_c,mz.thresh,time.thresh=NA,alignment.tool=alignment.tool)
	
	#get unique A
	rm_index<-which(data_a$mz%in%commonAB$mz.data.A)
	
	rm_index<-c(rm_index,which(data_a$mz%in%commonAC$mz.data.A))
	
	if(length(rm_index)>0){
	uniqueA<-data_a[-rm_index,]
	uniqueA<-as.data.frame(uniqueA)
	}
	

	rm_index<-which(data_b$mz%in%commonAB$mz.data.B)
	
	rm_index<-c(rm_index,which(data_b$mz%in%commonBC$mz.data.A))
	
	#rm_index<-which(uniqueB$mz%in%commonBC$mz.data.A)

	if(length(rm_index)>0){
	uniqueB<-data_b[-rm_index,]
	uniqueB<-as.data.frame(uniqueB)
	}	
	
	
	rm_index<-which(data_c$mz%in%commonAC$mz.data.B)

	rm_index<-c(rm_index,which(data_c$mz%in%commonBC$mz.data.B))

	if(length(rm_index)>0){
	uniqueC<-data_c[-rm_index,]
	uniqueC<-as.data.frame(uniqueC)
	}
	
	
	
	num_commonAB<-length(unique(commonAB$mz.data.A))-length(which(unique(commonAB$mz.data.A)%in%unique(commonABC$mz.data.A)))
	
	num_commonBC<-length(unique(commonBC$mz.data.A))-length(which(unique(commonBC$mz.data.A)%in%unique(commonBAC$mz.data.A)))
	
	num_commonAC<-length(unique(commonAC$mz.data.A))-length(which(unique(commonAC$mz.data.A)%in%unique(commonABC$mz.data.A)))
	
	num_commonCB<-length(unique(commonBC$mz.data.B))-length(which(unique(commonBC$mz.data.B)%in%unique(commonBAC$mz.data.B)))
	
	num_commonCA<-length(unique(commonAC$mz.data.B))-length(which(unique(commonAC$mz.data.B)%in%unique(commonABC$mz.data.B)))
	
	
	num_commonABC<-min(length(unique(commonABC$mz.data.A)),length(unique(commonABC$mz.data.B)))
	
	num_uniqueA<-dim(uniqueA)[1]
	num_uniqueB<-dim(uniqueB)[1]
	num_uniqueC<-dim(uniqueC)[1]
	
	g1 <-paste("a",seq(num_commonAB+num_commonAC+num_commonABC+num_uniqueA),sep="")

	g2<-paste("b",seq(num_commonAB+num_commonBC+num_commonABC+num_uniqueB),sep="")
	
	g3<-paste("c",seq(num_commonCA+num_commonCB+num_commonABC+num_uniqueC),sep="")

	#x: AB; w:AC; v:BC;u:ABC
	if(num_commonAB>0)
	{
		g1[1:num_commonAB]=paste("x_",seq(1,num_commonAB),sep="")
		
		g2[1:num_commonAB]=paste("x_",seq(1,num_commonAB),sep="")
	}
	
	if(num_commonAC>0)
	{
		g1[(num_commonAB+1):(num_commonAB+num_commonAC)]=paste("w_",seq(1,num_commonAC),sep="")
		
		g3[1:num_commonAC]=paste("w_",seq(1,num_commonAC),sep="")
		
	}
	
	if(num_commonBC>0)
	{
		g2[(num_commonAB+1):(num_commonAB+num_commonBC)]=paste("v_",seq(1,num_commonBC),sep="")
	
		g3[(num_commonAC+1):(num_commonAC+num_commonBC)]=paste("v_",seq(1,num_commonBC),sep="")
	}
	
	g1[(num_commonAB+num_commonAC+1):(num_commonAB+num_commonAC+num_commonABC)]=paste("u_",seq(1,num_commonABC),sep="")
	g2[(num_commonAB+num_commonBC+1):(num_commonAB+num_commonBC+num_commonABC)]=paste("u_",seq(1,num_commonABC),sep="")
	g3[(num_commonAC+num_commonBC+1):(num_commonAC+num_commonBC+num_commonABC)]=paste("u_",seq(1,num_commonABC),sep="")
	

	set1=as.character(g1)
	set2=as.character(g2)
	set3=as.character(g3)
	universe <- sort(unique( c(set1,set2,set3)))
	Counts <- matrix(0, nrow=length(universe), ncol=3)
	colnames(Counts) <- c(name_a, name_b,name_c)
	for (i in 1:length(universe))
	{
		Counts[i,1] <- universe[i] %in% set1
		Counts[i,2] <- universe[i] %in% set2
		Counts[i,3] <- universe[i] %in% set3
	}
	venn_counts<-vennCounts(Counts)
	fname<-paste(xMSanalyzer.outloc,"/overlapbetween", name_a,"_",name_b,"_",name_c,"_",mz.thresh,"ppm.pdf",sep="")
	pdf(fname)
	vennDiagram(venn_counts)
	dev.off()
	
	return(list("commonABC"=commonABC,"uniqueA"=uniqueA,"uniqueB"=uniqueB,"uniqueC"=uniqueC,"commonAB"=commonAB, 
	"commonBC"=commonBC,"commonAC"=commonAC,"vennCounts"=venn_counts))

}

##################################################################
#Function:xMSwrapper.apLCMS
#Description: wrapper function based on apLCMS.align,evaluate.Features,
#            evaluate.Samples,merge.Results,search.Metlin, and
#            search.KEGG
################################################################
xMSwrapper.apLCMS<-function(cdfloc, apLCMS.outloc, xMSanalyzer.outloc, min.run.list=c(3), min.pres.list=c(0.3,0.8), minexp=2, mztol=NA, alignmztol=NA, numnodes=NA,run.order.file=NA, max.mz.diff=10,max.rt.diff=300, tstatistic.thresh=3, subs=NA ,num_replicates=3, db.tolerance.match=NA, adduct.list=c("M+H"), samp.filt.thresh=0.70,feat.filt.thresh=50,cormethod="spearman")
{
	
        ############################################
        #1) Align profiles using the cdf.to.ftr wrapper function in apLCMS
        if(is.na(apLCMS.outloc)==TRUE)
	{
		stop("Undefined value for parameter, apLCMS.outloc. Please define the apLCMS output location.")

	}
	 if(is.na(xMSanalyzer.outloc)==TRUE)
        {
                stop("Undefined value for parameter, xMSanalyzer.outloc. Please define the xMSanalyzer output location.")

        }

	if(is.na(cdfloc)==FALSE)
        {
                setwd(cdfloc)
                if(is.na(apLCMS.outloc)==FALSE)
                {
                      
			apLCMS.align(cdfloc, apLCMS.outloc,min.run.list, min.pres.list, minexp, mztol, alignmztol, numnodes,run.order.file,subs)
    
                }
                else
                {
                        stop("Undefined value for parameter, apLCMS.outloc. Please define the output location.")
                }
        }
	
	dir.create(apLCMS.outloc,showWarnings=FALSE)
	dir.create(xMSanalyzer.outloc,showWarnings=FALSE)
	
        {
                #stop("Undefined value for parameter, cdfloc. Please enter path of the folder where the CDF files to be processed are located.")
                #change location to the output folder
                setwd(apLCMS.outloc)
                alignmentresults<-list.files(apLCMS.outloc, "*.txt")
                if(length(alignmentresults)>0)
                {
                          curdata_dim={}
                          data_rpd=new("list")
			  
			  parent_bad_list<-{}
			  
                          if(num_replicates==2)
                          {
                                  fileroot="_PID"
                          }
                          else
                          {
                                  if(num_replicates>2)
                                  {
                                          fileroot="_CV"
                                  }
                                  else
                                  {
                                          fileroot=""
                                  }
                          }
                          for(i in 1:length(alignmentresults))
                          {
				  print(paste("******Evaluating apLCMS results at parameter setting ",i,"*******",sep=""))				  
                                  ############################################
                                  #2)Calculate pairwise correlation coefficients
                                  file_name=sapply(strsplit(alignmentresults[i],".txt"),head)
                                  curdata=read.table(paste(apLCMS.outloc,"/",alignmentresults[i],sep=""),header=TRUE)
                                  #curdata=check.mz.in.replicates(curdata)
                                
                                  #############################################
                                  ############################################
                                  #3) Calculate Percent Intensity Difference

                               if(num_replicates>1)
                                  {
							
								
								feat.eval.result=evaluate.Features(curdata, numreplicates=num_replicates,alignment.tool="apLCMS",impute.bool=TRUE)
								cnames=colnames(feat.eval.result)
								feat.eval.result<-apply(feat.eval.result,2,as.numeric)
								feat.eval.result<-as.data.frame(feat.eval.result)
								feat.eval.result.mat=cbind(curdata[,c(1:4)],feat.eval.result)  
								feat.eval.outfile=paste(xMSanalyzer.outloc,"/",file_name,fileroot,"featureassessment.txt",sep="")					  
								#write results
								write.table(feat.eval.result.mat, feat.eval.outfile,sep="\t", row.names=FALSE)
								
								
								curdata<-curdata[which(as.numeric(feat.eval.result$median)<=feat.filt.thresh),]
								
								  if(num_replicates>1)
								  {
									  print(paste("**calculating pairwise ",cormethod," correlation**",sep=""))

									  
									  
											rsqres<-evaluate.Samples(curdata, num_replicates, alignment.tool="apLCMS", cormethod)

											rsqres<-as.data.frame(rsqres)
											snames<-colnames(curdata[,-c(1:4)])
											snames_1<-snames[seq(1,length(snames),num_replicates)]
											rownames(rsqres)<-snames_1
											pcor_outfile=paste(xMSanalyzer.outloc,"/",file_name,"_sampleassessment_usinggoodfeatures.txt",sep="")
											write.table(rsqres, pcor_outfile,sep="\t",row.names=TRUE)
									
								  }
								  else
								  {
									  print("**skipping sample evaluataion as only one replicate is present**")
								  }
									
								if(num_replicates>2)
								{
									bad_samples<-which(rsqres$meanCorrelation<samp.filt.thresh)
								}else
								{
									bad_samples<-which(rsqres$Correlation<samp.filt.thresh)
								}
								
								if(length(bad_samples)>0){
								bad_sample_names<-snames_1[bad_samples]
								
								feat.eval.outfile=paste(xMSanalyzer.outloc,"/",file_name,"_badsamples_at_cor",samp.filt.thresh,".txt",sep="")
								bad_sample_names<-as.data.frame(bad_sample_names)
								colnames(bad_sample_names)<-paste("Samples with correlation between technical replicates <", samp.filt.thresh,sep="")
								write.table(bad_sample_names, file=feat.eval.outfile,sep="\t", row.names=FALSE)
								}
								
								bad_list={}
								if(length(bad_samples)>0){
									for(n1 in 1:length(bad_samples))
									{	
										if(bad_samples[n1]>1)
										{
											bad_samples[n1]=bad_samples[n1]+(bad_samples[n1]-1)*(num_replicates-1)
										}
											
									}
									for(n1 in 1:num_replicates)
									{
										bad_list<-c(bad_list,(bad_samples+n1-1))
									}
									bad_list<-bad_list[order(bad_list)]
									if(i>1){
										
										
										curdata<-curdata[,-c(parent_bad_list+4)]
										
									}
									else{
									    curdata<-curdata[,-c(bad_list+4)]
									    parent_bad_list<-bad_list

									}
								}
								curdata<-cbind(curdata,feat.eval.result[which(as.numeric(feat.eval.result$median)<=feat.filt.thresh),])
								
								feat.eval.outfile=paste(xMSanalyzer.outloc,"/",file_name,"cor",samp.filt.thresh,fileroot,feat.filt.thresh,"filtereddata.txt",sep="")	
								
								#write results
								write.table(curdata, feat.eval.outfile,sep="\t", row.names=FALSE)
                                  }
				  else
				  {
					  print("*********skipping feature evaluataion as only one replicate is present******")
				  }
                                
	       	}
                          ###########################################
                          #4) Merge two or more parameter settings
                          print("*************merging features detected at different parameter settings********************")
                          union_list=new("list")
                          num_pairs=1
                          finalres={}
                          rnames={}
                          data_rpd=new("list")
			  
			  for(i in 1:length(alignmentresults))
                          {
                                  file_name=sapply(strsplit(alignmentresults[i],".txt"),head)
                                  feat.eval.file=paste(xMSanalyzer.outloc,"/",file_name,"cor",samp.filt.thresh,fileroot,feat.filt.thresh,"filtereddata.txt",sep="")	
                                  data_rpd[[i]]=read.table(feat.eval.file,header=TRUE)

				  a1=sapply(strsplit(as.character(alignmentresults[i]), "\\_pres"), head, n=2)[2]
                                  minpres=sapply(strsplit(as.character(a1), "\\_run"), head, n=2)[1]
                                  minpres=as.numeric(minpres)
                                  a2=sapply(strsplit(as.character(alignmentresults[i]), "\\_run"), head, n=2)[2]
                                  minrun=sapply(strsplit(as.character(a2), "\\_"), head, n=2)[1]
                                  minrun=as.numeric(minrun)
                                  p1=paste(minrun,"_",minpres,sep="")
					    

                                  for(j in i:length(alignmentresults))
                                  {
                		     if(i!=j)
				     {
		                          file_name=sapply(strsplit(alignmentresults[j],".txt"),head)
					  feat.eval.file=paste(xMSanalyzer.outloc,"/",file_name,"cor",samp.filt.thresh,fileroot,feat.filt.thresh,"filtereddata.txt",sep="")	
                                          data_rpd[[j]]=read.table(feat.eval.file,header=TRUE)

                                          a1=sapply(strsplit(as.character(alignmentresults[j]), "\\_pres"), head, n=2)[2]
                                          minpres=sapply(strsplit(as.character(a1), "\\_run"), head, n=2)[1]
                                          minpres=as.numeric(minpres)
                                          a2=sapply(strsplit(as.character(alignmentresults[j]), "\\_run"), head, n=2)[2]
                                          minrun=sapply(strsplit(as.character(a2), "\\_"), head, n=2)[1]
                                          minrun=as.numeric(minrun)
                                          p2=paste(minrun,"_",minpres,sep="")
                                          if(i!=j)
                                          {
                                                  p1_p2=paste(p1,"_U_",p2,sep="")
                                          }
                                          else
                                          {
                                                  p1_p2=p1
                                          }
                                          union_list[[num_pairs]]=merge.Results(data_rpd[[i]],data_rpd[[j]],max.mz.diff,max.rt.diff, tstatistic.thresh,alignment.tool="apLCMS")
                                    		
					  curres={}
                                          curres=cbind(curres, dim(union_list[[num_pairs]])[1])
                                          curres=cbind(curres, mean(as.numeric(union_list[[num_pairs]]$median)))
					  
                                          rnames=rbind(rnames, p1_p2)
                                          finalres=rbind(finalres,curres)
                                          finalname=paste("apLCMS_feature_list_at_", p1_p2,"cor",samp.filt.thresh,fileroot,feat.filt.thresh,".txt",sep="")
					  
					  merge.res.colnames=colnames(union_list[[num_pairs]])
					  merge.res.colnames[(length(merge.res.colnames)-5):length(merge.res.colnames)]=paste(merge.res.colnames[(length(merge.res.colnames)-5):length(merge.res.colnames)],fileroot,sep="")

					  colnames(union_list[[num_pairs]])=merge.res.colnames

                                          #Output merge results
                                          write.table(union_list[[num_pairs]],file=paste(xMSanalyzer.outloc,"/",finalname,sep=""), sep="\t",row.names=FALSE)
					  
					  metlin.res={}
                                          kegg.res={}
					  if(is.na(adduct.list)==FALSE){
					  
                                          print("*********Mapping m/z values to known metabolites using METLIN and KEGG*********")
                                          metlin.res<-feat.batch.annotation(union_list[[num_pairs]],mz.tolerance.dbmatch,adduct.list,xMSanalyzer.outloc)
						                                                
                                         
					}

					  num_pairs=num_pairs+1
                        	    }
			      }				  
                          }
                          finalres<-as.data.frame(finalres)
                          rownames(finalres)<-rnames
               		  finalres<-cbind(rnames,finalres)
                          finalres<-as.data.frame(finalres)
			  if(fileroot=="PID")
                          {
                                colnames(finalres)<-c("Parameter Combination", "Number of Features", "median PID between sample replicates")
                          }
                          else
                          {
                                if(fileroot=="CV")
                                {
                                        colnames(finalres)<-c("Parameter Combination", "Number of Features", "median CV between sample replicates")
                                }
                          } 
		          write.table(finalres,file=paste(xMSanalyzer.outloc,"/apLCMS_merge_summary.txt",sep=""), sep="\t", row.names=FALSE)
               		  print("*************Processing complete**********") 

                }
                else
                {
                        stop(paste("No files exist in",apLCMS.outloc, "Please check the input value for cdfloc", sep=""))
                }
                
        }
}

##################################################################
#Function:xMSwrapper.XCMS
#Description: wrapper function based on apLCMS.align,evaluate.Features,
#            evaluate.Samples,merge.Results,search.Metlin, and 
#            search.KEGG
################################################################
xMSwrapper.XCMS<-function(cdfloc, XCMS.outloc,xMSanalyzer.outloc,step.list=c(0.001,0.01,0.1), mz.diff.list=c(0.001,0.01,0.1), sn.thresh.list=c(3,6,10), max.list=c(5,10), bw=10, minfrac=0.5, minsamp=2, mzwid=0.25, sleep=0, run.order.file=NA,max.mz.diff=10,max.rt.diff=300, tstatistic.thresh=3, num_replicates=2,subs=NA, mz.tolerance.dbmatch=5, adduct.list=c("M+H"),cormethod="spearman")
{
        ############################################
        #1) Align profiles using the cdf.to.ftr wrapper function in apLCMS
	 if(is.na(XCMS.outloc)==TRUE)
        {
                stop("Undefined value for parameter, XCMS.outloc. Please define the XCMS output location.")

        }
         if(is.na(xMSanalyzer.outloc)==TRUE)
        {
                stop("Undefined value for parameter, xMSanalyzer.outloc. Please define the xMSanalyzer output location.")

        }


        if(is.na(cdfloc)==FALSE)
        {
                setwd(cdfloc)
                if(is.na(XCMS.outloc)==FALSE)
                {
                        XCMS.align(cdfloc, XCMS.outloc,step.list, mz.diff.list, sn.thresh.list, max.list, bw, minfrac, minsamp, mzwid, sleep, run.order.file,subs)
                       
                }
                else
                {
                        stop("Undefined value for parameter, XCMS.outloc. Please define the output location.")
                }
        }
	dir.create(XCMS.outloc,showWarnings=FALSE)
	dir.create(xMSanalyzer.outloc,showWarnings=FALSE)
        {
                #stop("Undefined value for parameter, cdfloc. Please enter path of the folder where the CDF files to be processed are located.")
                #change location to the output folder
                setwd(XCMS.outloc)
                alignmentresults<-list.files(XCMS.outloc, "*.txt")
                
                if(length(alignmentresults)>0)
                {
                          curdata_dim={}
                          data_rpd=new("list")
                          if(num_replicates==2)
                          {
                                  fileroot="PID"
                          }
                          else
                          {
                                  if(num_replicates>2)
                                  {
                                          fileroot="CV"
                                  }
                                  else
                                  {
                                          fileroot=""
                                  }
                          }
                          for(i in 1:length(alignmentresults))
                           {
				  print(paste("******Evaluating XCMS results at parameter setting ",i,"*******",sep=""))

                                  ############################################
                                  #2)Calculate pairwise correlation coefficients
                                  file_name=sapply(strsplit(alignmentresults[i],".txt"),head)
                                  curdata=read.table(paste(XCMS.outloc,"/",alignmentresults[i],sep=""), header=TRUE)
                                  curdata=as.data.frame(curdata)
                                  cnames=colnames(curdata)
                                  cnames[1]="mz"
                                  cnames[4]="time"      
                                  colnames(curdata)=cnames

                                  #curdata=check.mz.in.replicates(curdata)
                                  if(num_replicates>1)
                                  {
                                          print("**calculating pairwise ",cormethod," correlation**")
                                          
					rsqres<-evaluate.Samples(curdata, num_replicates, alignment.tool="XCMS", cormethod=cormethod)

							rsqres<-as.data.frame(rsqres)
							snames<-colnames(curdata[,-c(1:8)])
							snames_1<-snames[seq(1,length(snames),num_replicates)]
							rownames(rsqres)<-snames_1
							pcor_outfile=paste(xMSanalyzer.outloc,"/",file_name,"_sampleassessment_usingallfeatures.txt",sep="")
							write.table(rsqres, pcor_outfile,sep="\t",row.names=TRUE)
                                     
                                  }
				  else
				  {
					  print("**skipping sample evaluataion as only one replicate is present**")
				  }
                                  #############################################
                                  ############################################
                                  #3) Calculate Percent Intensity Difference or CV

                                  if(num_replicates>1)
                                  {
				  
				  
					  if(num_replicates>2)
								{
									bad_samples<-which(rsqres$meanCorrelation<samp.filt.thresh)
								}else
								{
									bad_samples<-which(rsqres$Correlation<samp.filt.thresh)
								}
								
								if(length(bad_samples)>0){
								bad_sample_names<-snames_1[bad_samples]
								
								feat.eval.outfile=paste(xMSanalyzer.outloc,"/",file_name,"_badsamples_at_cor",samp.filt.thresh,".txt",sep="")
								bad_sample_names<-as.data.frame(bad_sample_names)
								colnames(bad_sample_names)<-paste("Samples with correlation between technical replicates <", samp.filt.thresh,sep="")
								write.table(bad_sample_names, file=feat.eval.outfile,sep="\t", row.names=FALSE)
								}
								
								bad_list={}
								if(length(bad_samples)>0){
									for(n1 in 1:length(bad_samples))
									{	
										if(bad_samples[n1]>1)
										{
											bad_samples[n1]=bad_samples[n1]+(bad_samples[n1]-1)*(num_replicates-1)
										}
											
									}
									for(n1 in 1:num_replicates)
									{
										bad_list<-c(bad_list,(bad_samples+n1-1))
									}
									bad_list<-bad_list[order(bad_list)]
									if(i>1){
										common_bad_list<-which(bad_list%in%parent_bad_list)
										curdata<-curdata[,-c(bad_list[common_bad_list]+8)]
										parent_bad_list<-bad_list[common_bad_list]
									}
									else{
									    curdata<-curdata[,-c(bad_list+8)]
									    parent_bad_list<-bad_list

									}
								}
								
								feat.eval.result=evaluate.Features(curdata, num_replicates,alignment.tool,impute.bool)
								cnames=colnames(feat.eval.result)
								feat.eval.result<-apply(feat.eval.result,2,as.numeric)
								feat.eval.result<-as.data.frame(feat.eval.result)
								feat.eval.result.mat=cbind(curdata[,c(1:8)],feat.eval.result)  
								feat.eval.outfile=paste(xMSanalyzer.outloc,"/",file_name,"cor",samp.filt.thresh,fileroot,"featureassessment.txt",sep="")					  
								#write results
								write.table(feat.eval.result.mat, feat.eval.outfile,sep="\t", row.names=FALSE)
								
								curdata<-curdata[which(as.numeric(feat.eval.result$median)<=feat.filt.thresh),]
								
								feat.eval.outfile=paste(xMSanalyzer.outloc,"/",file_name,"cor",samp.filt.thresh,fileroot,feat.filt.thresh,"_filtereddata.txt",sep="")	
								
								#write results
								write.table(curdata, feat.eval.outfile,sep="\t", row.names=FALSE)
								  
                                  }
				  else
                                  {
                                          print("*********skipping feature evaluataion as only one replicate is present******")
                                  }

                                  #############################################
                                  
                          }
                          ###########################################
                          #4) Merge two or more parameter settings
                          print("*************merging features detected at different parameter settings********************")
                          union_list=new("list")
                          num_pairs=1
                          finalres={}
                          rnames={}
		          data_rpd=new("list")
                          for(i in 1:length(alignmentresults))
                          {
                                  file_name=sapply(strsplit(alignmentresults[i],".txt"),head)
                                
                                  feat.eval.file=paste(xMSanalyzer.outloc,"/",file_name,"cor",samp.filt.thresh,fileroot,feat.filt.thresh,"filtereddata.txt",sep="")	
				  data_rpd[[i]]=read.table(feat.eval.file,header=TRUE)
                                  a1=sapply(strsplit(as.character(alignmentresults[i]), "\\_thresh"), head, n=2)[2]
                                  a2=sapply(strsplit(as.character(a1), "\\_"), head, n=2)
                                  threshval=as.numeric(a2[1])
                                  stepval=sapply(strsplit(as.character(a2[2]), "\\."), head, n=2)[2]
                                  stepval=paste(".",stepval,sep="")
                                  stepval=as.numeric(stepval)
                                  a1=sapply(strsplit(as.character(alignmentresults[i]), "\\_mzdiff"), head, n=2)[2]
                                  a2=sapply(strsplit(as.character(a1[1]), "\\_max"), head, n=2)
                                  mzdiff=as.numeric(a2[1])
                                  a2=sapply(strsplit(as.character(a2[2]), "\\.txt"), head, n=2)
                                  max=as.numeric(a2[1])
                                  p1=paste(threshval,"_",stepval,"_",mzdiff,"_",max,sep="")

                                  for(j in i:length(alignmentresults))
                                  {
                                      if(i!=j)
				      {
				          file_name=sapply(strsplit(alignmentresults[j],".txt"),head)
					  feat.eval.file=paste(xMSanalyzer.outloc,"/",file_name,"cor",samp.filt.thresh,fileroot,feat.filt.thresh,"filtereddata.txt",sep="")	
	                                  data_rpd[[j]]=read.table(feat.eval.file,header=TRUE)
                                          
                                          a1=sapply(strsplit(as.character(alignmentresults[j]), "\\_thresh"), head, n=2)[2]
                                          a2=sapply(strsplit(as.character(a1), "\\_"), head, n=2)
                                          threshval=as.numeric(a2[1])
                                          stepval=sapply(strsplit(as.character(a2[2]), "\\."), head, n=2)[2]
                                          stepval=paste(".",stepval,sep="")
                                          stepval=as.numeric(stepval)
                                          a1=sapply(strsplit(as.character(alignmentresults[j]), "\\_mzdiff"), head, n=2)[2]
                                          a2=sapply(strsplit(as.character(a1[1]), "\\_max"), head, n=2)
                                          mzdiff=as.numeric(a2[1])
                                          a2=sapply(strsplit(as.character(a2[2]), "\\.txt"), head, n=2)
                                          max=as.numeric(a2[1])
                                          p2=paste(threshval,"_",stepval,"_",mzdiff,"_",max,sep="")
                                         
                                          if(i!=j)
                                          {
                                                  p1_p2=paste(p1,"_U_",p2,sep="")
                                          }
                                          else
                                          {
                                                  p1_p2=p1
                                          }
                                          union_list[[num_pairs]]=merge.Results(data_rpd[[i]],data_rpd[[j]],max.mz.diff,max.rt.diff, tstatistic.thresh,alignment.tool="XCMS")
                                          curres={}
                                          curres=cbind(curres, dim(union_list[[num_pairs]])[1])
                                          curres=cbind(curres, mean(union_list[[num_pairs]]$median))
                                          rnames=rbind(rnames, p1_p2)
                                          finalres=rbind(finalres,curres)
                                          finalname=paste("XCMS_feature_list_at_", p1_p2,".txt",sep="")

					  merge.res.colnames=colnames(union_list[[num_pairs]])                                          
					  merge.res.colnames[(length(merge.res.colnames)-5):length(merge.res.colnames)]=paste(merge.res.colnames[(length(merge.res.colnames)-5):length(merge.res.colnames)],".",fileroot,sep="")

                                          colnames(union_list[[num_pairs]])=merge.res.colnames


                                          #Output merge results
                                          write.table(union_list[[num_pairs]],file=paste(xMSanalyzer.outloc,"/",finalname,sep=""), sep="\t",row.names=FALSE)
					  metlin.res={}
                                          kegg.res={}
					 #length(union_list[[num_pairs]]$mz
					 if(is.na(adduct.list)==FALSE){
					  print("*********Mapping m/z values to known metabolites using METLIN*********")
					 
                                          metlin.res<-feat.batch.annotation(union_list[[num_pairs]],mz.tolerance.dbmatch,adduct.list,xMSanalyzer.outloc)
                                         }
				
					  num_pairs=num_pairs+1
                                     }
				  }
                          }
                          finalres<-as.data.frame(finalres)
                          rownames(finalres)<-rnames
			  finalres<-cbind(rnames,finalres)	
			  finalres<-as.data.frame(finalres)
			  if(fileroot=="PID")
			  {
			  	colnames(finalres)<-c("Parameter Combination", "Number of Features", "median PID between sample replicates")
		          }
			  else
			  {
				if(fileroot=="CV")
				{
					colnames(finalres)<-c("Parameter Combination", "Number of Features", "median CV between sample replicates")
			  	}
			  }
                          write.table(finalres,file=paste(xMSanalyzer.outloc,"/merge_summary.txt",sep=""), sep="\t", row.names=FALSE)
			  print("*************Processing complete**********")

			  #print("*********Characterizing metabolites*********")
		}             
                else
                {
                        stop(paste("No files exist in",XCMS.outloc, "Please check the input value for cdfloc", sep=""))
                }
                    
                
                
        }
}
                                           
############################################################
xMSwrapper<-function()
{
    print("Usage: xMSwrapper.apLCMS or xMSwrapper.XCMS")
}






      

                                

