########################################################
## Copyright (c) 2005
## University of Washington
## Licensed under the terms set forth by University of
## Washington. If you did not sign such a license, you
## are using this software/code illegally and you do not
## have permission to use, modify, or redistribute
## this or any files in this software package.
##
## File: odpui.r
## Contains functions for EDGE GUI for ODP options.
########################################################

source("odp.r")

#########################################################################
## Global variable with formatting settings for the Results window
#########################################################################
genedisplay <- list(
	    colLeft = 3,
	    geneNameMaxLength = 12,
	    geneNameColWidth = 15,
	    pvalColWidth = 10,
	    qvalColWidth = 10,
	    geneNameHeader = "Gene Name",
	    pvalHeader = "P-Value",
	    qvalHeader = "Q-Value",
            rankHeader = "Rank",
            maxSig = 1000
	    )


#########################################################################
## Creates the differential expression results frame
#########################################################################
getdiffexresultsframe.func <- function(parentwindow, data, geneNames, printmsg=function(...) stop("printmsg not defined in getdiffexresultsframe()")) {

  if(!is.matrix(data))
    stop("data is not a matrix")

  porq.var <- tclVar("q")
  lambda.var <- tclVar("1")
  pi0.var <- tclVar("0")
  to1.var <- tclVar("0.95")
  by1.var <- tclVar("0.05")
  cutoff.var <- tclVar("0.1")
  single.var <- tclVar("0")
  from1.var <- tclVar("0.0")
  diffexgenes.var <- tclVar(paste(0,"Genes Called Significant"))
  uid.var <- tclVar("0")
  showsig.var <- tclVar("1")

  p <- diffexresults$p
  if(is.null(p))
    stop("p is null")

  estat <- diffexresults$estat

  error.handler <- function(err) {
    printmsg(paste("\nError:", err$message))
  }
  
  ## This function disables the appropriate lambda entries.
  lambda.func <- function(...) {
    tryCatch(lambda.func.int(...)
     , error=error.handler)
  }
  
  lambda.func.int <- function() {
     if(tclvalue(lambda.var) == 1) {
       tkconfigure(from1.ety, state = "normal")
       tkconfigure(to1.ety, state = "normal")
       tkconfigure(by1.ety, state = "normal")
       tkconfigure(single.ety, state = "disabled")
     } else {
       tkconfigure(from1.ety, state = "disabled")
       tkconfigure(to1.ety, state = "disabled")
       tkconfigure(by1.ety, state = "disabled")
       tkconfigure(single.ety, state = "normal")
     }
  }

  ## This function populates the gene list.
  populate.genelist <- function(...) {
    tryCatch(populate.genelist.int(...), error=error.handler)
  }
  
  populate.genelist.int <- function(diffexresults, showsig) {
    ## Remove any genes from the differential expression list.
    tkdelete(diffexgenes.list, "0", "end")
    
    if(showsig && is.valid.number(diffexresults$nsig))
    {
      ngenes <- check.not.nullna(diffexresults$nsig)
      genesig.ord <- check.not.nullna(diffexresults$genesig.ord)
      genedisp.ord <- substr(genesig.ord,1,genedisplay$geneNameMaxLength)
      p.ord <- check.not.nullna(diffexresults$psig.ord)
      q.ord <- check.not.nullna(diffexresults$qsig.ord)
    }
    else
    {
      ord <- check.not.nullna(diffexresults$all.ord)
      geneNames.ord <- check.not.nullna(diffexresults$geneNames.ord)
      check.not.nullna(data)
      ngenes <- nrow(data)
      check.not.nullna(geneNames)
      genedisp.ord <- substr(geneNames.ord, 1,
                             check.not.nullna(genedisplay$geneNameMaxLength))
      p.ord <- check.not.nullna(diffexresults$p)[ord]
      q.ord <- check.not.nullna(diffexresults$q)[ord]
    }
    if(ngenes > 0)
    {
      for(i in 1:ngenes){
        pstr = format(round(p.ord[i], 6), nsmall = 6)
        qstr = format(round(q.ord[i], 6), nsmall = 6)
        tkinsert(diffexgenes.list, "end", 
                 paste(rep.str(" ", genedisplay$colLeft), 
                       genedisp.ord[i], 
                       rep.str(" ", genedisplay$geneNameColWidth-nchar(genedisp.ord[i])),
                       pstr, 
                       rep.str(" ", genedisplay$pvalColWidth - nchar(pstr)),
                       qstr,
                       rep.str(" ", genedisplay$pvalColWidth - nchar(qstr)),
                       format(i)
                       ))
      }
      
    }
    
    if(is.valid.number(diffexresults$nsig) && diffexresults$nsig > 0){
      tclvalue(diffexgenes.var) <- paste(diffexresults$nsig,"Genes Called Significant")
    }
    else{
      tkinsert(diffexgenes.list, "end", "No significant genes under these settings")
      tclvalue(diffexgenes.var) <- paste(diffexresults$nsig,"Differentially Expressed Genes")
    }
  }

  diffexdisplay.recalc.func <- function() {
      diffexdisplay.func(first=FALSE)
    }
  
  ## This function displays results from a differential expression analysis.
  ## Arguments:
  ##   first: whether or not this is the first call to diffexdisplay() after
  ##          completing the data analysis
  diffexdisplay.func <- function(...) {
    tryCatch(diffexdisplay.func.int(...), error=error.handler)
  }
  
  diffexdisplay.func.int <- function(first=FALSE) {
    ## Set the appropriate q-value parameters. 

    porq <- as.character(tclvalue(porq.var))
    
    alpha <- as.numeric(tclvalue(cutoff.var))
    if (alpha < 0 || alpha > 1)
      stop("Cutoff value must be between 0 and 1.")
    
    if(as.numeric(tclvalue(pi0.var)) == 0)
      pi0.method <- "smoother"
    else
      pi0.method <- "bootstrap"

    lambdatype <- as.numeric(tclvalue(lambda.var))
    if(lambdatype==1){
      from1 <- as.numeric(tclvalue(from1.var))
      to1 <- as.numeric(tclvalue(to1.var))
      by1 <- as.numeric(tclvalue(by1.var))
      lambda <- seq(from1,to1,by1)
      if(sum(lambda < 0) > 0 || sum(lambda >= 1) > 0)
        stop("One or more lambda values falls outside of the range [0, 1).")
    }
    else{
      lambda <- as.numeric(tclvalue(single.var))
      if(lambda < 0 || lambda >= 1)
        stop("lambda must be in the interval [0, 1).")
    }

    ## Do we need to recalculate the q-values?
    qval.params.changed <<-
      (is.null(diffexresults$qsettings$pi0.method) ||
       diffexresults$qsettings$pi0.method != pi0.method ||
       length(diffexresults$qsettings$lambda) != length(lambda) ||
       sum(c(diffexresults$qsettings$lambda) != c(lambda)) != 0)

    qerr <- NULL
    if (qval.params.changed)
    {
      printmsg("Recalculating q-values...")
      .Tcl("update idletasks")
      results <- tryCatch(calc.qvalues(p=p,
                                       diffextype=diffexsettings$diffextype,
                                       data=data,
                                       pi0.method=pi0.method,
                                       lambda=lambda
                                       ),
                                 error=function(e) { e })
      if(class(results)[1] != "list")
      {
        qerr <- results
      }
      if (is.null(qerr))
      {
        diffexresults$qobj <<- results$qobj
        diffexresults$q <<- results$q
        diffexresults$pi0 <<- results$pi0
        
        check.not.nullna(diffexresults$qobj)
      
        tkconfigure(qplot.but, state="normal")
        ## Save the new q-value parameters
        diffexresults$qsettings$pi0.method <<- pi0.method
        diffexresults$qsettings$lambda <<- lambda
        


        
        ## Display pi0 values
        if(!is.null(results$warning)) printmsg(paste("Warning:", results$warning))
        
        pi0 <- diffexresults$pi0
        printmsg("pi0 is the estimated overall proportion of non-differentially expressed genes")
        if(length(pi0) > 1)
          {
            printmsg("pi0 for each chunk:")
            printmsg(paste(round(pi0,4), sep="", collapse=", "))
          }
        else
          printmsg(paste("pi0 =", round(pi0,4)))
      }
      else
      {
        printmsg(paste("Could not calculate q-values. Please adjust q-value settings and try RECALCULATE."))
        printmsg(paste("Message:", qerr$message))
        tkconfigure(qplot.but, state="disabled")
        diffexresults$q <<- rep(NA, nrow(data))

      }
    }
    showsig <- as.logical(as.numeric(tclvalue(showsig.var)))

    if (
        (first ||
         qval.params.changed ||
         is.null(diffexresults$qsettings$alpha) ||
         diffexresults$qsettings$alpha != alpha ||
         is.null(diffexresults$qsettings$porq) ||
         diffexresults$qsettings$porq != porq ||
         is.null(diffexresults$qsettings$showsig) ||
         diffexresults$qsettings$showsig != showsig))
    {
      ord.results <- order.results(diffexresults$estat, diffexresults$p, diffexresults$q,
                                   data=data, geneNames=geneNames,
                                   porq, alpha, maxnumsig=(if(first) genedisplay$maxSig else 0))

      if(first && !is.null(ord.results$newalpha))
        {
          alpha <- ord.results$newalpha
          ## Update UI display of alpha
          tclvalue(cutoff.var) <- format(alpha, digits=3)
        }
      
      ## Copy results to diffexresults
      for(name in c("all.ord", "qerr", "nsig", "qsig.ord",
                    "psig.ord", "genesig.ord", "datasig.ord",
                    "datasig.m", "genesigdisp.ord", "geneNames.ord")) {
        expr <- parse(text=paste("diffexresults$", name, " <<- ord.results$", name, sep=""))
        eval(expr)
      }

      printmsg("Repopulating gene list. One moment please...")
      populate.genelist(diffexresults, showsig)

      ## Save new user settings for later comparison
      diffexresults$qsettings$alpha <<- alpha
      diffexresults$qsettings$porq <<- porq
      diffexresults$qsettings$showsig <<- showsig

    }
  }

  ## This function closes the dialogue when analysis is complete.
  diffexdone.func <- function(...) {
    tryCatch(diffexdone.func.int(...), error=error.handler)
  }

  diffexdone.func.int <- function() {
    result1 <- tkmessageBox(message = "Closing the results menu will delete all results. Do you wish to close the window?", 
      icon = "warning", type = "yesno")

    if(tclvalue(result1) == "yes") {
      if(dev.cur() > 1)
        dev.off()
      tkevent.generate(diffexresults.frm, "<<Done>>")
    }
  }

  ## This function saves the results of a differential expression analysis.
  diffexsave.func <- function(...) {
    tryCatch(diffexsave.func.int(...), error=error.handler)
  }

  diffexsave.func.int <- function() {
    filename <- tclvalue(tkgetSaveFile())
    if(filename != "") {
      printmsg("Saving results to:", bell=FALSE)
      printmsg(filename, bell=FALSE)
      .Tcl("update idletasks")
      savediffexresults.func(filename, diffexresults$p[diffexresults$all.ord],
                             diffexresults$geneNames.ord,
                             diffexresults$q[diffexresults$all.ord])
      
      printmsg("Output written.",bell=FALSE)
    }
    else
      printmsg("Save canceled.")
  }

  ## This function creates a q-plot for the q-object from a differential expression analysis.

  qplot.func <- function(...) {
    tryCatch(qplot.func.int(...), error=error.handler)
  }

  qplot.func.int <- function() {
    qobj <- diffexresults$qobj
    plot(qobj, rng=c(0.0, diffexresults$qsettings$alpha))
  }

  ## This function creates a p-value histogram from a differential expression analysis.
  pvalhist.func <- function(...) {
    tryCatch(pvalhist.func.int(...), error=error.handler)
  }

  pvalhist.func.int <- function() {
    qobj <- diffexresults$qobj
    hist(qobj$pvalues, xlab = "P-Value", ylab = "Frequency", main="Histogram of p-values")
  }

  clustsig.func <- function(...) {
    tryCatch(clustsig.func.int(...), error=error.handler)
  }

  clustsig.func.int <- function() {
    datasig.m <- diffexresults$datasig.m
    genesig.ord <- diffexresults$genesig.ord

    if(is.null(datasig.m))
    {
      stop("ERROR: null data")
    }

    if(nrow(datasig.m) == 0)
      stop("No significant genes are available to cluster.")

    if(is.null(genesig.ord))
    {
      stop("ERROR: null gene names")
    }

    colNames = colnames(data)

    getclusteroptionswindow.func(parentwindow, datasig.m, uidefaults,
      rowNames=genesig.ord, colNames=colNames)
  }

  showsig.toggle.func <- function(...) {
    tryCatch(showsig.toggle.func.int(...), error=error.handler)
  }

  showsig.toggle.func.int <- function() {
    showsig <- as.logical(as.numeric(tclvalue(showsig.var)))
    printmsg("One moment please...")
    populate.genelist(diffexresults, showsig)
  }

  accesspm.func <- function(...) {
    tryCatch(accesspm.func.int(...), error=error.handler)
  }
  
  ## This function accesses the pubmed information for a differentially expressed gene. 
  accesspm.func.int <- function() {
    geneNames.ord <- diffexresults$geneNames.ord

    pmval <- as.numeric(tkcurselection(diffexgenes.list))
    pmgene <- geneNames.ord[(pmval + 1)]
	  pmgene <- gsub(" ", "%20", pmgene)
    if(tclvalue(uid.var) == 0)
      browseURL(paste("http://www.ncbi.nih.gov/gquery/gquery.fcgi?cmd=search&term=", pmgene, sep = ""))
    else
      browseURL(paste("http://www.ncbi.nih.gov/gquery/gquery.fcgi?cmd=search&term=", pmgene, sep = ""))
  }

  ## This creates the results base.
  diffexresults.frm <- tkframe(parentwindow, bd = 2, bg = uidefaults$background,height=window.height,width=window.width2)
  diffexoptions.frm <- tkframe(diffexresults.frm, bd = 2, bg = uidefaults$background, relief = "raised")

  cooptions.frm <- tkframe(diffexoptions.frm, bd = 2, bg = uidefaults$background)
  tkpack(tklabel(cooptions.frm, text = "Select P or Q Value Cutoff:", font = uidefaults$titleFont, bg = uidefaults$background,
    fg = uidefaults$bigForeground), anchor = "w")
  cooptionsinset.frm <- tkframe(cooptions.frm, bd = 2, bg = uidefaults$background, relief = "groove")

  porq.frm <- tkframe(cooptionsinset.frm, bd = 2, bg = uidefaults$background)
  porqinset.frm <- tkframe(porq.frm, bd = 2, bg = uidefaults$background, bd = 2)
  p.frm <- tkframe(porqinset.frm, bd = 2, bg = uidefaults$background)
  q.frm <- tkframe(porqinset.frm, bd = 2, bg = uidefaults$background)
  p.lbl <- tklabel(p.frm, text = "P-Value", font = uidefaults$normalFont, bg = uidefaults$background, fg = uidefaults$foreground)
  q.lbl <- tklabel(q.frm, text = "Q-Value", font = uidefaults$normalFont, bg = uidefaults$background, fg = uidefaults$foreground)

  p.rbtn <- new.radiobutton(p.frm, uidefaults=uidefaults, variable = porq.var, value = "p")
  q.rbtn <- new.radiobutton(q.frm, uidefaults=uidefaults, variable = porq.var, value = "q")

  cutoff.frm <- tkframe(cooptionsinset.frm, bd = 2, bg = uidefaults$background)
  cutoff.lbl <- tklabel(cutoff.frm, text = "Cutoff Value:", font = uidefaults$normalFont, bg = uidefaults$background, fg = uidefaults$foreground)
  cutoff.ety <- tkentry(cutoff.frm, textvariable = cutoff.var, font = uidefaults$normalFont, bg = uidefaults$listBackground, 
    fg = uidefaults$listForeground, width = 26)

  ## This creates the q-value options frame. 
  qvaloptions.frm <- tkframe(diffexoptions.frm, bd = 2, bg = uidefaults$background)
  tkpack(tklabel(qvaloptions.frm, text = "Optional Q-Value Arguments:", font = uidefaults$titleFont, bg = uidefaults$background,
    fg = uidefaults$bigForeground), anchor = "w")
  qvaloptionsinset.frm <- tkframe(qvaloptions.frm, relief = "groove", bd = 2, bg = uidefaults$background)    

  ## This function creates the lambda selection frame.
  lambdalabel.frm <- tkframe(qvaloptionsinset.frm, bg = uidefaults$background)
  tkpack(tklabel(lambdalabel.frm, text = "Specify lambda:", font = uidefaults$normalFont, bg = uidefaults$background, fg = uidefaults$bigForeground), 
    anchor = "w")
  lambdarange.frm <- tkframe(qvaloptionsinset.frm, bg = uidefaults$background, padx = 10)
  range.lbl <- tklabel(lambdarange.frm, text = "Range:", font = uidefaults$normalFont, bg = uidefaults$background, fg = uidefaults$foreground)
  range.rbtn <- new.radiobutton(lambdarange.frm, uidefaults=uidefaults, value = 1, variable = lambda.var, command = lambda.func)
  from1.lbl <- tklabel(lambdarange.frm, text = "from:", font = uidefaults$normalFont, bg = uidefaults$background, fg = uidefaults$foreground)
  to1.lbl <- tklabel(lambdarange.frm, text = "to:", font = uidefaults$normalFont, bg = uidefaults$background, fg = uidefaults$foreground)
  by1.lbl <- tklabel(lambdarange.frm, text = "by:", font = uidefaults$normalFont, bg = uidefaults$background, fg = uidefaults$foreground)
  from1.ety <- tkentry(lambdarange.frm, textvariable = from1.var, font = uidefaults$normalFont, width = 5, bg = uidefaults$listBackground,
    fg = uidefaults$listForeground)
  to1.ety <- tkentry(lambdarange.frm, textvariable = to1.var, font = uidefaults$normalFont, width = 5, bg = uidefaults$listBackground,
    fg = uidefaults$listForeground)
  by1.ety <- tkentry(lambdarange.frm, textvariable = by1.var, font = uidefaults$normalFont, width = 5, bg = uidefaults$listBackground,
    fg = uidefaults$listForeground)

  lambdasingle.frm <- tkframe(qvaloptionsinset.frm, padx = 10, bg = uidefaults$background)
  single.lbl <- tklabel(lambdasingle.frm, text = "Single No.:", font = uidefaults$normalFont, bg = uidefaults$background, fg = uidefaults$foreground)
  single.rbtn <- new.radiobutton(lambdasingle.frm, uidefaults=uidefaults, value = 0, 
                                 variable = lambda.var, command = lambda.func)
  single.ety <- tkentry(lambdasingle.frm, textvariable = single.var, font = uidefaults$normalFont, width = 5, 
      state = "disabled", bg = uidefaults$listBackground, fg = uidefaults$listForeground)

  ## These specify bootstrap or smoother method for q-value computation.
  methodlabel.frm <- tkframe(qvaloptionsinset.frm, bg = uidefaults$background)
  tkpack(tklabel(methodlabel.frm, text = "Choose pi_0 method:", font = uidefaults$normalFont, bg = uidefaults$background, fg = uidefaults$bigForeground))
  methodchoice.frm <- tkframe(qvaloptionsinset.frm, bg = uidefaults$background, padx = 10)
  smoother.lbl <- tklabel(methodchoice.frm, text = "Smoother", font = uidefaults$normalFont, bg = uidefaults$background, fg = uidefaults$foreground)
  smoother.rbtn <- new.radiobutton(methodchoice.frm, uidefaults=uidefaults, value = 0, variable = pi0.var)
  bootstrap.lbl <- tklabel(methodchoice.frm, text = "Bootstrap", font = uidefaults$normalFont, bg = uidefaults$background, fg = uidefaults$foreground)
  bootstrap.rbtn <- new.radiobutton(methodchoice.frm, uidefaults=uidefaults, value = 1, variable = pi0.var)


  ## This adds the recalculate button.
  recalculate.frm <- tkframe(diffexoptions.frm, bg = uidefaults$background)
  recalculate.but <- tkbutton(recalculate.frm, text = "RECALCULATE", bg = uidefaults$buttonBackground, fg = uidefaults$buttonForeground,
    command = diffexdisplay.recalc.func)

  ## This creates the differentially expressed gene display. 
  diffexdisplay.frm <- tkframe(diffexresults.frm, bg = uidefaults$background)
  diffexdisplay.lbl <- tklabel(diffexdisplay.frm, textvariable = diffexgenes.var, font = uidefaults$titleFont,
    bg = uidefaults$background, fg = uidefaults$bigForeground)

  ## Check boxes for displaying all genes, or significant genes only.
  diffexshow.frm <- tkframe(diffexdisplay.frm, bg=uidefaults$background)
  diffexshowall.rb <- new.radiobutton(diffexshow.frm, uidefaults=uidefaults, variable = showsig.var, value=0, command=showsig.toggle.func, text="All")
  diffexshowsig.rb <- new.radiobutton(diffexshow.frm, uidefaults=uidefaults, variable = showsig.var, value=1, command=showsig.toggle.func, text="Significant")
  tkgrid(tklabel(diffexshow.frm, font = uidefaults$normalFont,
    bg = uidefaults$background, fg = uidefaults$bigForeground,
    text="Show:"),
  diffexshowall.rb$frame, diffexshowsig.rb$frame)

  diffexgenes.frm <- tkframe(diffexdisplay.frm, bg = uidefaults$background)
  diffexgenes.lbl <- tklabel(diffexdisplay.frm,
    text = paste(rep.str(" ", genedisplay$colLeft),
                 genedisplay$geneNameHeader,
	         rep.str(" ", genedisplay$geneNameColWidth - nchar(genedisplay$geneNameHeader)),
	         genedisplay$pvalHeader,
	         rep.str(" ", genedisplay$pvalColWidth - nchar(genedisplay$pvalHeader)),
	         genedisplay$qvalHeader,
	         rep.str(" ", genedisplay$pvalColWidth - nchar(genedisplay$qvalHeader)),
                 genedisplay$rankHeader
                ),
    bg = uidefaults$background, fg = uidefaults$bigForeground, font = uidefaults$tableFont)
  diffexgenesscr <- tkscrollbar(diffexgenes.frm, repeatinterval = 10, 
    command = function(...) tkyview(diffexgenes.list, ...), bg = uidefaults$background)
  diffexgenes.list <- tklistbox(diffexgenes.frm, height = 10, selectmode = "single", 
    yscrollcommand = function(...) tkset(diffexgenesscr, ...), 
    bg = uidefaults$listBackground, fg = uidefaults$listForeground,
    font = uidefaults$tableFont,
    exportselection = "false", width = 60)
  tkgrid(diffexgenes.list, diffexgenesscr)
  tkgrid.configure(diffexgenesscr, rowspan = 5, sticky = "nsw")

  ## This creates the pubmed accession buttons.
  pubmed.frm <- tkframe(diffexdisplay.frm, bg = uidefaults$background)
  pubmedinset.frm <- tkframe(pubmed.frm)
  uid.lbl <- tklabel(pubmedinset.frm, text = "UID", font = uidefaults$normalFont, bg = uidefaults$background, fg = uidefaults$foreground)
  uid.rbtn <- new.radiobutton(pubmedinset.frm, uidefaults=uidefaults, value = 0, variable = uid.var)
  accession.lbl <- tklabel(pubmedinset.frm, text = "Accession Number", font = uidefaults$normalFont, bg = uidefaults$background,
    fg = uidefaults$foreground)
  accession.rbtn <- new.radiobutton(pubmedinset.frm, uidefaults=uidefaults, value = 1, variable = uid.var)
  pubmed.but <- tkbutton(pubmed.frm, text = "ACCESS NCBI FOR SELECTED GENE", bg = uidefaults$buttonBackground, fg = uidefaults$buttonForeground,
    font = uidefaults$normalFont, command = accesspm.func)

  ## This creates the plot and done buttons.
  diffexbuttons.frm <- tkframe(diffexdisplay.frm, bg = uidefaults$background, bd = 2)
  buttons1.frm <- tkframe(diffexbuttons.frm, bg = uidefaults$background)
  buttons2.frm <- tkframe(diffexbuttons.frm, bg = uidefaults$background)
  qplot.but <- tkbutton(buttons1.frm, text = "Q-PLOT", bg = uidefaults$buttonBackground, fg = uidefaults$buttonForeground, font = uidefaults$normalFont,
    command = qplot.func)
  pvalhist.but <- tkbutton(buttons1.frm, text = "P-VALUE HISTOGRAM", bg = uidefaults$buttonBackground, fg = uidefaults$buttonForeground, 
    font = uidefaults$normalFont, command = pvalhist.func)
  cluster.but <- tkbutton(diffexbuttons.frm, text = "CLUSTER SIGNIFICANT GENES", bg = uidefaults$buttonBackground, fg = uidefaults$buttonForeground,
    font = uidefaults$normalFont, command = clustsig.func)
  saveresults.but <- tkbutton(buttons2.frm, text = "SAVE RESULTS", bg = uidefaults$buttonBackground, fg = uidefaults$buttonForeground,
    font = uidefaults$normalFont, command = diffexsave.func)
  diffexdone.but <- tkbutton(buttons2.frm, text = "DONE", bg = uidefaults$buttonBackground, fg = uidefaults$buttonForeground, font = uidefaults$normalFont,
    command = diffexdone.func)


  ## Pack all of the frames for differential expression results.
  tkpack(diffexdisplay.frm, side = "right", anchor = "n")
  tkpack(diffexdisplay.lbl)
  tkpack(diffexshow.frm)
  tkpack(diffexgenes.lbl, anchor="w")
  tkpack(diffexgenes.frm)
  tkpack(pubmed.frm)
  tkpack(pubmedinset.frm)
  tkpack(uid.lbl, side = "left")
  tkpack(uid.rbtn$frame, side = "left")
  tkpack(accession.lbl, side = "left")
  tkpack(accession.rbtn$frame, side = "left")
  tkpack(pubmed.but)
  tkpack(diffexbuttons.frm)
  tkpack(buttons1.frm)
  tkpack(cluster.but)
  tkpack(buttons2.frm)
  tkgrid(qplot.but, pvalhist.but)
  tkgrid(saveresults.but, diffexdone.but)
  tkpack(diffexoptions.frm, side = "left")
  tkpack(cooptions.frm)
  tkpack(cooptionsinset.frm, expand = "TRUE")
  tkpack(porq.frm)
  tkpack(porqinset.frm)
  tkpack(q.frm)
  tkpack(p.frm)
  tkpack(q.rbtn$frame, side = "right")
  tkpack(q.lbl, side = "left")
  tkpack(p.rbtn$frame, side = "right")
  tkpack(p.lbl, side = "left")
  tkpack(cutoff.ety, side = "right")
  tkpack(cutoff.lbl, side = "left")
  tkpack(cutoff.frm)
  tkpack(qvaloptions.frm)
  tkpack(qvaloptionsinset.frm, expand = "TRUE")
  tkpack(lambdalabel.frm)
  tkpack(range.rbtn$frame, side = "left")
  tkpack(range.lbl,side = "left")
  tkpack(from1.lbl, side = "left")
  tkpack(from1.ety, side = "left")
  tkpack(to1.lbl, side = "left")
  tkpack(to1.ety, side = "left")
  tkpack(by1.lbl, side = "left")
  tkpack(by1.ety, side = "left")
  tkpack(lambdarange.frm)
  tkpack(single.rbtn$frame, side = "left")
  tkpack(single.lbl, side = "left")
  tkpack(single.ety, side = "left")
  tkpack(lambdasingle.frm, fill = "x")
  tkpack(methodlabel.frm, fill = "x")
  tkpack(smoother.lbl, side = "left")
  tkpack(smoother.rbtn$frame, side = "left")
  tkpack(bootstrap.lbl, side = "left")
  tkpack(bootstrap.rbtn$frame, side = "left")
  tkpack(methodchoice.frm, fill = "x")
  tkpack(recalculate.frm)
  tkpack(recalculate.but)

  diffexdisplay.func(first=TRUE)
  return(diffexresults.frm)
  
}

