#' Plot gistic results.
#' @description takes output generated by readGistic and draws a plot similar to oncoplot.
#'
#' @details
#' Takes gistic file as input and plots it as a matrix. Any desired annotations can be added at the bottom of the oncoplot by providing \code{annotation}
#'
#' @param gistic an \code{\link{GISTIC}} object generated by \code{\link{readGistic}}
#' @param top how many top cytobands to be drawn. defaults to all.
#' @param showTumorSampleBarcodes logical to include sample names.
#' @param clinicalData data.frame with columns containing Tumor_Sample_Barcodes and rest of columns with annotations.
#' @param clinicalFeatures columns names from `clinicalData` to be drawn in the plot. Dafault NULL.
#' @param sortByAnnotation logical sort oncomatrix (samples) by provided `clinicalFeatures`. Defaults to FALSE. column-sort
#' @param annotationColor list of colors to use for clinicalFeatures. Default NULL.
#' @param bandsToIgnore do not show these bands in the plot Default NULL.
#' @param removeNonAltered Logical. If \code{TRUE} removes samples with no mutations in the oncoplot for better visualization. Default \code{FALSE}.
#' @param colors named vector of colors Amp and Del events.
#' @param fontSize font size for cytoband names. Default 10.
#' @return None.
#' @examples
#' all.lesions <- system.file("extdata", "all_lesions.conf_99.txt", package = "maftools")
#' amp.genes <- system.file("extdata", "amp_genes.conf_99.txt", package = "maftools")
#' del.genes <- system.file("extdata", "del_genes.conf_99.txt", package = "maftools")
#' scores.gistic <- system.file("extdata", "scores.gistic", package = "maftools")
#' laml.gistic = readGistic(gisticAllLesionsFile = all.lesions, gisticAmpGenesFile = amp.genes, gisticDelGenesFile = del.genes, gisticScoresFile = scores.gistic)
#' gisticOncoPlot(laml.gistic)
#' @import ComplexHeatmap
#' @import grid
#' @seealso \code{\link{oncostrip}}
#' @export


