.packageName <- "RMAGEML"
.packageName <- "RMAGEML"


##############################################################################
##                                                                          ##
## This is an R Package for handling MAGE-ML documents in Bioconductor.     ##
##                                                                          ##
##@Authors  Steffen Durinck, Joke Allemeersch, Vincent Carey                ##
## ESAT-SCD KULeuven                                                        ##
##                                                                          ##
##############################################################################


.First.lib <- function(libname, pkgname, where) {
  dir1<-system.file("classes", package="RMAGEML")
  dir2<-system.file("jaxp", package="RMAGEML")
  dir3<-system.file("MAGEstk.jar", package="RMAGEML")
  cpvec <- c(dir1,paste(dir2,"lib/endorsed/xercesImpl.jar", sep="/" ),dir3)
  
  if (as.numeric(R.Version()$major) < 2 &&  as.numeric(R.Version()$minor) < 9){
     require(SJava)
     require(marray)
     require(limma)
 
    if (as.numeric(package.description("SJava", fields="Version")) < .67) .JavaInit(javaConfig(cpvec))
    else .JavaInit(classPath=cpvec, options ="-Xmx256m")
  }
  else{
    if (as.numeric(packageDescription("SJava")$Version) < .67) .JavaInit(javaConfig(cpvec))
    else .JavaInit(classPath=cpvec, options = "-Xmx256m")
  }

  if(.Platform$OS.type == "windows" && require(Biobase) && interactive()
     && .Platform$GUI ==  "Rgui"){
    addVigs2WinMenu("RMAGEML")
  }
}


importMAGEML <- function( directory = ".", package = "marray",DED = "none", QTD = "none", name.Rf="none", name.Rb="none", name.Gf="none" ,name.Gb = "none"){
 if ( package != "marray" && package !="limma" ){
   writeLines( "The current MAGEML package only imports MAGEML to the marray and limma packages of BioConductor" )
 }
 if( package == "marray" ){

   writeLines( "parsing MAGEML files" )
   mageOM <- .JNew( "MAGEML.RMAGESTK",directory , .convert = TRUE)
   Gnames <- getGnames( mageOM, DED )
   Layout <- getArrayLayout( mageOM )
   writeLines( "making Layout and Gnames objects" )
   raw <- makeMarrayRaw( mageOM, Layout,Gnames,directory, DED = DED, QTD = QTD, name.Rf = name.Rf, name.Rb = name.Rb, name.Gf=name.Gf ,name.Gb = name.Gb )
   return(raw)
 }
 if (package == "limma"){
   writeLines( "parsing MAGEML files" )
   mageOM <- .JNew( "MAGEML.RMAGESTK",directory, .convert = TRUE )
   genes <- getArrayLayoutLimma( mageOM )
   RG <- makeRG( mageOM = mageOM, genes = genes, directory = directory,DED = DED, QTD = QTD, name.Rf = name.Rf, name.Rb = name.Rb, name.Gf = name.Gf ,name.Gb = name.Gb)
   return(RG)
 }
}


####################################################
#
#import MAGEML to marray package
#
####################################################


getGnames <- function( mageOM , DED = "none"){
  
  succes <- .Java(mageOM, "importFeatures","marray", DED, .convert = TRUE)
  if(!succes){
    stop("import of features failed")
  }
  databaseEntry <- .Java(mageOM,"getBioSequenceID", .convert = TRUE)
  names <- .Java(mageOM,"getBioSequenceNames", .convert = TRUE)
  db <- .Java(mageOM,"getBioSeqDB", .convert = TRUE)
  mInfo <- new( "marrayInfo" )
  maInfo <- as.data.frame( databaseEntry )
  names(maInfo) <- c( "Identification" )
  mInfo@maLabels <- names
  mInfo@maInfo <- maInfo
  mInfo@maNotes <- c( paste("Identifiers refer to database:",db) )
  return( mInfo )
}