######################################################################### 
## This function creates the "Differential Expression"  settings frame
######################################################################### 
getdiffexsettingsframe.func <- function(parentwindow, data, pdata, varLabels, 
			                uidefaults, printmsg=function(...) stop("printmsg not defined in settingsframe") ) {
  if(is.null(data))
    stop("data is null")

  if(is.null(pdata))
    stop("pdata is null")

  if(is.null(varLabels))
    stop("varLabels is null")

  if(!exists("diffexsettings"))
    diffexsettings <<- list()
  if(!exists("diffexresults"))
    diffexresults <<- list()
  
  nullperm.var <- tclVar("100")
  seed.var <- tclVar("NULL")

  ##############################################
  ## Internal Functions
  ##############################################
  diffgo.func <- function() {
    ## Clear the results.
    diffexresults <<- list()
    
    ## Apply settings.
    cvar <- as.numeric(tkcurselection(class.list))
    ## Make sure class does not equal time setting
    grp <- NULL
    if(cvar > 0) 
      grp <- make.consecutive.int(pdata[cvar, ])
    B <- as.numeric(tclvalue(nullperm.var))

    ## Get the seed, and warn the user if they entered a garbage string
    seedstr <- tclvalue(seed.var)
    seed <<- tryCatch(as.numeric(seedstr),
       warning=function(w) {
         if(seedstr != "NULL" && seedstr != "NA") 
	   printmsg(paste("Warning: Could not decipher a numeric seed from the string '", 
	     tclvalue(seed.var),"'")); seed <<- NULL
       })

    if(!is.valid.number(seed))##is.vector(seed) && is.na(seed))
      seed <<- NULL
    if(diffexsettings$diffextype == "timecourse") 
    {
      printmsg("The EDGE analysis may take a moment. Please be patient while the estimated time left loads...")
      if(!list.has(diffexsettings,"tvar")) 
      {
        stop("Please click the TIME COURSE SETTINGS button and",
             "select parameters for the analysis.")
        return("failed")
      }

      tvar <- check.not.nullna(diffexsettings$tvar)
      if(cvar > 0 && cvar == tvar)
        stop("You have chosen the same covariate, '", varLabels[cvar],"', for both",
             "Class and Time Point covariates, which is not allowed. Please choose",
             "a different covariate for Class or for Time Points.")
      nullfit <<- "flat"
      if(!is.null(grp)){nullfit <<- "curve"}
      if(!list.has(diffexsettings,"intercept")) 
      {
        stop("Please click the TIME COURSE SETTINGS button and",
             "select parameters for the analysis.")
        return("failed")
      }

      tvar <- check.not.nullna(diffexsettings$tvar)
      if(cvar > 0 && cvar == tvar)
        stop("You have chosen the same covariate, '", varLabels[cvar],"', for both",
             "Class and Time Point covariates, which is not allowed. Please choose",
             "a different covariate for Class or for Time Points.")

      if((is.null(diffexsettings$ind)) && (nullfit == "flat"))
	{
	  diffexsettings$intercept <<- TRUE
	}
      tid <<- timecourse.func(dat = data, tme = diffexsettings$tme, grp = grp,
                              ind = diffexsettings$ind, B = B, null = nullfit,
                              dfo = diffexsettings$dfo,
                              intercept = diffexsettings$intercept,
                              outfile = NULL, 
                              basis = diffexsettings$basis,seed=seed,
                              match=diffexsettings$match,
                              updatefunc=timecourseupdate.func,
                              finalfunc=timecoursedone.func,
                              printmsg=printmsg)

      diffexconfigurestate("running")
    }
    else if(diffexsettings$diffextype == "static") 
    {
      printmsg("The EDGE analysis may take a moment. Please be patient while the estimated time left loads...")
       tid <<- odp.func(dat=data,grp=grp,B=B,match=diffexsettings$match,
                        seed=seed,
                        updatefunc=staticupdate.func,
                        finalfunc=staticdone.func,
                        printmsg=printmsg,
                        background=TRUE)
       if(tid == 0)
         stop("tid is 0")

       diffexconfigurestate("running")
     }
    else if((diffexsettings$diffextype != "static")
            && (diffexsettings$diffextype != "timecourse"))
      stop("You must choose settings for either a Static or Time Course Analysis")
   
  }
  ##############################################

  diffexconfigurestate <- function(state)
  {
    if(state=="running")
    {
      for(gui in runningEnabled) tkconfigure(gui[[1]], state="normal")
      for(gui in runningDisabled) tkconfigure(gui[[1]], state="disabled")
    }
    else if (state=="stopped")
    {
      for(gui in runningEnabled) tkconfigure(gui[[1]], state="disabled")	
      for(gui in runningDisabled) tkconfigure(gui[[1]], state="normal")
      ## Disable either "STATIC SETTINGS" or "TIME COURSE SETTINGS" buttons
      diffextype.func()
    }
    else
      stop("state must be either 'running' or 'stopped'")
  }

  diffexstop.func <- function()
  {
    diffexconfigurestate("stopped")
    if (0 != thread.stop.func(tid))
      stop("Could not stop thread")
    tkconfigure(diffexstatus.lbl, text="Stopped")
    tkconfigure(diffextime.lbl, text="")
  }

  staticupdate.func <- function(tid, progress, datalist)
  {
    max <- check.not.nullna(progress$max)

    current <- (progress$current-progress$min)
    
    pct <- current / max
# gah - debug
#   print(paste("pct: current=",current,"max=",max))

    if(pct > 1) 
    {
      pct <- 1
# gah - don't print message, stay at 100% (unless debugging)
      if(debugOn) print(paste("warning: pct>1 current=", current, "max=", max))
    }

    timeLeft = (1 - pct)*(proc.time()[3] - datalist$startTime) / pct

    tkconfigure(diffextime.lbl, text = paste("Estimated time left:",
                                  secsToString(timeLeft)))
    tkconfigure(diffexstatus.lbl, text=paste(floor(100*pct),
                                    "% significance analysis completed"))

  }

  staticdone.func <- function(p, lr, lr0, status)
  {
    tkconfigure(diffexstop.btn, state="disabled")
    diffexresults$status <<- status

    tkconfigure(diffextime.lbl, text = "")
    if(status$succeeded) {
      diffexresults$p <<- p
      diffexresults$estat <<- lr
      diffexresults$lr0 <<- lr0

      tkconfigure(diffexstatus.lbl, text="Constructing results window...")
      .Tcl("update idletasks")
      tkevent.generate(holder.frm, "<<DiffexDone>>")
    } else {
      tkconfigure(diffexstatus.lbl, text="Analysis failed. Check message window.")
      .Tcl("update idletasks")
      printmsg(paste("\nError:", status$reason))
      tkevent.generate(holder.frm, "<<DiffexDoneError>>")
    }
    
    diffexconfigurestate("stopped")
  }

  current <- -1
  timecourseupdate.func <- function(tid, progress, datalist)
  {
    if(current != progress$current)
    {
      current <<- progress$current
    
      pct <- (progress$current - progress$min) / (progress$max - progress$min)
      timeLeft <- (1 - pct)*(proc.time()[3] - datalist$startTime) / pct
      if(is.finite(pct))
      {
        if(pct > 1) pct <- 1
      }
      else timeLeft <- 0
  
      tkconfigure(diffextime.lbl, text = paste("Estimated time left:",
                                    secsToString(timeLeft)))
      tkconfigure(diffexstatus.lbl, text=paste(floor(100*pct),
                                      "% significance analysis completed"))
    }

  }

  timecoursedone.func <- function(p, lr, lr0, status)
  {
    tkconfigure(diffexstop.btn, state="disabled")

    diffexresults$status <<- status
    tkconfigure(diffextime.lbl, text = "")
    if(status$succeeded) {
      diffexresults$p <<- p
      diffexresults$estat <<- lr
      diffexresults$lr0 <<- lr0
      
      tkconfigure(diffexstatus.lbl, text="Constructing results window...")
      .Tcl("update idletasks")
      
      tkevent.generate(holder.frm, "<<DiffexDone>>")
    } else {
      tkconfigure(diffexstatus.lbl, text="Analysis failed. Check message window.")
      .Tcl("update idletasks")
      printmsg(paste("\nError:", status$reason))
      tkevent.generate(holder.frm, "<<DiffexDoneError>>")
    }
    
    diffexconfigurestate("stopped")
  }


  ##############################################
  diffhelp.func <- function() {
    tkmessageBox(message=paste(
                    "The CLASS VARIABLE assigns the arrays into the biological",
                    "groups that are compared for differential expression. If",
                    "the arrays come from a single group (e.g., a direct comparison",
                    "on a two-channel array or testing for genes that change over",
                    "time), then select \"None.\""),
                   icon="info",type="ok")
  }
  ##############################################

  ##############################################
  timesettings.func <- function() {
    tkpack.forget(diffex.frm)
    tkpack(timesettings.frm)
  }
  timesettingsdone.func <- function() {
    tkpack.forget(timesettings.frm)
    tkpack(diffex.frm)
  }
  ##############################################

  ##############################################
  staticsettings.func <- function() {
    tkpack.forget(diffex.frm)
    tkpack(staticsettings.frm)
  }
  staticsettingsdone.func <- function() {
    tkpack.forget(staticsettings.frm)
    tkpack(diffex.frm)
  }
  ##############################################

  ##############################################
  matchsettings.func <- function() {
    tkpack.forget(diffex.frm)
    tkpack(matchsettings.frm)
  }
  matchsettingsdone.func <- function() {
    tkpack.forget(matchsettings.frm)
    tkpack(diffex.frm)
  }
  ##############################################

  
  diffextype.func <- function() {
    if(as.numeric(tkcurselection(diffextype.list)) == 0){
      diffexsettings$diffextype <<- "static"
      tkconfigure(timecourse.but,state="disabled")
      tkconfigure(static.but,state="normal")
    }
    else{
      diffexsettings$diffextype <<- "timecourse"
      tkconfigure(static.but,state="disabled")
      tkconfigure(timecourse.but,state="normal")
    }
  }

  ## Create the differential expression base
  holder.frm <- tkframe(parentwindow, bd = 2, bg = uidefaults$background)

  ## Sub-frames
  env <- environment()

  timesettings.frm <- gettimesettingsframe.func(
    holder.frm, pdata, varLabels, env, uidefaults, printmsg)
  staticsettings.frm <- getstaticsettingsframe.func(holder.frm, data, env, uidefaults, printmsg)
  matchsettings.frm <- getmatchsettingsframe.func(
    holder.frm, env, uidefaults, pdata, varLabels, printmsg)
  tkbind(timesettings.frm, "<<Apply>>", timesettingsdone.func)
  tkbind(timesettings.frm, "<<Cancel>>", timesettingsdone.func)
  tkbind(staticsettings.frm, "<<Apply>>", staticsettingsdone.func)
  tkbind(staticsettings.frm, "<<Cancel>>", staticsettingsdone.func)
  tkbind(matchsettings.frm, "<<Apply>>", matchsettingsdone.func)
  tkbind(matchsettings.frm, "<<Cancel>>", matchsettingsdone.func)

  ## Differential Expression settings sub-frame
  diffex.frm <- tkframe(holder.frm, bd = 2, bg = uidefaults$background)
  diffexinset.frm <- tkframe(diffex.frm, bd = 2, bg = uidefaults$background)

  ## Create the help button.
  diffexhelp.frm <- tkframe(diffexinset.frm, bg = uidefaults$background)
  diffexhelp.but <- tkbutton(diffexhelp.frm, text = "WHAT IS THE CLASS COVARIATE?", 
  		 font = uidefaults$normalFont, command = diffhelp.func, 
		 bg = uidefaults$bigForeground, fg = uidefaults$background)
  tkgrid(diffexhelp.but)

  ## Create the expression base buttons.
  diffexbuttons.frm <- tkframe(diffex.frm, bg = uidefaults$background)
  diffexgo.but <- tkbutton(diffexbuttons.frm, text = "GO", font = uidefaults$titleFont, command = diffgo.func, 
    bg=uidefaults$buttonBackground,fg=uidefaults$buttonForeground)
  diffexdone.but <- tkbutton(diffexbuttons.frm, text = "DONE", font = uidefaults$titleFont, 
    command=function() { 
      tkevent.generate(holder.frm, "<<SettingsDone>>") 
    }, 
    bg = uidefaults$buttonBackground, fg = uidefaults$buttonForeground)
  tkgrid(diffexgo.but, diffexdone.but)

  ## Create the list box to select the class covariate for differential expression.
  classchoice.frm <- tkframe(diffexinset.frm, relief = "raised", bd = 2, bg = uidefaults$background)
  tkpack(tklabel(classchoice.frm, text = "Choose Class Variable:", font = uidefaults$titleFont, bg = uidefaults$background, fg = uidefaults$bigForeground), anchor = "w")
  classchoiceinset.frm <- tkframe(classchoice.frm, relief = "raised", bd = 2, bg = uidefaults$background)
  classscr <- tkscrollbar(classchoiceinset.frm, repeatinterval = 5, command = function(...) tkyview(class.list, ...))
  class.list<- tklistbox(classchoiceinset.frm, height = 5, width = 60, selectmode = "single", 
    yscrollcommand = function(...) tkset(classscr, ...), bg = uidefaults$foreground, fg = uidefaults$background, exportselection = "false")

  ngene <- dim(data)[1]

  l <- length(varLabels)
  if(l >= 1) {
    tkinsert(class.list, "end", "None (within class differential expression)")
    for(i in 1:l)
      tkinsert(class.list, "end", as.character(varLabels[i]))
  } else
    tkinsert(class.list, "end", "None (within class differential expression)")

  tkselection.set(class.list, 0)
  tkgrid(class.list, classscr)
  tkgrid(class.list)
  tkgrid.configure(classscr, rowspan = 5, sticky = "nsw")

  ## Create the list box for adjusting for covariates.
  diffextype.frm <- tkframe(diffex.frm, relief = "raised", bd = 2, bg = uidefaults$background)
  tkpack(tklabel(diffextype.frm, text = "Differential Expression Type:", font = uidefaults$titleFont, bg = uidefaults$background, fg = uidefaults$bigForeground), anchor = "w")
  diffextypeinset.frm <- tkframe(diffextype.frm, relief = "raised", bd = 2, bg = uidefaults$background)
  diffextypescr <- tkscrollbar(diffextypeinset.frm, repeatinterval = 2, command = function(...) tkyview(diffextype.list, ...))
  diffextype.list <- tklistbox(diffextypeinset.frm, height = 2, width = 60, selectmode = "single", 
    yscrollcommand = function(...) tkset(diffextypescr, ...), bg = uidefaults$foreground, 
    fg = uidefaults$background, exportselection = "false")

  
  tkinsert(diffextype.list,"end","Static (standard, non-time course sampling)")
  tkinsert(diffextype.list,"end","Time Course")
  tkbind(diffextype.list, "<ButtonRelease-1>", diffextype.func)

  tkselection.set(diffextype.list, 0)
  tkgrid(diffextype.list, diffextypescr)
  tkgrid(diffextype.list)
  tkgrid.configure(diffextypescr, rowspan = 5, sticky = "nsw")

  ## Create the null permuations entry.
  nullperm.frm <- tkframe(diffex.frm, bd = 2, bg = uidefaults$background)
  nullperminset.frm <- tkframe(nullperm.frm, relief = "groove", bd = 2, bg = uidefaults$background)
  nullperm.lbl <- tklabel(nullperminset.frm, text = "Number of null iterations:", font = uidefaults$normalFont, 
    bg = uidefaults$background, fg = uidefaults$bigForeground)
  nullperm.ety <- tkentry(nullperminset.frm, textvariable = nullperm.var, font = uidefaults$normalFont, width = 32, 
    bg = uidefaults$foreground, fg = uidefaults$background)

  ## Create the seed entry
  seed.frm <- tkframe(diffex.frm,bd=2,bg=uidefaults$background)
  seedinset.frm <- tkframe(seed.frm,relief="groove",bd=2,bg=uidefaults$background)
  seed.lbl <- tklabel(seedinset.frm, text="Choose a seed for reproducible results:",font= uidefaults$normalFont,bg=uidefaults$background,fg=uidefaults$bigForeground)
  seed.ety <- tkentry(seedinset.frm,textvariable=seed.var,font=uidefaults$normalFont,width=20,bg=uidefaults$listBackground,fg=uidefaults$listForeground)
  
  
  ## Create the settings buttons.
  settings.frm <- tkframe(diffex.frm, bg = uidefaults$background)
  timecourse.frm <- tkframe(settings.frm, bg = uidefaults$background)
  timecourse.but <- tkbutton(timecourse.frm, text = "TIME COURSE SETTINGS", font = uidefaults$titleFont, 
    command = timesettings.func, bg = uidefaults$bigForeground, fg = uidefaults$background, width = 30)

  tkconfigure(timecourse.but,state="disabled")
 
  static.frm <- tkframe(settings.frm, bg = uidefaults$background)
  static.but <- tkbutton(static.frm, text = "STATIC SAMPLING SETTINGS", font = uidefaults$titleFont, command = staticsettings.func, 
    bg = uidefaults$bigForeground, fg = uidefaults$background, width = 30)
 
  match.frm <- tkframe(settings.frm, bg = uidefaults$background)
  match.but <- tkbutton(match.frm, text = "MATCH DESIGN SETTINGS", font = uidefaults$titleFont, command = matchsettings.func, 
    bg = uidefaults$bigForeground, fg = uidefaults$background, width = 30)

  ## Lay out the buttons.
  tkgrid(static.but)
  tkgrid(timecourse.but)
  tkgrid(match.but)   

  ## Create Spacing frames
  space1.frm <- tkframe(diffex.frm, bg = uidefaults$background, width = 30, height = 15)
  space2.frm <- tkframe(diffex.frm, bg = uidefaults$background, width = 30, height = 15)
  space3.frm <- tkframe(diffex.frm, bg = uidefaults$background, width = 30, height = 15)
  space4.frm <- tkframe(diffex.frm, bg = uidefaults$background, width = 30, height = 15)
  space5.frm <- tkframe(diffex.frm, bg = uidefaults$background, width = 30, height = 15)

  diffexstatus.frm <- tkframe(diffex.frm, bg = uidefaults$background, width=30, height=15)
  diffexstatus.lbl <- tklabel(diffexstatus.frm, bg= uidefaults$background, fg=uidefaults$bigForeground, font=uidefaults$normalFont, width=60)
  diffextime.lbl <- tklabel(diffexstatus.frm, bg= uidefaults$background, fg=uidefaults$bigForeground, font=uidefaults$normalFont, width=60)
  diffexstop.btn <- tkbutton(diffexstatus.frm, bg=uidefaults$background, fg=uidefaults$buttonForeground, bg=uidefaults$buttonBackground, font=uidefaults$titleFont, command=diffexstop.func, text="CANCEL")

  runningEnabled <- c(list(diffexstop.btn))
  runningDisabled <- c(
      list(diffexgo.but),
      list(diffexdone.but),
      list(diffexhelp.but),
      list(timecourse.but),
      list(static.but),
      list(match.but),
      list(nullperm.ety),
      list(seed.ety),
      list(class.list),
      list(diffextype.list)
      )

  diffexconfigurestate("stopped")
  ## Pack the frames onto the statex base.
  tkpack(diffexinset.frm)
  tkpack(classchoice.frm)
  tkpack(classchoiceinset.frm)
  tkpack(diffexhelp.frm)
  tkpack(space1.frm)
  tkpack(diffextype.frm)
  tkpack(diffextypeinset.frm)
  tkpack(space2.frm)
  tkpack(nullperm.frm)
  tkpack(nullperminset.frm)
  tkpack(nullperm.lbl, side = "left")
  tkpack(nullperm.ety, side = "right")
  tkpack(seed.frm)
  tkpack(seedinset.frm)
  tkpack(seed.lbl,side="left")
  tkpack(seed.ety,side="right")
  tkpack(space3.frm)
  tkpack(settings.frm)
  tkpack(static.frm)
  tkpack(timecourse.frm)
  tkpack(match.frm)
  tkpack(space4.frm)
  tkpack(space5.frm)
  tkpack(diffexbuttons.frm)
  tkpack(diffexstatus.frm)
  tkpack(diffextime.lbl)
  tkpack(diffexstatus.lbl)
  tkpack(diffexstop.btn)
  tkpack(diffex.frm)

  return(holder.frm)
}

