#' @name ggInterval_indexImage
#' @title Index image plot for interval-valued data
#' @description Visualize interval-valued observations with color strips.
#' For a single variable, the display acts as a color-based analogue of an
#' index plot. When \code{plotAll = TRUE}, the function produces a
#' multivariate image plot across all continuous interval-valued variables.
#' @import ggplot2 ggthemes
#' @importFrom RSDA is.sym.interval
#' @importFrom ggpubr ggarrange
#' @param data A ggInterval object. It can also be either RSDA object or
#' classical data frame,which will be automatically convert to ggInterval
#' data.
#' @param mapping  Set of aesthetic mappings created by aes() or aes_().
#' If specified and inherit. aes = TRUE (the default),
#' it is combined with the default mapping at the top level of
#' the plot. You must supply mapping if there is no plot mapping.
#' @param column_condition Logical. If \code{TRUE}, the color scale is
#' applied separately within each variable (column condition). If
#' \code{FALSE}, one common color scale is applied to the whole matrix
#' (matrix condition).
#' @param full_strip Logical. If \code{TRUE}, each strip spans the full
#' plotting width. If \code{FALSE}, strip widths reflect the interval ranges.
#' @param plotAll Logical. If \code{TRUE}, produce a multivariate image plot
#' for all continuous interval-valued variables. The default is \code{FALSE}.
#' @return Return a ggplot2 object.
#' @usage ggInterval_indexImage(data = NULL, mapping = aes(NULL),
#' column_condition = TRUE, full_strip = FALSE, plotAll = FALSE)
#' @examples
#' mydata <- ggInterval::facedata
#' p <- ggInterval_indexImage(mydata, aes(x = AD),
#'   full_strip = TRUE, column_condition = TRUE)
#' # Recommend adding coord_flip() to make the single-variable display clearer.
#' p + coord_flip()
#' ggInterval_indexImage(
#'   mydata,
#'   plotAll = TRUE,
#'   full_strip = TRUE,
#'   column_condition = FALSE
#' ) +
#'   scale_colour_distiller(palette = "Blues", direction = 1)
#' ggInterval_indexImage(mydata, plotAll = TRUE, full_strip = FALSE)
#'
#' @export
ggInterval_indexImage <- function(data = NULL,
                                  mapping = aes(NULL),
                                  column_condition = TRUE,
                                  full_strip = FALSE,
                                  plotAll = FALSE) {
  #data preparing
  argsNum <- length(mapping)
  args <- lapply(mapping[1:argsNum], FUN = rlang::get_expr)
  this.x <- args$x
  this.y <- args$y
  
  #test data illegal
  ggSymData <- testData(data)
  iData <- ggSymData$intervalData
  myHeatMapNames <- rownames(iData)
  if (plotAll) {
    if (!is.null(this.x) | !is.null(this.y)) {
      warning("Using heatmap presentation cannot specify variables.")
    }
  } else{
    testXY(iData, this.x, this.y)
  }
  
  p <- dim(iData)[2]
  n <- dim(iData)[1]
  #test big o
  if (full_strip == FALSE & dim(iData)[1] > 200) {
    stop("Out of time limits")
  }
  if (full_strip == TRUE & dim(iData)[1] > 50) {
    stop("Out of time limits")
  }
  #start process
  datasetMin <- min(ggSymData$statisticsDF$min)
  datasetMax <- max(ggSymData$statisticsDF$max)
  #allDataMean <- mean(unlist(ggSymData$statisticsDF$min, ggSymData$statisticsDF$max))
  
  
  with(data, {
    #add heatmap
    if (plotAll) {
      #set adjust ggarrange width scale
      widthScale <- 7
      
      #get numerical data
      numericData <- unlist(lapply(data.frame(iData[1:dim(iData)[2]]) , FUN = is.sym.interval))
      iData <- iData[, which(numericData)]
      
      #scale
      if (column_condition) {
        iData <- scale_sym_table(iData, n, p)$intervalData
      }
      
      d <- data.frame(NULL)
      for (i in colnames(iData)) {
        a <- iData[[i]]$min
        b <- iData[[i]]$max
        adjustStrip <- min(b - a) / 50
        d <- rbind(d, data.frame(
          buildPlotData(a, b, adjustStrip, n, full_strip, datasetMax),
          group = factor(i)
        ))
      }
    } else{
      #end headmap
      
      #get attr
      if (any(unlist(lapply(
        as.data.frame(data[, 1:p]),
        FUN = identical,
        x = eval(this.x)
      )))) {
        attr <- which(unlist(lapply(
          as.data.frame(data[, 1:p]),
          FUN = identical,
          x = eval(this.x)
        )))
        attr <- names(attr)
      } else if (any(unlist(lapply(
        as.data.frame(data[, 1:p]),
        FUN = identical,
        x = eval(this.y)
      )))) {
        attr <- which(unlist(lapply(
          as.data.frame(data[, 1:p]),
          FUN = identical,
          x = eval(this.y)
        )))
        attr <- names(attr)
      } else{
        stop("ERROR : Cannot find variables in aes(...)")
      }
      if (p == 1) {
        attr = colnames(data)
      }
      #test attribute illegal
      if (all(!is.numeric(data[[attr]]) , !RSDA::is.sym.interval(data[[attr]]))) {
        stop("ERROR : Variables in Min-Max Plot can only be numeric.")
      }
      
      #build data frame for ggplot
      a <- iData[[attr]]$min
      b <- iData[[attr]]$max
      
      #whether full strip (if partial strip)
      #debug for separate strip "adjustStrip"
      adjustStrip <- min(b - a) / 50
    }
    
    if (!full_strip) {
      if (!plotAll) {
        d <- buildPlotData(a, b, adjustStrip, n, full_strip, datasetMax)
      }
      #whether column condition
      if (!column_condition) {
        midp <- (datasetMin + datasetMax) / 2
        #midp <- allDataMean
        #midp<-(max(d$y)+min(d$y))/2
        NAME <- "Matrix Condition"
        myColScale <- "scale_color_gradient2(low = 'blue', mid = 'yellow', high = 'red',
                              midpoint = midp,
                              name = 'Value',
                              breaks=c(min(d$y),max(d$y)),
                              labels = c(round(min(d$y)),round(max(d$y))))"
        #breaks=c(min(d$y),max(d$y)),
        #labels = c(round(min(d$y)),round(max(d$y))))
        
        if (plotAll) {
          base <- ggplot(d, aes(
            x = x,
            xend = xend,
            y = y,
            yend = y,
            color = y
          )) +
            geom_segment(linewidth = 3) + facet_grid(. ~ group) +
            eval(parse(text = myColScale)) +
            coord_flip() + scale_x_continuous(breaks = 1:n, label = myHeatMapNames) +
            labs(x = "Concepts", y = "Values") +
            theme(legend.position = "bottom",
                  legend.title = element_blank())
          
          return(base)
        }
      } else{
        #column control
        #midp<-(max(d$y)+min(d$y))/2
        midp <- mean(d$y)
        #midp<-(datasetMin+datasetMax)/2
        NAME <- "Column Condition"
        myColScale <- "scale_color_gradient2(low = 'blue', mid = 'yellow', high = 'red',
                              midpoint = midp,
                              name = 'Value',
                              breaks=c(min(d$y),max(d$y)),
                              labels = c(round(min(d$y)),round(max(d$y))))"
        #c(round(datasetMin),round(datasetMax)))
        
        if (plotAll) {
          #midp<-(max(d$y)+min(d$y))/2
          midp <- 0
          p <- ggplot(d, aes(
            x = x,
            xend = xend,
            y = y,
            yend = yend,
            color = y
          ))
          
          p <- p + geom_segment(linewidth = 3) +
            scale_color_gradient2(
              low = 'blue',
              mid = 'yellow',
              high = 'red',
              midpoint = midp,
              breaks = c(min(d$y), max(d$y)),
              labels = c("min", "max")
            ) +
            scale_x_continuous(breaks = c(1:n), labels = myHeatMapNames) +
            coord_flip() +
            guides(fill = "none", alpha = "none") +
            facet_grid(. ~ group) +
            labs(x = "Concepts", y = "") +
            theme(legend.position = "bottom",
                  legend.title = element_blank()) +
            scale_y_continuous(breaks = NULL)
          return(p)
          
          # base <- ggplot(d, aes(x = x, xend = xend, y = y, yend = y,color=y)) +
          #   geom_segment(size = 3) + facet_grid(. ~ group) +
          #   eval(parse(text=myColScale))+
          #   coord_flip()+scale_x_continuous(breaks = 1:n, label=myHeatMapNames)+
          #   labs(x="Concepts",y="Values")+
          #   theme(legend.position="bottom",
          #         legend.title = element_blank())
          #
          # return(base)
          
          # u<-1
          # myp <- NULL
          # for(ele in levels(d$group)){
          #   tempData <- dplyr::filter(d, d$group == ele)
          #   myp[[u]] <- myplot(tempData, u, NAME, myHeatMapNames, n, ele,full_strip)
          #   u<-u+1
          # }
          #
          # #v <- seq(min(d$y),max(d$y),(max(d$y)-min(d$y))/(1000-1))
          # #adjust grid
          # maxChar <- max(unlist(lapply(myHeatMapNames, nchar)))
          # adjustWidth <- 1 + sqrt(maxChar)/widthScale
          # base <- ggarrange(plotlist=myp, nrow=1,
          #                   widths = c(adjustWidth,rep(1, p-1)))
          #
          # v <- seq(1,1000)
          # return(ggarrange(base, buildColLegend(v),nrow=2,heights=c(8,1)))
        }
      }
      
      #plot
      ggplot(d, aes(
        x = x,
        xend = xend,
        y = y,
        yend = yend,
        color = y
      )) +
        geom_segment(linewidth = 3) + eval(parse(text = myColScale)) +
        labs(y = attr,
             x = "",
             title = paste0("Index Image-", NAME)) +
        scale_x_continuous(breaks = c(1:n), labels = rownames(iData))
    }
    else{
      # if full strip
      #adjust
      #newN<-sort(runif((n)*2,1,n))
      if (!plotAll) {
        d <- buildPlotData(a, b, adjustStrip, n, full_strip, datasetMax)
      }
      
      #whether column condition
      if (!column_condition) {
        midp <- (datasetMin + datasetMax) / 2
        #midp <- allDataMean
        NAME <- "Matrix Condition"
        myColScale <- "scale_color_gradient2(low = 'blue', mid = 'yellow', high = 'red',
                              midpoint = midp,
                              name = 'Value',
                              breaks=c(min(d$value),max(d$value)),
                              labels = c(round(min(d$value)),round(max(d$value))))"
        
        if (plotAll) {
          base <- ggplot(d, aes(
            x = x,
            xend = xend,
            y = y,
            yend = y,
            color = value
          )) +
            geom_segment(linewidth = 3) + facet_grid(. ~ group) +
            eval(parse(text = myColScale)) +
            coord_flip() + scale_x_continuous(breaks = 1:n, label = myHeatMapNames) +
            labs(x = "Concepts", y = "Values") +
            theme(legend.position = "bottom",
                  legend.title = element_blank())
          return(base)
        }
        
      } else{
        # column condition
        midp <- (max(d$value) + min(d$value)) / 2
        NAME <- "Column Condition"
        myColScale <- "scale_color_gradient2(low = 'blue', mid = 'yellow', high = 'red',
                              midpoint = midp,
                              name = 'Value',
                              breaks=c(min(d$value),max(d$value)),
                              labels = c(round(min(d$value)),round(max(d$value))))"
        
        if (plotAll) {
          midp <- 0
          p <- ggplot(d, aes(
            x = x,
            xend = xend,
            y = y,
            yend = y,
            color = value
          ))
          
          p <- p + geom_segment(linewidth = 3) +
            scale_color_gradient2(
              low = 'blue',
              mid = 'yellow',
              high = 'red',
              midpoint = midp,
              breaks = c(min(d$value), max(d$value)),
              labels = c("min", "max")
            ) +
            scale_x_continuous(breaks = c(1:n), labels = myHeatMapNames) +
            coord_flip() +
            guides(fill = "none", alpha = "none") +
            facet_grid(. ~ group) +
            labs(x = "Concepts", y = "") +
            theme(legend.position = "bottom",
                  legend.title = element_blank()) +
            scale_y_continuous(breaks = NULL)
          return(p)
          
          
          
          
          # u<-1
          # myp <- NULL
          # for(ele in levels(d$group)){
          #   tempData <- dplyr::filter(d, d$group == ele)
          #   myp[[u]] <- myplot(tempData, u, NAME, myHeatMapNames, n, ele, full_strip)
          #   u<-u+1
          # }
          #
          # #v <- seq(min(d$y),max(d$y),(max(d$y)-min(d$y))/(1000-1))
          # #adjust grid
          # maxChar <- max(unlist(lapply(myHeatMapNames, nchar)))
          # adjustWidth <- 1 + sqrt(maxChar)/widthScale
          # base <- ggarrange(plotlist=myp, nrow=1,
          #                   widths = c(adjustWidth, rep(1, p-1)))
          #
          # v <- seq(1,1000)
          #
          # return(ggarrange(base, buildColLegend(v),nrow=2,heights=c(12,1)))
          
        }
        
      }
      
      #plot
      ggplot(data = d, aes(
        x = x,
        xend = xend,
        y = y,
        yend = y,
        color = value
      )) +
        geom_segment(linewidth = 3) +
        eval(parse(text = myColScale)) +
        labs(y = attr,
             x = "",
             title = paste0("Index Image-", NAME)) +
        scale_x_continuous(breaks = c(1:n), labels = rownames(iData)) +
        scale_y_continuous(breaks = NULL)
    }
  })
}