getArrayLayout<-function(mageOM){
  layout <-.Java(mageOM,"getGridDimensions", .convert = TRUE)
  ngr <- layout[4]
  ngc <- layout[3]
  nsr <- layout[2]
  nsc <- layout[1]
  nspots <- as.integer( ngr ) * as.integer( ngc ) * as.integer( nsr ) * as.integer( nsc )

  mlayout <- new("marrayLayout", maNgr = as.integer( ngr ),
                 maNgc = as.integer( ngc ),
                 maNsr = as.integer( nsr ),
                 maNsc = as.integer( nsc ),
                 maNspots = nspots,maNotes="")
  return( mlayout )
}

makeMarrayRaw <- function(mageOM, layout, gnames, directory = ".", DED="none", QTD = "none", name.Rf="none", name.Rb="none", name.Gf="none" ,name.Gb = "none"){
 quantitationTypes<-.Java(mageOM,"selectQTypes", QTD, name.Rf, name.Rb, name.Gf,name.Gb, .convert = TRUE)
 fileNames<-.Java(mageOM,"getExternalData","marray", DED, .convert = TRUE)
 fullnames<-file.path(directory,fileNames)
 Gf<-Gb<-Rf<-Rb<-W<- NULL
 names(Gb)<-names(Rf)<-names(Rb)<-names(W)<-NULL
 fileLabels<-NULL
 for ( f in fileNames ){
    writeLines( paste("Reading ",f) )
    dat<-read.table(file=file.path(directory,f),header=FALSE,sep="\t")
    Gf<-cbind(Gf,as.numeric(dat[[quantitationTypes[1]]]))
    Gb<-cbind(Gb,as.numeric(dat[[quantitationTypes[2]]]))
    Rf<-cbind(Rf,as.numeric(dat[[quantitationTypes[3]]]))
    Rb<-cbind(Rb,as.numeric(dat[[quantitationTypes[4]]]))
  }
  targets<-.Java(mageOM,"getTargets", .convert = TRUE);
  nrrow<-length( targets )
  TargetRG<-matrix(data = NA, nrow = nrrow, ncol = 2)
  colnames( TargetRG )<-c("Cy3","Cy5")
  TargetRG<-as.data.frame( TargetRG )
  rownames <- rep("U",nrrow)
  for (i in 1:nrrow){

     hybInfo<-strsplit(targets[i],"\\$")
     if (hybInfo[[1]][2]=="cy3" || hybInfo[[1]][2]=="Cy3"){
        TargetRG[i,1] <- hybInfo[[1]][1]
     }
     if (hybInfo[[1]][2]=="cy5" || hybInfo[[1]][2]=="Cy5"){
        TargetRG[i,2]<-hybInfo[[1]][1]
     }
     if (hybInfo[[1]][4]=="cy3" || hybInfo[[1]][4]=="Cy3"){
        TargetRG[i,1] <- hybInfo[[1]][3]
     }
     if (hybInfo[[1]][4]=="cy5" || hybInfo[[1]][4]=="Cy5"){
         TargetRG[i,2]<-hybInfo[[1]][3]
     }
   }
   target<-new("marrayInfo",maLabels=fileNames,maInfo=TargetRG,maNotes="Description of the targets")
   mraw<-new("marrayRaw", maRf=Rf, maRb=Rb, maGf=Gf, maGb=Gb, maLayout=layout, maGnames=gnames, maTargets=target)
 return( mraw )
}

####################################################
#
#import MAGEML to limma package
#
####################################################

getArrayLayoutLimma <- function(mageOM, DED = "none"){
  .Java(mageOM, "importFeatures","limma", DED, .convert = TRUE)
  ID <- .Java(mageOM,"getBioSequenceID", .convert = TRUE)
  NAME <- .Java(mageOM,"getBioSequenceNames", .convert = TRUE)
  ROW <- as.numeric(.Java(mageOM,"getRows", .convert = TRUE))
  COLUMN <- as.numeric(.Java(mageOM,"getColumns", .convert = TRUE))
  BLOCK <- as.numeric(.Java(mageOM,"getZones", .convert = TRUE))
  genes <- as.data.frame(list(Block=BLOCK,Row=ROW,Column=COLUMN,ID=ID,Name= NAME))
  return( genes )

}