######################################################################### 
## This function creates the "Differential Expression" settings sub-frame
## for TIME COURSE data sets
######################################################################### 
gettimesettingsframe.func <- function(parentwindow, pdata, varLabels, diffexsettings.env, uidefaults, printmsg = function(m, ...) { stop("printmsg not defined in settingsframe") }) {

  diffexsettings$diffextype <<- "timecourse"

  df.cbval <- tclVar("0")
  df.var <- tclVar("4")
  intercept.var <- tclVar("0")

  dfactive.func <- function() {
    if(tclvalue(df.cbval) == "1")
      tkconfigure(df.ety,state="normal")
    else
      tkconfigure(df.ety,state="disabled")
  }

  timecancel.func <-function() 
  { 
    printmsg("Time settings NOT applied.")
    tkevent.generate(timesettings.frm, "<<Cancel>>") 
  }

  timeapply.func <- function() {
    check.not.nullna(diffexsettings)

    diffexsettings$diffextype <<- "timecourse"
    ## Individual
    diffexsettings$ivar <<- as.numeric(tkcurselection(indiv.list))
    diffexsettings$ind <<- NULL
    if(diffexsettings$ivar > 0)
      diffexsettings$ind <<- make.consecutive.int(pdata[diffexsettings$ivar, ])

    svar <<- as.numeric(tkcurselection(spline.list))
    diffexsettings$basis <<- "ncs"
    if(svar == 1)
      diffexsettings$basis <<- "poly"

    dfvar <<- as.numeric(tclvalue(df.cbval))
    diffexsettings$dfo <<- NULL
    if(dfvar == 1)
    {
      diffexsettings$dfo <<- as.numeric(tclvalue(df.var))
      if(!is.valid.number(diffexsettings$dfo))##is.na(diffexsettings$dfo))
        stop("Dimension of basis is not a valid decimal number.")
    }
    
    ## Time points
    diffexsettings$tvar <<- (as.numeric(tkcurselection(tme.list)) + 1)
### Do not call make.consecutive.int - just make sure these are numbers
    diffexsettings$tme <<- tryCatch(
                                    data.frame.as.numeric(pdata[diffexsettings$tvar, ]),
                                    error=function(e) stop(paste("Could not convert the time covariates to numbers:",
                                      e$message))
                                   )

    ivar <<- as.numeric(tclvalue(intercept.var))
    diffexsettings$intercept <<- FALSE
    if(ivar == 1)
      diffexsettings$intercept <<- TRUE

    ## Fire a "done" event
    printmsg("Time settings applied.")
    tkevent.generate(timesettings.frm, "<<Apply>>")
  }

  timesettings.frm <- tkframe(parentwindow, bd = 2, bg = uidefaults$background)

  ## Create the list box with time covariate options.
  tmechoice.frm <- tkframe(timesettings.frm, relief = "raised", bd = 2, bg = uidefaults$background)
  tkpack(tklabel(tmechoice.frm, text = "Choose covariate giving time points (required):", font = uidefaults$titleFont, bg = uidefaults$background, 
    fg = uidefaults$bigForeground), anchor = "w")
  tmechoiceinset.frm <- tkframe(tmechoice.frm, relief = "raised", bd = 2, bg = uidefaults$background)
  tmescr <- tkscrollbar(tmechoiceinset.frm, repeatinterval = 5, command = function(...) tkyview(tme.list, ...))
  tme.list <- tklistbox(tmechoiceinset.frm, height = 5, width = 60, selectmode = "single", 
    yscrollcommand = function(...) tkset(tmescr, ...), bg = uidefaults$listBackground, fg = uidefaults$listForeground, exportselection = "false")

  l <- length(varLabels)
  if(l >= 1) {
    for(i in 1:l) 
      tkinsert(tme.list, "end", as.character(varLabels[i]))
    timecov <- 1
  } else {
    tkinsert(tme.list, "end", "No covariates loaded, you cannot perform")
    tkinsert(tme.list, "end", "a differential expression analysis")
    timecov <- 0
  }

  tkselection.set(tme.list, 0)
  tkgrid(tme.list, tmescr)
  tkgrid(tme.list)
  tkgrid.configure(tmescr, rowspan = 5, sticky = "nsw")

  ## Create the list box with individual covariate options.
  indivchoice.frm <- tkframe(timesettings.frm, relief = "raised", bd = 2, bg = uidefaults$background)
  tkpack(tklabel(indivchoice.frm, text = "Choose covariate corresponding to individuals:", 
  font = uidefaults$titleFont, bg = uidefaults$background, fg = uidefaults$bigForeground), anchor = "w")
  indivchoiceinset.frm <- tkframe(indivchoice.frm, relief = "raised", bd = 2, bg = uidefaults$background)
  indivscr <- tkscrollbar(indivchoiceinset.frm, repeatinterval = 5, command = function(...) tkyview(indiv.list, ...))
  indiv.list <- tklistbox(indivchoiceinset.frm, height = 5, width = 60, selectmode = "single", 
    yscrollcommand = function(...) tkset(indivscr, ...), bg = uidefaults$listBackground, fg = uidefaults$listForeground, exportselection = "false")

  l <- length(varLabels)
  if(l >= 1) {
    tkinsert(indiv.list, "end", "None (Independent Sampling)")
    for(i in 1:l) 
      tkinsert(indiv.list, "end", as.character(varLabels[i]))
  } else 
    tkinsert(indiv.list, "end", "None (Independent Sampling)")

  tkselection.set(indiv.list, 0)
  tkgrid(indiv.list, indivscr)
  tkgrid(indiv.list)
  tkgrid.configure(indivscr, rowspan = 5, sticky = "nsw")
  tkpack(tklabel(indivchoice.frm, text = "(This is only necessary for longitudinal sampling.)", 
    font = uidefaults$littleFont, bg = uidefaults$background, fg = uidefaults$foreground))

  ## Create the spline entry.
  spline.frm <- tkframe(timesettings.frm, relief="raised", bd = 2, bg = uidefaults$background)
  tkpack(tklabel(spline.frm, text = "Choose spline type:", font = uidefaults$titleFont, bg = uidefaults$background, fg = uidefaults$bigForeground), anchor = "w")
  splineinset.frm <- tkframe(spline.frm, relief="raised", bd = 2, bg = uidefaults$background)
  splinescr <- tkscrollbar(splineinset.frm, repeatinterval = 2, command = function(...) tkyview(test.list, ...))
  spline.list <- tklistbox(splineinset.frm, height = 2, width = 60, selectmode = "single", 
    yscrollcommand = function(...) tkset(splinescr, ...), bg = uidefaults$listBackground, fg = uidefaults$listForeground, exportselection = "false")
  tkinsert(spline.list, "end", "Natural Cubic Spline")
  tkinsert(spline.list, "end", "Polynomial Spline")
  tkselection.set(spline.list, 0)
  tkgrid(spline.list, splinescr)
  tkgrid(spline.list)
  tkgrid.configure(splinescr, rowspan = 2, sticky = "nsw")

  ## Create the Intercept checkbutton.
  intercept.frm <- tkframe(timesettings.frm,bd=2,bg=uidefaults$background,relief="raised")
  intercept.cb <- new.checkbutton(intercept.frm, uidefaults=uidefaults, variable = intercept.var)
  intercept.lbl <- tklabel(intercept.frm, text = "Check to include baseline levels in analysis.",
    font = uidefaults$normalFont, bg = uidefaults$background, fg = uidefaults$bigForeground)

  ## Create the degrees of freedom entry.
  df.frm <- tkframe(timesettings.frm, bd = 2, bg = uidefaults$background)
  dfinset.frm <- tkframe(df.frm, relief = "raised", bd = 2, bg = uidefaults$background)
  df.cb <- new.checkbutton(dfinset.frm, uidefaults=uidefaults, variable = df.cbval, command = dfactive.func)
  df.lbl <- tklabel(dfinset.frm, text = "Dimension of basis for the spline:", font = uidefaults$normalFont, bg = uidefaults$background, fg = uidefaults$bigForeground)
  df.ety <- tkentry(dfinset.frm, textvariable = df.var, font = uidefaults$normalFont, width = 20, bg = uidefaults$listBackground, fg = uidefaults$listForeground)
  tkconfigure(df.ety, state = "disabled")

  ## Create the space frames
  spacetime1.frm <- tkframe(timesettings.frm, bg = uidefaults$background, width = 30, height = 15)
  spacetime2.frm <- tkframe(timesettings.frm, bg = uidefaults$background, width = 30, height = 15)
  spacetime3.frm <- tkframe(timesettings.frm, bg = uidefaults$background, width = 30, height = 15)
  spacetime4.frm <- tkframe(timesettings.frm,bg = uidefaults$background, width = 30, height = 15)
  spacetime5.frm <- tkframe(timesettings.frm,bg = uidefaults$background, width = 30, height = 15)

  ## Create the buttons frame.
  timebuttons.frm <- tkframe(timesettings.frm, bg = uidefaults$background)
  timeapply.but <- tkbutton(timebuttons.frm, text = "APPLY", font = uidefaults$titleFont, command = timeapply.func, 
    bg = uidefaults$buttonBackground, fg = uidefaults$buttonForeground)
  if(timecov == 0) {
    tkconfigure(timeapply.but, state = "disabled")
    tkconfigure(tme.list, state = "disabled")
    tkconfigure(indiv.list, state = "disabled")
  }
  timecancel.but <- tkbutton(timebuttons.frm, text = "CANCEL", font = uidefaults$titleFont, 
    command = timecancel.func,
    bg = uidefaults$buttonBackground, fg = uidefaults$buttonForeground)
  tkgrid(timeapply.but, timecancel.but)

  ## Pack the appropriate frames
  tkpack(tmechoice.frm)
  tkpack(tmechoiceinset.frm)
  tkpack(spacetime1.frm)
  tkpack(indivchoice.frm)
  tkpack(indivchoiceinset.frm)
  tkpack(spacetime3.frm)
  tkpack(spline.frm)
  tkpack(splineinset.frm)
  tkpack(spacetime4.frm)
  tkpack(df.frm)
  tkpack(dfinset.frm)
  tkpack(df.cb$frame, side = "left")
  tkpack(df.lbl, side = "left")
  tkpack(df.ety, side = "left")
  tkpack(intercept.frm)
  tkpack(intercept.cb$frame, side = "left")
  tkpack(intercept.lbl, side = "left")
  tkpack(spacetime5.frm)
  tkpack(timebuttons.frm)

  return(timesettings.frm)
}

