#' Draw gene-level radar plots across annotated cell groups
#'
#' @description
#' `CellWindX_GeneRadar()` visualizes the expression pattern of selected genes
#' across annotated cell groups using straight-line spider radar plots. For each
#' selected gene, the function generates two radar plots: one for the percentage
#' of expressing cells and another for average expression.
#'
#' @details
#' This function is designed to directly accept the output generated by
#' `CellWindX_TopMarkersStats()`. It uses the `marker_expr_by_group` table from
#' that result object, which should contain gene expression statistics across
#' cell groups.
#'
#' Each cell group is represented as one axis of the radar plot. Unlike polar
#' coordinate radar plots, this function manually calculates polygon coordinates,
#' resulting in straight polygon grid lines rather than curved circular grid
#' lines. This style is generally clearer for comparing cell-group-specific
#' expression patterns.
#'
#' The function draws two panels:
#'
#' \itemize{
#'   \item `pct_plot`: expression percentage across cell groups.
#'   \item `avg_plot`: average expression across cell groups.
#' }
#'
#' The expression percentage and average expression panels use intentionally
#' distinct color sets within the selected CellWindX palette. Three built-in
#' palettes are available: `"shanshui"`, `"chongqing_modern"`, and `"girlish"`.
#'
#' @param marker_result A result object returned by `CellWindX_TopMarkersStats()`,
#'   or a data frame containing marker expression statistics. If a data frame is
#'   provided, it must contain the columns `source_cluster`, `target_cluster`,
#'   `gene`, `pct_expr`, and `avg_expr`.
#' @param genes Character vector. Gene symbols to visualize.
#' @param source_cluster Character vector or `NULL`. Optional source-cluster
#'   filter. If provided, only marker statistics from the selected source
#'   cluster(s) are used. Default is `NULL`.
#' @param aggregate_fun Character string. Method used to aggregate duplicated
#'   gene-cell-group rows. One of `"mean"`, `"max"`, or `"first"`.
#'   Default is `"mean"`.
#' @param palette Character string. Built-in CellWindX palette. One of
#'   `"shanshui"`, `"chongqing_modern"`, or `"girlish"`.
#' @param scale_avg Logical. Whether to scale average expression values before
#'   plotting. Default is `TRUE`.
#' @param scale_pct Logical. Whether to scale expression percentage values by
#'   gene before plotting. If `FALSE`, the raw percentage values are used and
#'   capped by `pct_max`. Default is `FALSE`.
#' @param pct_max Numeric. Maximum value used to cap percentage values when
#'   `scale_pct = FALSE`. Default is `100`.
#' @param avg_scale_method Character string. Scaling method for average
#'   expression. One of `"max"`, `"zscore"`, or `"none"`. `"max"` rescales
#'   each gene to a 0-100 range by dividing by its maximum value. `"zscore"`
#'   performs gene-wise Z-score scaling and rescales the result to 0-100.
#'   `"none"` keeps the original average expression values. Default is `"max"`.
#' @param grid_levels Numeric vector. Radar grid levels. These values determine
#'   the radius of the straight polygon grid lines. Default is
#'   `c(25, 50, 75, 100)`.
#' @param axis_label_size Numeric. Font size of cell-group labels placed around
#'   the radar plot. Default is `5.2`.
#' @param grid_label_size Numeric. Font size of radar grid labels. Default is
#'   `3.2`.
#' @param facet_title_size Numeric. Font size of facet titles when multiple
#'   genes are plotted. Default is `12`.
#' @param line_width Numeric. Width of radar polygon lines. Default is `1.2`.
#' @param point_size Numeric. Size of points on radar axes. Default is `2.8`.
#' @param fill_alpha Numeric. Transparency of polygon fill. Values should
#'   usually range from 0 to 1. Default is `0.18`.
#' @param facet Logical. Whether to draw multiple genes as separate facets.
#'   Default is `TRUE`.
#' @param ncol Integer or `NULL`. Number of columns used in facet layout when
#'   `facet = TRUE`. Default is `NULL`.
#' @param show_points Logical. Whether to show points on radar axes.
#'   Default is `TRUE`.
#' @param show_fill Logical. Whether to fill radar polygons. Default is `TRUE`.
#' @param show_grid_label Logical. Whether to show numeric grid labels.
#'   Default is `TRUE`.
#' @param output_file Character string or `NULL`. Optional path used to save the
#'   combined radar plot. Supported formats depend on [ggplot2::ggsave()],
#'   such as `.pdf`, `.png`, `.tiff`, or `.svg`. Default is `NULL`.
#' @param output_width Numeric. Width of the saved plot in inches. Default is
#'   `11`.
#' @param output_height Numeric. Height of the saved plot in inches. Default is
#'   `5.5`.
#' @param dpi Numeric. Resolution used when saving raster formats. Default is
#'   `300`.
#'
#' @return A list with class `"CellWindX_GeneRadar"` containing:
#' \describe{
#'   \item{pct_plot}{A ggplot object showing expression percentage.}
#'   \item{avg_plot}{A ggplot object showing average expression.}
#'   \item{combined_plot}{A patchwork object combining percentage and average expression plots.}
#'   \item{plot_data}{A data frame used for plotting.}
#'   \item{pct_coord}{Radar coordinates for the expression percentage plot.}
#'   \item{avg_coord}{Radar coordinates for the average expression plot.}
#'   \item{palette}{The selected CellWindX palette.}
#'   \item{genes}{Genes used for visualization.}
#'   \item{parameters}{A list of function parameters used in the plot.}
#' }
#'
#' @author Xiaofeng Yang, Chongqing Medical University
#'
#' @examples
#' marker_df <- data.frame(
#'   source_cluster = rep(c("T cell", "B cell"), each = 4),
#'   target_cluster = rep(c("T cell", "B cell", "Myeloid", "Platelet"), times = 2),
#'   gene = rep(c("CD3D", "MS4A1"), each = 4),
#'   pct_expr = c(92, 8, 15, 4, 6, 88, 12, 3),
#'   avg_expr = c(2.8, 0.2, 0.5, 0.1, 0.1, 2.5, 0.4, 0.1),
#'   stringsAsFactors = FALSE
#' )
#'
#' radar_res <- CellWindX_GeneRadar(
#'   marker_result = marker_df,
#'   genes = c("CD3D", "MS4A1"),
#'   palette = "shanshui",
#'   scale_avg = TRUE,
#'   avg_scale_method = "max",
#'   facet = TRUE,
#'   ncol = 2
#' )
#'
#' radar_res$combined_plot
#'
#' @export
CellWindX_GeneRadar <- function(
    marker_result,
    genes,
    source_cluster = NULL,
    aggregate_fun = c("mean", "max", "first"),
    palette = c("shanshui", "chongqing_modern", "girlish"),
    scale_avg = TRUE,
    scale_pct = FALSE,
    pct_max = 100,
    avg_scale_method = c("max", "zscore", "none"),
    grid_levels = c(25, 50, 75, 100),
    axis_label_size = 5.2,
    grid_label_size = 3.2,
    facet_title_size = 12,
    line_width = 1.2,
    point_size = 2.8,
    fill_alpha = 0.18,
    facet = TRUE,
    ncol = NULL,
    show_points = TRUE,
    show_fill = TRUE,
    show_grid_label = TRUE,
    output_file = NULL,
    output_width = 11,
    output_height = 5.5,
    dpi = 300
) {

  # -----------------------------
  # 1. Package check
  # -----------------------------
  if (!requireNamespace("ggplot2", quietly = TRUE)) {
    stop("Package 'ggplot2' is required.")
  }
  if (!requireNamespace("dplyr", quietly = TRUE)) {
    stop("Package 'dplyr' is required.")
  }
  if (!requireNamespace("tidyr", quietly = TRUE)) {
    stop("Package 'tidyr' is required.")
  }
  if (!requireNamespace("patchwork", quietly = TRUE)) {
    stop("Package 'patchwork' is required. Please install.packages('patchwork').")
  }

  aggregate_fun <- match.arg(aggregate_fun)
  palette <- match.arg(palette)
  avg_scale_method <- match.arg(avg_scale_method)

  if (missing(genes) || length(genes) == 0) {
    stop("'genes' must be provided.")
  }

  genes <- unique(as.character(genes))

  # -----------------------------
  # 2. CellWindX palettes
  # pct_colors and avg_colors are intentionally different
  # -----------------------------
  CellWindX_palettes <- list(

    shanshui = list(
      pct_colors = c(
        "#6F8F9F", "#8FB9A8", "#A7C7D9", "#7FA6C7", "#738A99",
        "#AFC8BA", "#C9D6DF", "#8A9A8F", "#6E7F80", "#B7C8A3",
        "#A6B1C2", "#C6D8D3", "#7C9A92", "#9BB8C2", "#5F7F8A",
        "#B5C7B1", "#91B3A2", "#82A6B3", "#D0DDD7", "#789395"
      ),
      avg_colors = c(
        "#9D9AC7", "#B58C9E", "#C6B7D9", "#D1A7A0", "#9E8FB2",
        "#BFA58A", "#D8C7A3", "#E2D8C3", "#B5A789", "#C7A6B8",
        "#8E89B8", "#BA99AD", "#D6C6B9", "#A88FAF", "#C9B6D8",
        "#B59B8F", "#D9B7B3", "#A696C8", "#CBBDA4", "#907EA4"
      )
    ),

    chongqing_modern = list(
      pct_colors = c(
        "#2F4858", "#33658A", "#4A90A4", "#86BBD8", "#1C7293",
        "#00A6A6", "#3A506B", "#355070", "#7D8491", "#B8B8D1",
        "#264653", "#287271", "#457B9D", "#118AB2", "#073B4C",
        "#52796F", "#354F52", "#669BBC", "#003049", "#5C677D"
      ),
      avg_colors = c(
        "#F26419", "#F6AE2D", "#D64550", "#8E5572", "#5D5179",
        "#E0A458", "#C8553D", "#6D597A", "#758E4F", "#2A2D34",
        "#E76F51", "#F4A261", "#E63946", "#9D4EDD", "#FF7F51",
        "#BC4749", "#B56576", "#C77DFF", "#FFB703", "#A44A3F"
      )
    ),

    girlish = list(
      pct_colors = c(
        "#A0C4FF", "#BFD7FF", "#A0E7E5", "#B5EAD7", "#B4F8C8",
        "#D4F0F0", "#CCE2CB", "#C7CEEA", "#CDE7FF", "#BDE0FE",
        "#90DBF4", "#98F5E1", "#8EECF5", "#C1FBA4", "#B8E0D2",
        "#AED9E0", "#CDEAC0", "#A2D2FF", "#CAF0F8", "#B9FBC0"
      ),
      avg_colors = c(
        "#FF8FAB", "#FF9AA2", "#FFB7B2", "#FFD6E0", "#F6C1D5",
        "#F7A8B8", "#D5AAFF", "#F3C4FB", "#E7C6FF", "#FFABAB",
        "#FFC3A0", "#FFDAC1", "#FBE7C6", "#FFAFCC", "#FFC8DD",
        "#FFCAD4", "#F4ACB7", "#E0BBE4", "#FFB5A7", "#FFCCD5"
      )
    )
  )

  pal_use <- CellWindX_palettes[[palette]]

  # -----------------------------
  # 3. Extract marker expression table
  # -----------------------------
  if (is.list(marker_result) && "marker_expr_by_group" %in% names(marker_result)) {
    expr_df <- marker_result$marker_expr_by_group
  } else if (is.data.frame(marker_result)) {
    expr_df <- marker_result
  } else {
    stop(
      "marker_result must be either the output list from CellWindX_TopMarkersStats() ",
      "or a data.frame containing marker expression statistics."
    )
  }

  required_cols <- c(
    "source_cluster",
    "target_cluster",
    "gene",
    "pct_expr",
    "avg_expr"
  )

  missing_cols <- setdiff(required_cols, colnames(expr_df))

  if (length(missing_cols) > 0) {
    stop(
      "The following required columns are missing: ",
      paste(missing_cols, collapse = ", ")
    )
  }

  expr_df <- as.data.frame(expr_df)
  expr_df$source_cluster <- as.character(expr_df$source_cluster)
  expr_df$target_cluster <- as.character(expr_df$target_cluster)
  expr_df$gene <- as.character(expr_df$gene)
  expr_df$pct_expr <- as.numeric(expr_df$pct_expr)
  expr_df$avg_expr <- as.numeric(expr_df$avg_expr)

  if (!is.null(source_cluster)) {
    expr_df <- expr_df[expr_df$source_cluster %in% source_cluster, , drop = FALSE]
  }

  expr_df <- expr_df[expr_df$gene %in% genes, , drop = FALSE]

  if (nrow(expr_df) == 0) {
    stop(
      "None of the selected genes were found in marker_result. ",
      "Please check genes or source_cluster."
    )
  }

  missing_genes <- setdiff(genes, unique(expr_df$gene))

  if (length(missing_genes) > 0) {
    warning(
      "The following genes were not found and will be ignored: ",
      paste(missing_genes, collapse = ", ")
    )
  }

  # -----------------------------
  # 4. Aggregate duplicated gene-target rows
  # -----------------------------
  if (aggregate_fun == "mean") {
    plot_df <- expr_df |>
      dplyr::group_by(gene, target_cluster) |>
      dplyr::summarise(
        pct_expr = mean(pct_expr, na.rm = TRUE),
        avg_expr = mean(avg_expr, na.rm = TRUE),
        .groups = "drop"
      )
  }

  if (aggregate_fun == "max") {
    plot_df <- expr_df |>
      dplyr::group_by(gene, target_cluster) |>
      dplyr::summarise(
        pct_expr = max(pct_expr, na.rm = TRUE),
        avg_expr = max(avg_expr, na.rm = TRUE),
        .groups = "drop"
      )
  }

  if (aggregate_fun == "first") {
    plot_df <- expr_df |>
      dplyr::group_by(gene, target_cluster) |>
      dplyr::slice(1) |>
      dplyr::ungroup() |>
      dplyr::select(gene, target_cluster, pct_expr, avg_expr)
  }

  # -----------------------------
  # 5. Preserve cell group order
  # -----------------------------
  cell_order <- unique(expr_df$target_cluster)
  cell_order <- cell_order[cell_order %in% unique(plot_df$target_cluster)]

  plot_df$target_cluster <- factor(
    plot_df$target_cluster,
    levels = cell_order
  )

  plot_df$gene <- factor(
    plot_df$gene,
    levels = genes[genes %in% unique(plot_df$gene)]
  )

  plot_df <- tidyr::complete(
    plot_df,
    gene,
    target_cluster,
    fill = list(
      pct_expr = 0,
      avg_expr = 0
    )
  )

  plot_df$target_cluster <- factor(
    plot_df$target_cluster,
    levels = cell_order
  )

  plot_df$gene <- factor(
    plot_df$gene,
    levels = genes[genes %in% unique(as.character(plot_df$gene))]
  )

  # -----------------------------
  # 6. Scaling
  # -----------------------------
  plot_df$pct_value <- plot_df$pct_expr

  if (scale_pct) {
    plot_df <- plot_df |>
      dplyr::group_by(gene) |>
      dplyr::mutate(
        pct_value = ifelse(
          max(pct_expr, na.rm = TRUE) == 0,
          0,
          pct_expr / max(pct_expr, na.rm = TRUE) * 100
        )
      ) |>
      dplyr::ungroup()
  } else {
    plot_df$pct_value <- pmin(plot_df$pct_expr, pct_max)
  }

  plot_df$avg_value <- plot_df$avg_expr

  if (scale_avg) {

    if (avg_scale_method == "max") {
      plot_df <- plot_df |>
        dplyr::group_by(gene) |>
        dplyr::mutate(
          avg_value = ifelse(
            max(avg_expr, na.rm = TRUE) == 0,
            0,
            avg_expr / max(avg_expr, na.rm = TRUE) * 100
          )
        ) |>
        dplyr::ungroup()
    }

    if (avg_scale_method == "zscore") {
      plot_df <- plot_df |>
        dplyr::group_by(gene) |>
        dplyr::mutate(
          avg_value = as.numeric(scale(avg_expr))
        ) |>
        dplyr::ungroup()

      plot_df$avg_value[is.na(plot_df$avg_value)] <- 0

      min_v <- min(plot_df$avg_value, na.rm = TRUE)
      max_v <- max(plot_df$avg_value, na.rm = TRUE)

      if (max_v == min_v) {
        plot_df$avg_value <- 0
      } else {
        plot_df$avg_value <- (plot_df$avg_value - min_v) / (max_v - min_v) * 100
      }
    }
  }

  if (!scale_avg || avg_scale_method == "none") {
    plot_df$avg_value <- plot_df$avg_expr
  }

  # -----------------------------
  # 7. Convert values to radar coordinates
  # -----------------------------
  add_radar_coordinates <- function(df, value_col) {

    n_axis <- length(cell_order)

    angle_df <- data.frame(
      target_cluster = factor(cell_order, levels = cell_order),
      axis_id = seq_along(cell_order),
      angle = seq(0, 2 * pi, length.out = n_axis + 1)[-1],
      stringsAsFactors = FALSE
    )

    df2 <- dplyr::left_join(
      df,
      angle_df,
      by = "target_cluster"
    )

    df2$radius <- as.numeric(df2[[value_col]])
    df2$x <- df2$radius * sin(df2$angle)
    df2$y <- df2$radius * cos(df2$angle)

    df2 <- df2 |>
      dplyr::arrange(gene, axis_id)

    # close polygon by repeating the first point of each gene
    df_closed <- df2 |>
      dplyr::group_by(gene) |>
      dplyr::group_modify(function(.x, .y) {
        rbind(.x, .x[1, , drop = FALSE])
      }) |>
      dplyr::ungroup()

    return(list(
      data = df2,
      data_closed = df_closed,
      angle_df = angle_df
    ))
  }

  pct_coord <- add_radar_coordinates(plot_df, "pct_value")
  avg_coord <- add_radar_coordinates(plot_df, "avg_value")

  # -----------------------------
  # 8. Grid data: straight polygon grid lines
  # -----------------------------
  build_grid_data <- function(angle_df, grid_levels) {

    grid_poly <- do.call(
      rbind,
      lapply(grid_levels, function(r) {
        tmp <- angle_df
        tmp$radius <- r
        tmp$x <- r * sin(tmp$angle)
        tmp$y <- r * cos(tmp$angle)
        tmp$grid_level <- r
        tmp <- tmp[order(tmp$axis_id), , drop = FALSE]
        rbind(tmp, tmp[1, , drop = FALSE])
      })
    )

    axis_df <- angle_df
    axis_df$x <- 0
    axis_df$y <- 0
    axis_df$xend <- max(grid_levels) * sin(axis_df$angle)
    axis_df$yend <- max(grid_levels) * cos(axis_df$angle)

    label_df <- angle_df
    label_radius <- max(grid_levels) * 1.18
    label_df$x <- label_radius * sin(label_df$angle)
    label_df$y <- label_radius * cos(label_df$angle)
    label_df$label <- as.character(label_df$target_cluster)

    grid_label_df <- data.frame(
      x = 0,
      y = grid_levels,
      label = grid_levels,
      stringsAsFactors = FALSE
    )

    return(list(
      grid_poly = grid_poly,
      axis_df = axis_df,
      label_df = label_df,
      grid_label_df = grid_label_df
    ))
  }

  radar_grid <- build_grid_data(
    angle_df = pct_coord$angle_df,
    grid_levels = grid_levels
  )

  # -----------------------------
  # 9. Plot helper
  # -----------------------------
  gene_levels <- levels(plot_df$gene)
  n_genes <- length(gene_levels)

  pct_gene_cols <- pal_use$pct_colors[seq_len(min(n_genes, length(pal_use$pct_colors)))]
  avg_gene_cols <- pal_use$avg_colors[seq_len(min(n_genes, length(pal_use$avg_colors)))]

  names(pct_gene_cols) <- gene_levels[seq_along(pct_gene_cols)]
  names(avg_gene_cols) <- gene_levels[seq_along(avg_gene_cols)]

  make_spider_plot <- function(
    coord_obj,
    value_type = c("pct", "avg"),
    title,
    gene_cols
  ) {

    value_type <- match.arg(value_type)

    df_point <- coord_obj$data
    df_closed <- coord_obj$data_closed

    p <- ggplot2::ggplot()

    # straight polygon grid
    p <- p +
      ggplot2::geom_path(
        data = radar_grid$grid_poly,
        ggplot2::aes(
          x = x,
          y = y,
          group = grid_level
        ),
        color = "grey82",
        linewidth = 0.35
      ) +
      ggplot2::geom_segment(
        data = radar_grid$axis_df,
        ggplot2::aes(
          x = x,
          y = y,
          xend = xend,
          yend = yend
        ),
        color = "grey86",
        linewidth = 0.35
      )

    # radar polygon
    if (show_fill) {
      p <- p +
        ggplot2::geom_polygon(
          data = df_closed,
          ggplot2::aes(
            x = x,
            y = y,
            group = gene,
            fill = gene
          ),
          alpha = fill_alpha,
          color = NA
        )
    }

    p <- p +
      ggplot2::geom_path(
        data = df_closed,
        ggplot2::aes(
          x = x,
          y = y,
          group = gene,
          color = gene
        ),
        linewidth = line_width,
        lineend = "round"
      )

    if (show_points) {
      p <- p +
        ggplot2::geom_point(
          data = df_point,
          ggplot2::aes(
            x = x,
            y = y,
            color = gene
          ),
          size = point_size,
          alpha = 0.95
        )
    }

    # axis labels: larger cell group labels
    p <- p +
      ggplot2::geom_text(
        data = radar_grid$label_df,
        ggplot2::aes(
          x = x,
          y = y,
          label = label
        ),
        size = axis_label_size,
        fontface = "bold",
        color = "black",
        lineheight = 0.9
      )

    if (show_grid_label) {
      p <- p +
        ggplot2::geom_text(
          data = radar_grid$grid_label_df,
          ggplot2::aes(
            x = x,
            y = y,
            label = label
          ),
          size = grid_label_size,
          color = "grey45",
          hjust = -0.2
        )
    }

    p <- p +
      ggplot2::scale_color_manual(values = gene_cols) +
      ggplot2::scale_fill_manual(values = gene_cols) +
      ggplot2::coord_equal(
        xlim = c(-max(grid_levels) * 1.35, max(grid_levels) * 1.35),
        ylim = c(-max(grid_levels) * 1.35, max(grid_levels) * 1.35),
        clip = "off"
      ) +
      ggplot2::labs(
        title = title,
        color = "Gene",
        fill = "Gene"
      ) +
      ggplot2::theme_void(base_size = 12) +
      ggplot2::theme(
        plot.title = ggplot2::element_text(
          hjust = 0.5,
          face = "bold",
          size = 15
        ),
        legend.position = "right",
        legend.title = ggplot2::element_text(
          face = "bold",
          size = 10
        ),
        legend.text = ggplot2::element_text(size = 9),
        plot.margin = ggplot2::margin(18, 18, 18, 18)
      )

    if (facet && n_genes > 1) {
      p <- p +
        ggplot2::facet_wrap(
          ~ gene,
          ncol = ncol
        ) +
        ggplot2::theme(
          legend.position = "none",
          strip.text = ggplot2::element_text(
            face = "bold",
            size = facet_title_size
          )
        )
    }

    return(p)
  }

  # -----------------------------
  # 10. Build plots
  # -----------------------------
  pct_title <- ifelse(
    scale_pct,
    "Scaled expression percentage",
    "Expression percentage"
  )

  avg_title <- ifelse(
    scale_avg,
    paste0("Scaled average expression", " (", avg_scale_method, ")"),
    "Average expression"
  )

  pct_plot <- make_spider_plot(
    coord_obj = pct_coord,
    value_type = "pct",
    title = pct_title,
    gene_cols = pct_gene_cols
  )

  avg_plot <- make_spider_plot(
    coord_obj = avg_coord,
    value_type = "avg",
    title = avg_title,
    gene_cols = avg_gene_cols
  )

  combined_plot <- pct_plot + avg_plot + patchwork::plot_layout(ncol = 2)

  # -----------------------------
  # 11. Save output
  # -----------------------------
  if (!is.null(output_file)) {
    ggplot2::ggsave(
      filename = output_file,
      plot = combined_plot,
      width = output_width,
      height = output_height,
      dpi = dpi
    )
  }

  # -----------------------------
  # 12. Return
  # -----------------------------
  result <- list(
    pct_plot = pct_plot,
    avg_plot = avg_plot,
    combined_plot = combined_plot,
    plot_data = plot_df,
    pct_coord = pct_coord$data,
    avg_coord = avg_coord$data,
    palette = palette,
    genes = genes,
    parameters = list(
      source_cluster = source_cluster,
      aggregate_fun = aggregate_fun,
      scale_avg = scale_avg,
      scale_pct = scale_pct,
      avg_scale_method = avg_scale_method,
      pct_max = pct_max,
      grid_levels = grid_levels
    )
  )

  class(result) <- c("CellWindX_GeneRadar", class(result))

  return(result)
}