makeRG <- function(mageOM,genes, directory = ".", QTD = "none", DED="none", name.Rf="none", name.Rb="none", name.Gf="none" ,name.Gb = "none"){

 ngenes <- length( genes$ID )
 quantitationTypes<-.Java(mageOM,"selectQTypes", QTD = QTD, name.Rf=name.Rf, name.Rb=name.Rb, name.Gf=name.Gf ,name.Gb = name.Gb, .convert = TRUE )
 fileNames<-.Java(mageOM,"getExternalData","limma",DED, .convert = TRUE)
 nslides <- length( fileNames )
 fullnames<-file.path(directory,fileNames)
 Gf<-Gb<-Rf<-Rb<-W<- NULL
 names(Gb)<-names(Rf)<-names(Rb)<-names(W)<-NULL
 fileLabels<-NULL
 Y <- matrix(0,ngenes,nslides)
 colnames(Y) <- fileNames
 RG <- list(R=Y,G=Y,Rb=Y,Gb=Y, genes=genes)

 for (i in 1: nslides){
    writeLines(paste("Reading ",fileNames[i]))
    dat<-read.table(file=file.path(directory,fileNames[i]),header=FALSE,sep="\t")
    RG$G[,i]<-as.numeric(dat[,quantitationTypes[1]])
    RG$Gb[,i]<-as.numeric(dat[,quantitationTypes[2]])
    RG$R[,i]<-as.numeric(dat[,quantitationTypes[3]])
    RG$Rb[,i]<-as.numeric(dat[,quantitationTypes[4]])
  }

 RGL <- new("RGList", RG)
 return( RGL )

}


###############################################
#
#Import the object model and obtain a reference
#to it.
#
###############################################


importMAGEOM<-function(directory = "."){
  writeLines("parsing MAGEML files")
  mageOM<-.JNew("MAGEML.RMAGESTK",directory, .convert = TRUE)
  return( mageOM )
}

################################################
#
#writing MAGEML from BioConductor
#
#addNormToMAGEML is still work in progress
#and is not yet functional enough to be employed
#
################################################