buildPlotData <- function(a,
                          b,
                          adjustStrip,
                          n,
                          full_strip,
                          datasetMax) {
  if (!full_strip) {
    val <- mapply(
      a,
      b,
      FUN = function(x, y)
        seq(x, y, by = adjustStrip)
    )
    y <- unlist(val)
    mid <- rep(1:n, lengths(val))
    d <- data.frame(
      x = mid - 0.4,
      xend = mid + 0.4,
      y = y,
      yend = y
    )
  } else{
    datasetMax <- ceiling(datasetMax)
    adjustCoef <- ifelse(datasetMax * n > 2000, 1, ceiling(2000 / (datasetMax *
                                                                     n)))
    
    myAdjust <- seq(1, datasetMax, (datasetMax - 1) / (datasetMax * adjustCoef -
                                                         1))
    #debug for unequal bin image
    d2 <- data.frame(
      x = rep(1:n, each = datasetMax * adjustCoef) - 0.5,
      xend = rep(1.5:(n + 0.5), each = datasetMax * adjustCoef),
      y = rep(myAdjust, n)
    )
    val2 <- mapply(
      a,
      b,
      FUN = function(x, y)
        sort(runif(datasetMax * adjustCoef, x, y))
    )
    val <- matrix(val2, ncol = 1)
    d <- data.frame(d2, value = val)
  }
  return(d)
}


