#'Function to convert any numerical table to a grid of coloured squares.
#'
#'@description This function converts a numerical data matrix in a coloured grid. Useful in a slide or article, to present tabular results as colors instead of numbers.
#'
#'@param table numerical matrix containing the values to be displayed in a colored image.
#'@param colors A vector with the color sequence to use in the grid.
#'@param brks A vector with the intervals to split the data into. There must be one \code{brks} more than the number of \code{colors}.
#'@param title The title of the grid. Default is NULL (no title). 
#'@param title.color Color to use for the title (default is dark blue).
#'@param xtitle Title of the x-axis (default is NULL)
#'@param ytitle Title of the y-axis (default is NULL)
#'@param xlabels Vector of length ncol(\code{table}) with the labels of the x-axis (default is a sequence from 1 to the number of columns).
#'@param xvert If x-axis labels are too long, it is possible to place them vertically by setting \code{xvert} to TRUE (default is FALSE). 
#'@param ylabels Vector of length nrow(\code{table}) with the labels of the y-axis (default is a sequence from 1 to the number of rows).
#'@param line Distance of the title of the x-axis from the x-axis (default is 3 lines). Adjust as necessary if your x-axis labels are long.
#'@param figure.width If the form of the grid cells is not perfectly squared, it is possible adjust it by multiplying the grid width for this factor (default is 1).
#'@param legend Set it to FALSE not to draw the grid color legend (default is TRUE).
#'@param legend.width If the width of the color legend is too small or too large, it can be adjusted by increasing or decreasing the legend width (default is 0.15)
#'@param file Set the path and the filename where the .png image of the grid will be saved (default is 'PlotMatrix.png' in the working directory).
#'@param ... Set additional parameters to pass to draw the color legend with function ColorBar() of package s2dverification.
#'
#'@return No data is returned. Only the grid image is saved in a .png file specified by the user.
#'
#'@examples 
#'#Example with random data (by default it is saved in the working directory, but the user can specify a different one):
#' 
#' PlotMatrix(table = matrix(rnorm(n = 120, mean = 0.3), 10, 12),
#'           colors = c('white','#fef0d9','#fdd49e','#fdbb84','#fc8d59','#e34a33','#b30000', '#7f0000'),
#'           brks = c(-1, 0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 1),
#'           title = "Mean Absolute Error", xtitle = "Forecast time (month)", ytitle = "Start date",
#'           xlabels = c("Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"))
#'
#'@export

PlotMatrix <- function(table, colors, brks, title = NULL, title.color = "royalblue4", xtitle = NULL, ytitle = NULL, xlabels = NULL,
                       xvert = FALSE, ylabels = NULL, line = 3, figure.width = 1, legend = TRUE, legend.width = 0.15, file = NULL, ...){

  # Check variables:  
  if (!is.matrix(table))
    stop("Input values are not a matrix")
  if (!is.numeric(table))
    stop("Input values are not always numbers")
  if (is.null(colors) || length(colors) < 2)
    stop("You have to specify a color palette of at least 2 colors")
  if (is.null(brks) || length(brks) < 2)
    stop("You have to specify 2 or more intervals")
  n.colors <- length(colors) ## number of colours
  n.brks <- length(brks) ## number of intervals
  if (n.brks != n.colors + 1)
    stop("There must be one break more than the number of colors")
  n.cols <- ncol(table) ## number of columns of the image
  n.rows <- nrow(table) ## number of rows of the image
  if (n.cols < 2)
    stop("Matrix must have at least two columns")
  if (n.rows < 2)
    stop("Matrix must have at least two rows")
  if (!is.null(xlabels) && length(xlabels) != n.cols)
      stop("The number of x labels must be equal to the number of columns of the data matrix")    
  if (!is.null(ylabels) && length(ylabels) != n.rows)
      stop("The number of y labels must be equal to the number of rows of the data matrix")
  if (!is.numeric(figure.width) || figure.width < 0)
      stop("figure.width must be a positive number")
  if (!is.numeric(legend.width) || legend.width < 0 || legend.width > 0.5)
      stop("legend.width must be a number from 0 to 0.5")
    
  # Print output file:
  if (is.null(file)) file.output <- paste0(getwd(), "/PlotMatrix.png") else file.output <- file
  print(paste0("Saving grid image in: ", file.output))

  # Generate image:
  png(file = file.output, width = 55 * n.cols * figure.width, height = 50 * n.rows) 
  plot.new()
    
  # Draw empty plot:
  par(mar = c(4, 4, 1, 0), fig = c(0.1, 1 - legend.width, 0.1, 0.9), new = TRUE)
  plot(1, 1, type = "n", xaxt = "n", yaxt = "n", ylim = c(0.5, n.rows + 0.5), xlim = c(-0.5, n.cols - 1 + 0.5), ann = F,  bty = "n")
    
  # Add axes titles:
  label.size <- 1.2 * (max(n.cols, n.rows) / 10) ^ 0.5        
  mtext(side = 1, text = xtitle, line = line, cex = label.size, font = 3)
  mtext(side = 2, text = ytitle, line = 3, cex = label.size, font = 3)

  # Add plot title:
  if (is.null(title.color)) title.color <- "royalblue4"
  mtext(side = 3, text = title, cex = 1.75 * (n.rows / 10) ^ 0.7, col = title.color)

  # Add axis labels:
  axis.size <- (max(n.cols, n.rows) / 10) ^ 0.3
  if (is.null(xlabels)) xlabels = 1:n.cols
  if (is.null(ylabels)) ylabels = 1:n.rows
  axis(1, at = seq(0, n.cols-1), las = ifelse(xvert, 2, 1), labels = xlabels, cex.axis = axis.size, tck = 0, lwd = 0, line = - 1 - (n.rows / 10 - 1))  ## Add x-axis labels
  axis(2, at = seq(1, n.rows), las = 1, labels = rev(ylabels), cex.axis = axis.size, tck = 0, lwd = 0, line = 0.5 - n.cols / 10)     ## Add y-axis labels

  # Create an array of colors instead of numbers (it starts all gray):                
  array.colors <- array("gray", c(n.rows, n.cols))
  for (int in n.colors:1) array.colors[table <= brks[int + 1]] <- colors[int]

  # fill with colors the cells in the figure:
  for (p in 1:n.rows){
    for (l in 0:(n.cols - 1)){
      polygon(c(0.5 + l - 1, 0.5 + l - 1, 1.5 + l - 1, 1.5 + l - 1),
              c(-0.5 + n.rows + 1 - p, 0.5 + n.rows + 1 - p, 0.5 + n.rows + 1 - p, -0.5 + n.rows + 1 - p), col = array.colors[p, 1 + l], border = "black")
    }
  }

  # Draw color legend:
  if (legend){
    par(fig = c(1 - legend.width - 0.01, 1 - legend.width + legend.width * min(1, 10 / n.cols), 0.3, 0.8), new=TRUE)
    legend.label.size <- (max(n.cols, n.rows) / 10) ^ 0.4
    ColorBar(brks, cols = colors, vert = TRUE, label_scale = legend.label.size, subsample = 1, ...)
  }
    
  dev.off()  
}