addNormToMAGEML <- function(mageOM = NULL, norm = NULL, outputDirectory = ".", externalDataFiles = NULL, protocolID = NULL, protocol = "none", date ="NA", qtID = NULL, qtName = NULL, qtScale = NULL, qtDataType = NULL, qtDimID = NULL,transformationID = NULL, DED = "none", BADIDs = NULL, derivedBioAssayIDs = NULL, derivedBioAssayDataIDs = NULL){
  
  if ( is.null( externalDataFiles )){ #check as well if they end with txt!!
    stop("No filenames for output derivedFile found, please read the documentation and specify using parameter derivedFiles")
  }

  if ( is.null( protocolID )){
    stop("No protocol idenitifier found, please read the documentation and  specify using parameter protocolID")
  }
  
  if ( is.null( transformationID )){
    stop("No transformation idenitifier found, please read the documentation and  specify using parameter transformationID")
  }

  if ( is.null( protocol )){
    stop("No protocol found, please read the documentation and specify using parameter protocol")
  }

  if ( is.null( qtID )){
    stop("No QuantitationTypes identifiers found, please read the documentation and specify using parameter qtIDs")
  }

  if ( is.null( qtName ) && !is.null( qtID )){
    warning("No QuantitationTypes names found, continuing without names for QuantitationTypes")
  }

  if ( is.null( qtScale )){
    stop("No QuantitationType scales found, please read the documentation and specify using parameter qtScales")
  }

  if ( is.null( qtDataType )){
    stop("No QuantitationType DataTypes found, please read the documentation and specify using parameter qtDataTypes")
  }

  if ( is.null( qtDimID )){
    stop("No QuantitationTypeDimension identifier found, please read the documentation and specify using parameter qtDimID")
  }

  if ( is.null( BADIDs )){
    stop("No BioAssayDimension identifier found, please read the documentation and specify using parameter BAD")
  }

  if ( is.null( derivedBioAssayIDs )){
    stop("No derivedBioAssay identifier found, please read the documentation and specify using parameter derivedBioAssayID")
  }


  if ( is.null( derivedBioAssayDataIDs )){
    stop("No derivedBioAssayData identifier found, please read the documentation and specify using parameter derivedBioAssayDataIDs")
  }

  clas <- class( norm )
  if( attributes( clas )$package == "marray"){
    if( clas[1] == "marrayNorm" ){

      numberOfHybs <- length( norm@maM[1,] )
      numberOfFeatures <- length( norm@maM[,1] )
      featuresInDED <- .Java(mageOM, "getSizeDED", DED, .convert = TRUE)

      if (numberOfFeatures != featuresInDED){
        stop("MAGEML update failure: selected DED has different size than number of features present in update files, please ensure the number of features is the same")
      }

      if( length( externalDataFiles ) != numberOfHybs ){
        stop( "number of files in 'files' list should equal number of columns in maM slot of norm object" )
      }

      #Add stuff to MAGEML files

      qtdimsize <- as.integer(1)
      .Java(mageOM, "createNewQTDim", qtdimsize, .convert = TRUE)
      .Java (mageOM, "addQuantitationTypeInfo", qtID, qtName, qtScale, qtDataType, .convert = TRUE)

      for (i in 1: length(externalDataFiles)){
        BAD <- BADIDs[ i ]
        derivedBioAssayID <- derivedBioAssayIDs[ i ]
        derivedBioAssayDataID <- derivedBioAssayDataIDs[ i ]
        file <- externalDataFiles[ i ]
        sizeMBA <- as.integer(1)
        .Java(mageOM, "createNewMBASet", sizeMBA, .convert = TRUE)
        mbaVal <- as.integer(i)  #we expect here that the normalized object was created from the entire experiment as it was imported
        .Java( mageOM, "setMBA",  mbaVal, .convert = TRUE)
        .Java( mageOM, "updateMAGEML", file, protocolID, protocol, date, qtDimID, transformationID, numberOfFeatures, DED, BAD, derivedBioAssayID, derivedBioAssayDataID, .convert = TRUE)

      }                                   #write the external data files

      for( i in 1:numberOfHybs ){
        writeLines(paste("writing ExternalData file:", externalDataFiles[i], sep = " "))
        write.table( norm@maM[,i], file = paste(outputDirectory,externalDataFiles[i],sep = "/"),sep = "\t", col.names = FALSE, row.names = FALSE, quote = FALSE )
      }
    }
    else{
      stop( "MAGEML write error: your marray object was not of class marrayNorm" )
    }
  }

  else{
    if( attributes( clas )$package == "limma" ){

      numberOfHybs <- length( norm$M[1,] )
      numberOfFeatures <- length( norm$M[,1] )
      featuresInDED <- .Java(mageOM, "getSizeDED", DED, .convert = TRUE)

      if (numberOfFeatures != featuresInDED){
        stop("MAGEML update failure: selected DED has different size than number of features present in update files, please ensure the number of features is the same")
      }

      if( length( externalDataFiles ) != numberOfHybs )
        stop( "number of files in 'files' list should equal number of columns in maM slot of norm object" )

      #Add stuff to MAGEML files

      qtdimsize <- as.integer(1)
      .Java(mageOM, "createNewQTDim", qtdimsize, .convert = TRUE)

      .Java (mageOM, "addQuantitationTypeInfo", qtID, qtName, qtScale, qtDataType, .convert = TRUE)
      for (i in 1: length(externalDataFiles)){
        BAD <- BADIDs[ i ]
        derivedBioAssayID <- derivedBioAssayIDs[ i ]
        derivedBioAssayDataID <- derivedBioAssayDataIDs[ i ]
        file <- externalDataFiles[ i ]
        sizeMBA <- as.integer(1)
        .Java(mageOM, "createNewMBASet", sizeMBA, .convert = TRUE)
        mbaVal <- as.integer(i)  #we expect here that the normalized object was created from the entire experiment as it was imported
        .Java( mageOM, "setMBA",  mbaVal, .convert = TRUE) 
        .Java( mageOM, "updateMAGEML", file, protocolID, protocol, date, qtDimID, transformationID, numberOfFeatures, DED, BAD, derivedBioAssayID, derivedBioAssayDataID, .convert = TRUE)
    
      }                                   #write the external data files

      for( i in 1:numberOfHybs ){
        writeLines(paste("writing ExternalData file:", externalDataFiles[i], sep = " "))
        write.table( norm$M[,i], file = paste(outputDirectory,externalDataFiles[i],sep = "/"),sep = "\t", col.names = FALSE, row.names = FALSE, quote = FALSE )
      }
    }
    else{
      warning( "MAGEML write error: your R object was not a limma or marray object" )
    }
  }
}