# buildColLegend <- function(v){
#     newd<-data.frame(x = rep(1:1000),
#                      xend = rep(1:1000),
#                      y = rep(1, 1000),
#                      yend = rep(2, 1000),
#                      val = v)
#     p2 <- ggplot(newd,aes(x=x,xend=xend,y=y,yend=yend,col=val))+
#       geom_segment()+
#       scale_color_gradient2(low = 'blue', mid = 'yellow', high = 'red',
#                             midpoint = (min(newd$val)+max(newd$val))/2,
#                             name = 'Value',
#                             breaks=c(min(newd$val),max(newd$val)),
#                             labels = c(round(min(newd$val)),round(max(newd$val))))+
#       guides(color=F,y=F)+theme_tufte()+labs(y=NULL,x=NULL)+
#       scale_x_continuous(breaks=c(0,1000),labels = c("min","max"))
#
#     temp<-ggplot()+theme_void()
#     temp2<-ggarrange(temp,p2,temp,nrow=1,widths = c(2,1,2))
#     return(temp2)
# }


myplot <- function(tempData,
                   u,
                   NAME,
                   myHeatMapNames,
                   n,
                   ele,
                   full_strip) {
  if (full_strip) {
    midp <- (max(tempData$value) + min(tempData$value)) / 2
    p <- ggplot(
      tempData,
      aes(
        x = tempData$x,
        xend = tempData$xend,
        y = tempData$y,
        yend = tempData$y,
        color = tempData$value
      )
    )
  } else{
    midp <- (max(tempData$y) + min(tempData$y)) / 2
    p <- ggplot(
      tempData,
      aes(
        x = tempData$x,
        xend = tempData$xend,
        y = tempData$y,
        yend = tempData$yend,
        color = tempData$y
      )
    )
  }
  p <- p + geom_segment(linewidth = 3) +
    scale_color_gradient2(
      low = 'blue',
      mid = 'yellow',
      high = 'red',
      midpoint = midp
    ) +
    labs(y = "",
         x = "",
         title = paste0("Index Image-", NAME)) +
    scale_x_continuous(breaks = c(1:n), labels = myHeatMapNames) +
    coord_flip() +
    guides(fill = "none",
           col = "none",
           alpha = "none") +
    theme(plot.title = element_text(hjust = 0.5)) + ggtitle(ele)
  
  if (u != 1) {
    p <- p + theme(axis.text.y = element_blank())
  }
  
  return(p)
}
scale_sym_table <- function(d, n, p) {
  temp1 <- sapply(
    1:p,
    FUN = function(x)
      unlist(data.frame(d[[x]]))
  )
  temp2 <- apply(temp1, 2, scale)
  newd <- data.frame(temp2[1:n, ], temp2[(n + 1):(n * 2), ])
  myd <- classic2sym(newd,
                     groupby = "customize",
                     minData = temp2[1:n, ],
                     maxData = temp2[(n + 1):(n * 2), ])
  colnames(myd$intervalData) <- colnames(d)
  return(myd)
}