######################################################################### 
## This function creates the "Differential Expression" settings sub-frame
## for STATIC data sets
######################################################################### 
getstaticsettingsframe.func <- function(parentwindow, data, diffexsettings.env, uidefaults,
			    printmsg = function(...) { stop("printmsg not defined in getstaticsettingsframe") }) {

  staticcancel.func <- function() {
    ## Fire a "done" event
    printmsg("Static settings NOT applied.")
    tkevent.generate(staticsettings.frm, "<<Cancel>>")
  }
  
  staticapply.func <- function() {
    if(!is.list(diffexsettings))
      stop("diffexsettings is not a list")
    diffexsettings$diffextype <<- "static"

    ## Fire a "done" event
    printmsg("Static settings applied.")
    tkevent.generate(staticsettings.frm, "<<Apply>>")
  }

  staticsettings.frm <- tkframe(parentwindow, bg = uidefaults$background, relief = "raised", bd = 2)


  ## Create the buttons frame.
  staticbuttons.frm <- tkframe(staticsettings.frm, bg = uidefaults$background)
  staticapply.but <- tkbutton(staticbuttons.frm, text = "APPLY", font = uidefaults$titleFont, command = staticapply.func, 
    bg = uidefaults$buttonBackground, fg = uidefaults$buttonForeground)
  staticcancel.but <- tkbutton(staticbuttons.frm, text = "CANCEL", font = uidefaults$titleFont,
    command = staticcancel.func,
    bg = uidefaults$buttonBackground, fg = uidefaults$buttonForeground)
  tkgrid(staticapply.but,staticcancel.but)

  ## Create the space frames
  spacestatic2.frm <- tkframe(staticsettings.frm, bg = uidefaults$background, width = 30, height = 15)

  tkpack(tklabel(staticsettings.frm,
                 text = "No extra static settings available at this time.",
                 font = uidefaults$titleFont,
                 bg = uidefaults$background,
                 fg = uidefaults$bigForeground),
         anchor = "w")
                 
  tkpack(spacestatic2.frm)
  tkpack(staticbuttons.frm)

  return(staticsettings.frm)
}