########################################
#
#Adding a new derived data file to
#an existing document
#NOTE: this method is more general than
#addNormToMAGEML
#
########################################

addDerivedData <- function(mageOM = NULL, data = NULL, outputDirectory = ".", externalDataFile = NULL, protocolID = NULL, protocol = "none", date = "NA", qtIDs = NULL, qtNames = NULL, qtScales = NULL, qtDataTypes = NULL, qtDimID = NULL, transformationID = NULL, DED = "none", BAD = NULL, derivedBioAssayID = NULL, derivedBioAssayDataID = NULL, MBA = NULL ){
  
  numberOfFeatures <- 0
                                        #some checks to see if the necessary parameters are present and valid

  if ( is.null( externalDataFile )){ #check as well if they end with txt!!
    stop("No filenames for output derivedFile found, please read the documentation and specify using parameter derivedFiles")
  }

  if ( is.null( protocolID )){
    stop("No protocol idenitifier found, please read the documentation and  specify using parameter protocolID")
  }
  
  if ( is.null( transformationID )){
    stop("No transformation idenitifier found, please read the documentation and  specify using parameter protocolID")
  }
  if ( is.null( protocol )){
    stop("No protocol found, please read the documentation and specify using parameter protocol")
  }

  if ( is.null( qtIDs )){
    stop("No QuantitationTypes identifiers found, please read the documentation and specify using parameter qtIDs")
  }

  if ( is.null( qtNames ) && !is.null( qtIDs )){
    warning("No QuantitationTypes names found, continuing without names for QuantitationTypes")
  }

  if ( is.null( qtScales )){
    stop("No QuantitationType scales found, please read the documentation and specify using parameter qtScales")
  }

  if ( is.null( qtDataTypes )){
    stop("No QuantitationType DataTypes found, please read the documentation and specify using parameter qtDataTypes")
  }

  if ( is.null( qtDimID )){
    stop("No QuantitationTypeDimension identifier found, please read the documentation and specify using parameter qtDimID")
  }

  if ( is.null( BAD )){
    stop("No BioAssayDimension identifier found, please read the documentation and specify using parameter BAD")
  }

  if ( is.null( derivedBioAssayID )){
    stop("No derivedBioAssay identifier found, please read the documentation and specify using parameter derivedBioAssayID")
  }


  if ( is.null( derivedBioAssayDataID )){
    stop("No derivedBioAssayData identifier found, please read the documentation and specify using parameter derivedBioAssayDataIDs")
  }

  if (is(data, "numeric") || is(data, "matrix")) {
    if(is(data, "numeric")) {
      numberOfFeatures <- length( data )
    }
    if(is(data, "matrix")) {
      numberOfFeatures <- length( data[,1] )
    }

    featuresInDED <- .Java(mageOM, "getSizeDED", DED, .convert = TRUE)

    if (numberOfFeatures != featuresInDED){
      stop("MAGEML update failure: selected DED has different size than number of features present in update files, please ensure the number of features is the same")
    }
                                        #Add stuff to MAGEML files
    sizeQTDim <- length(qtIDs)
    .Java(mageOM, "createNewQTDim", sizeQTDim, .convert = TRUE)

    for( i in 1: length(qtIDs)){
      qtID <- qtIDs[ i ]
      qtName <- qtNames[ i ]
      qtScale <- qtScales[ i ]
      qtDataType <- qtDataTypes[ i ]
      .Java (mageOM, "addQuantitationTypeInfo", qtID, qtName, qtScale, qtDataType, .convert = TRUE)
    }

    sizeMBA <- length( MBA )
    .Java(mageOM, "createNewMBASet", sizeMBA, .convert = TRUE)

    for( i in 1:length( MBA )){
      mbaVal <- as.integer(MBA[i])
      .Java( mageOM, "setMBA",  mbaVal, .convert = TRUE)
    }
    
    .Java( mageOM, "updateMAGEML", externalDataFile, protocolID, protocol, date,  qtDimID, transformationID, numberOfFeatures, DED, BAD, derivedBioAssayID, derivedBioAssayDataID, .convert = TRUE)
    
                                        #write the external data files

    writeLines( paste( "writing ExternalData file:", externalDataFile, sep = " " ))
    write.table( data, file = paste( outputDirectory, externalDataFile, sep = "/" ), sep = "\t", col.names = FALSE, row.names = FALSE, quote = FALSE )
  }
  else{
    warning("update not supported for this data type, use addNormToMAGEML() if you want to add limma or marray object to MAGEML or create a matrix with the appropriate values first and try this function again")
  }
}