gisticOncoPlot = function (gistic, top = NULL,
                     showTumorSampleBarcodes = FALSE, clinicalData = NULL, clinicalFeatures = NULL, sortByAnnotation = FALSE,
                     annotationColor = NULL, bandsToIgnore = NULL,
                     removeNonAltered = FALSE, colors = NULL, fontSize = 10) {

  #set seed for consistancy.
  set.seed(seed = 1024)

  #Not so useful. Set default to FALSE.
  drawRowBar = FALSE
  drawColBar = FALSE
  writeMatrix = FALSE

  numMat = gistic@numericMatrix
  #rownames(numMat) = sapply(strsplit(x = rownames(numMat), split = ':'), '[', 2)
  mat_origin = gistic@cnMatrix
  #rownames(mat_origin) = sapply(strsplit(x = rownames(mat_origin), split = ':'), '[', 2)

  if(ncol(numMat) < 2){
    stop('Cannot create plot for single sample. Minimum two sample required ! ')
  }

  #remove genes from bandsToIgnore if any
  if(!is.null(bandsToIgnore)){
    numMat = numMat[!rownames(numMat) %in% bandsToIgnore,, drop = FALSE]
  }

  #choose user defined nuber of top genes
  if(!is.null(top)){
    if(nrow(numMat) < top){
      numMat = numMat
    }else{
      numMat = numMat[1:top, ]
    }
  }

  oncoPlot = TRUE #Change later
  bg = "#CCCCCC" #Default gray background

  #To remove samples with no mutations in top n genes, if user says removeNonAltered
  if(removeNonAltered){
    tsb = colnames(numMat)
    tsb.exclude = colnames(numMat[,colSums(numMat) == 0])
    tsb.include = tsb[!tsb %in% tsb.exclude]
    numMat = numMat[,tsb.include, drop = FALSE]
  }

  #Annotations
  if(!is.null(clinicalFeatures)){
    if(is.null(clinicalData)){
      stop("annotation data missing. Use argument annotation to provide one.")
    }else{
      data.table::setDF(clinicalData)
      if(length(clinicalFeatures[!clinicalFeatures %in% colnames(clinicalData)]) > 0){
        message('Following columns are missing from provided annotation data. Ignoring them..')
        print(clinicalFeatures[!clinicalFeatures %in% colnames(clinicalData)])
        clinicalFeatures = clinicalFeatures[clinicalFeatures %in% colnames(annotation)]
        if(length(clinicalFeatures) == 0){
          stop('Zero annotaions to add! Make sure at-least one of the provided clinicalFeatures are present in clinicalData')
        }
      }
      annotation = clinicalData[,c('Tumor_Sample_Barcode', clinicalFeatures)]
      annotation = data.frame(row.names = annotation$Tumor_Sample_Barcode ,annotation[,clinicalFeatures, drop = FALSE])
    }

    if(sortByAnnotation){
      numMat = sortByAnnotation(numMat = numMat, anno = annotation)
      annotation = annotation[colnames(numMat), , drop = FALSE]
    }
  }


  mat = mat_origin[rownames(numMat), , drop = FALSE]
  mat = mat[,colnames(numMat), drop = FALSE]
  mat[mat == ''] = 'xxx'

  #Bottom annotations
  if(!is.null(clinicalFeatures)){
    if(!is.null(annotationColor)){
      bot.anno = ComplexHeatmap::HeatmapAnnotation(df = annotation, col = annotationColor, annotation_legend_param = list(title_gp = gpar(fontface = "bold"),
                                                                                                                          labels_gp = gpar(fontface = "bold")))
    }else{
      bot.anno = ComplexHeatmap::HeatmapAnnotation(annotation, annotation_legend_param = list(title_gp = gpar(fontface = "bold"),
                                                                                              labels_gp = gpar(fontface = "bold")))
    }
  }

  #hard coded colors for variant classification if user doesnt provide any
  if(is.null(colors)){
    col = c('green', 'red', 'blue')
    names(col) = names = c('Del', 'Amp', 'Complex')
  }else{
    col = colors
  }

  variant.classes = unique(unlist(as.list(apply(mat_origin, 2, unique))))
  variant.classes = unique(unlist(strsplit(x = variant.classes, split = ';', fixed = TRUE)))
  variant.classes = variant.classes[!variant.classes %in% c('xxx')]

  type_col = structure(col[variant.classes], names = names(col[variant.classes]))
  type_col = type_col[!is.na(type_col)]

  type_name = structure(variant.classes, names = variant.classes)


  #------------------------------------Helper functions to add %, rowbar and colbar----------------------------------------------------

  ##This function adds percent rate
  anno_pct = function(index) {
    n = length(index)
    pct = apply(mat_origin[rev(index), ], 1, function(x) sum(!grepl("^\\s*$", x))/length(x)) * 100
    pct = paste0(round(pct), "%")
    grid::pushViewport(viewport(xscale = c(0, 1), yscale = c(0.5, n + 0.5)))
    grid::grid.text(pct, x = 1, y = seq_along(index), default.units = "native",
                    just = "right", gp = grid::gpar(fontsize = fontSize, fontface = "bold"))
    grid::upViewport()
  }

  ha_pct = ComplexHeatmap::HeatmapAnnotation(pct = anno_pct,
                                             width = grid::grobWidth(grid::textGrob("100%", gp = grid::gpar(fontsize = 10, fontface = "bold"))), which = "row")

  ##Following two funcs add grids
  add_oncoprint = function(type, x, y, width, height) {
    grid::grid.rect(x, y, width - unit(0.5, "mm"),
                    height - grid::unit(1, "mm"), gp = grid::gpar(col = NA, fill = bg))

    for (i in 1:length(variant.classes)) {
      if (any(type %in% variant.classes[i])) {
        grid::grid.rect(x, y, width - unit(0.5, "mm"), height -
                          grid::unit(1, "mm"), gp = grid::gpar(col = NA, fill = type_col[variant.classes[i]]))
      }
    }
  }

  #This is the main cel function which is passed to ComplexHeatmap::Hetamap()
  celFun = function(j, i, x, y, width, height, fill) {
    type = mat[i, j]
    if(type != 'xxx'){
      typeList = unlist(strsplit(x = as.character(type), split = ';'))
      if(length(typeList) > 1){
        for(i in 1:length(typeList)){
          add_oncoprint(typeList[i], x, y, width, height)
        }
      }else{
        for(i in 1:length(typeList)){
          add_oncoprint(typeList[i], x, y, width, height)
        }
      }

    }else{
      add_oncoprint(type, x, y, width, height)
    }
  }

  #---------------------------------------------------------------------------

      if(is.null(clinicalFeatures)){
        ht = ComplexHeatmap::Heatmap(mat, rect_gp = grid::gpar(type = "none"), cell_fun = celFun,
          row_names_gp = grid::gpar(fontsize = fontSize, fontface = "bold"),
          show_column_names = showTumorSampleBarcodes, show_heatmap_legend = FALSE)
      }else{
        ht = ComplexHeatmap::Heatmap(mat, rect_gp = grid::gpar(type = "none"), cell_fun = celFun,
          row_names_gp = grid::gpar(fontsize = fontSize, fontface = "bold"),
          show_column_names = showTumorSampleBarcodes, show_heatmap_legend = FALSE,
          bottom_annotation = bot.anno)
      }


    ht_list = ha_pct + ht

    legend = grid::legendGrob(labels = type_name[names(type_col)],  pch = 15, gp = grid::gpar(col = type_col, fontface = "bold"), nrow = 2)

    ComplexHeatmap::draw(ht_list, newpage = FALSE, annotation_legend_side = "bottom", annotation_legend_list = list(legend))
}