######################################################################### 
## This function creates the match settings frame
######################################################################### 
getmatchsettingsframe.func <- function(parentwindow, diffexsettings.env, uidefaults, pdata, varLabels,
			    printmsg = function(...) { stop("printmsg not defined in getmatchsettingsframe") }) {

  ## Functions
  matchapply.func <- function() {

    diffexsettings$mvar <<- as.numeric(tkcurselection(paired.list)) 
    if(diffexsettings$mvar > 0) {
      diffexsettings$match <<- make.consecutive.int(pdata[diffexsettings$mvar, ])
    } else {
      diffexsettings$match <<- NULL
    }


    ## Fire a "done" event
    printmsg("Match settings applied.")
    tkevent.generate(matchsettings.frm, "<<Apply>>")
  }
  
  matchcancel.func <- function() 
  { 
    printmsg("Match settings NOT applied.")
    tkevent.generate(matchsettings.frm, "<<Cancel>>") 
  }

  matchsettings.frm <- tkframe(parentwindow, bg = uidefaults$background, relief = "raised", bd = 2)

  ## Create the list box for selecting a pairing covariate for paired static differential expression.
  paired.frm <- tkframe(matchsettings.frm, relief = "raised", bd = 2, bg = uidefaults$background)
  tkpack(tklabel(paired.frm, text = "Choose matching covariate:", font = uidefaults$titleFont, bg = uidefaults$background, fg = uidefaults$bigForeground), anchor = "w")
  pairedinset.frm <- tkframe(paired.frm, relief = "raised", bd = 2, bg = uidefaults$background)
  pairedscr <- tkscrollbar(pairedinset.frm, repeatinterval = 5, command = function(...) tkyview(paired.list, ...))
  paired.list <- tklistbox(pairedinset.frm, height = 5, width = 60, selectmode = "single", 
    yscrollcommand = function(...) tkset(pairedscr, ...), bg = uidefaults$listBackground, fg = uidefaults$listForeground, exportselection = "false")

  l <- length(varLabels)
  if(l >= 1) {
    tkinsert(paired.list, "end", "None, no matching")
      for(i in 1:l) 
        tkinsert(paired.list, "end", as.character(varLabels[i]))
  } else
    tkinsert(paired.list, "end", "None, no matching")

  tkselection.set(paired.list, 0)
  tkgrid(paired.list, pairedscr)
  tkgrid(paired.list)
  tkgrid.configure(pairedscr, rowspan = 5, sticky = "nsw")

  ## Create the matching button.
  matchbuttons.frm <- tkframe(matchsettings.frm, bg = uidefaults$background)
  matchapply.but <- tkbutton(matchbuttons.frm, text = "APPLY", font = uidefaults$titleFont, command = matchapply.func, 
    bg = uidefaults$bigForeground, fg = uidefaults$background)
  matchcancel.but <- tkbutton(matchbuttons.frm,text="CANCEL", font=uidefaults$titleFont,command=matchcancel.func, bg=uidefaults$buttonBackground,fg=uidefaults$buttonForeground)
  tkgrid(matchapply.but,matchcancel.but)

  ## Pack the appropriate frames

  tkpack(paired.frm)
  tkpack(pairedinset.frm)
  tkpack(matchbuttons.frm)
  return(matchsettings.frm)
}