######################################################
#
#After updating MAGEML this function can be used to
#create a real MAGEML document
#
#####################################################

writeMAGEML <- function ( mageOM = NULL, directory = ".", file = NULL){

  magemlOutFile <- paste( directory, file, sep = "/" )
  writeLines( paste( "writing MAGEML file:", magemlOutFile, sep=" " ))
  .Java( mageOM,"writeMAGEML", file, directory, .convert = TRUE)

}

#########################################################
#
#Functions to get information other
#than the information needed to build raw
#object to normalise.
#
#########################################################

getQuantitationTypes <- function ( mageOM = NULL, QTD = "none"){
  
   if(is.null(mageOM)){
    stop("RMAGEML Error:  Import MAGE Object Model first using the function importMAGEOM")
  }
 
  quantitationTypes <- ""
  quantitationTypes <- .Java(mageOM, "getQuantitationTypes", QTD, .convert = TRUE )
  return( quantitationTypes )

}



#retrieve identifier of organization

getOrganization <- function ( mageOM = NULL ){

  if(is.null(mageOM)){
    stop("RMAGEML Error:  Import MAGE Object Model first using the function importMAGEOM")
  }
 
 organization <- .Java( mageOM, "getOrganization", .convert = TRUE )
 return( organization )
}


#retrieve number of features for a specific Design Element Dimension

getNumberOfFeatures <- function ( mageOM = NULL, DED = "none"){

   if(is.null(mageOM)){
    stop("RMAGEML Error:  Import MAGE Object Model first using the function importMAGEOM")
  }
  featuresInDED <- .Java(mageOM, "getSizeDED", DED, .convert = TRUE)
  return( featuresInDED )
}


#retieve array accession No of arrays that were used

getArrayID <- function( mageOM = NULL ){
  
  if(is.null(mageOM)){
    stop("RMAGEML Error:  Import MAGE Object Model first using the function importMAGEOM")
  }
  arrayIDs <- .Java(mageOM, "getArrayIDs", .convert = TRUE)
  return(arrayIDs)
  
}

#retrieve Description of a QuantitationType

getQTypeDescription <- function(mageOM = NULL, QTypeID = ""){
  
  if(is.null(mageOM)){
    stop("RMAGEML Error:  Import MAGE Object Model first using the function importMAGEOM")
  }
  description = .Java(mageOM, "getQuantitationTypeDescription", QTypeID, .convert = TRUE)
  return(description)
}
