context("Accessing and subsetting tables")

test_that("cell_values function works as desired", {
  l <- basic_table() %>%
    split_cols_by("ARM") %>%
    split_cols_by("SEX") %>%
    split_rows_by("RACE") %>%
    summarize_row_groups() %>%
    split_rows_by("STRATA1") %>%
    analyze("AGE", afun = function(x, .N_col, .N_row) rcell(c(.N_row, .N_col), format = "(xx.x, xx.x)"))

  ourdat <- DM
  ourdat$SEX <- droplevels(ourdat$SEX)
  ourdat$RACE <- droplevels(ourdat$RACE)
  tbl <- build_table(l, ourdat)

  armsextab <- table(ourdat$SEX, ourdat$ARM)

  armaval <- "A: Drug X"
  cvres1 <- cell_values(tbl, c("RACE", "ASIAN"), c("ARM", "A: Drug X", "SEX", "M"))
  contcount <- nrow(subset(ourdat, RACE == "ASIAN" & ARM == armaval & SEX == "M"))
  asianstrata <- table(subset(ourdat, RACE == "ASIAN")$STRATA1)
  expect_equal(
    unname(cvres1),
    list(
      list("A: Drug X.M" = c(
        contcount,
        contcount / armsextab["M", armaval]
      )),
      list("A: Drug X.M" = c(
        unname(asianstrata["A"]),
        armsextab["M", armaval]
      )),
      list("A: Drug X.M" = c(
        unname(asianstrata["B"]),
        armsextab["M", armaval]
      )),
      list("A: Drug X.M" = c(
        unname(asianstrata["C"]),
        armsextab["M", armaval]
      ))
    )
  )



  cvres2 <- cell_values(
    tbl, c("RACE", "ASIAN", "STRATA1"),
    c("ARM", "A: Drug X", "SEX", "M")
  )
  expect_identical(unname(cvres1[2:4]), unname(cvres2))
  cvres3 <- cell_values(
    tbl, c("RACE", "ASIAN", "STRATA1", "B"),
    c("ARM", "A: Drug X", "SEX", "M")
  )
  expect_identical(cvres3, cvres1[[3]])
  ## any arm, male columns from the ASIAN content (i.e. summary) row
  cvres4 <- cell_values(tbl, c("RACE", "ASIAN", "@content"))
  expect_identical(cvres4[2], cvres1[[1]])

  cvres5 <- cell_values(
    tbl, c("RACE", "ASIAN", "@content"),
    c("ARM", "*", "SEX", "M")
  )
  expect_identical(cvres5, cvres4[seq(2, 6, by = 2)])
  ## all columns
  cvres6 <- cell_values(tbl, c("RACE", "ASIAN", "STRATA1", "B"))

  ## all columns for the Combination arm
  cvres7 <- cell_values(
    tbl, c("RACE", "ASIAN", "STRATA1", "B"),
    c("ARM", "C: Combination")
  )

  expect_identical(
    cvres6[5:6],
    cvres7
  )

  cvres8 <- cell_values(
    tbl, c("RACE", "ASIAN", "STRATA1", "B", "AGE"),
    c("ARM", "C: Combination", "SEX", "M")
  )
  vares8 <- value_at(
    tbl, c("RACE", "ASIAN", "STRATA1", "B", "AGE"),
    c("ARM", "C: Combination", "SEX", "M")
  )
  expect_identical(cvres8[[1]], vares8)
  expect_error(value_at(
    tbl, c("RACE", "ASIAN", "STRATA1", "B"),
    c("ARM", "C: Combination", "SEX", "M")
  ))
  expect_error(value_at(
    tbl, c("RACE", "ASIAN", "STRATA1", "B", "AGE"),
    c("ARM", "C: Combination", "SEX")
  ))
  expect_error(value_at(
    tbl, c("RACE", "ASIAN", "STRATA1", "B", "AGE"),
    c("ARM", "C: Combination")
  ))

  allrows <- collect_leaves(tbl, TRUE, TRUE)
  crow <- allrows[[1]]
  lrow <- allrows[[2]]
  expect_error(
    cell_values(crow, rowpath = "@content"),
    "cell_values on TableRow objects must have NULL rowpath"
  )
  expect_error(
    cell_values(lrow),
    "cell_values on LabelRow is not meaningful"
  )
})


test_colpaths <- function(tt) {
  cdf <- make_col_df(tt, visible_only = TRUE)
  cdf2 <- make_col_df(tt, visible_only = FALSE)
  res3 <- lapply(cdf$path, function(pth) rtables:::subset_cols(tt, pth))
  res4 <- lapply(cdf2$path, function(pth) rtables:::subset_cols(tt, pth))
  expect_identical(res3, res4[!is.na(cdf2$abs_pos)])
  expect_identical(res3, lapply(
    seq_len(ncol(tt)),
    function(j) tt[, j]
  ))
  TRUE
}


test_rowpaths <- function(tt, visonly = TRUE) {
  cdf <- make_row_df(tt, visible_only = visonly)
  res3 <- lapply(cdf$path, function(pth) cell_values(tt, pth)) # nolint
  TRUE
}



test_that("make_row_df, make_col_df give paths which all work", {
  lyt <- basic_table() %>%
    split_cols_by("ARM") %>%
    split_cols_by("SEX", ref_group = "F") %>%
    analyze("AGE", mean, show_labels = "hidden") %>%
    analyze("AGE", refcompmean,
      show_labels = "hidden",
      table_names = "AGE2a"
    ) %>%
    split_rows_by("RACE", nested = FALSE, split_fun = drop_split_levels) %>%
    analyze("AGE", mean, show_labels = "hidden") %>%
    analyze("AGE", refcompmean, show_labels = "hidden", table_names = "AGE2b")


  tab <- build_table(lyt, rawdat)
  rdf1a <- make_row_df(tab)
  rdf1b <- make_row_df(tab, visible_only = FALSE)
  expect_true(
    all.equal(rdf1a, rdf1b[!is.na(rdf1b$abs_rownumber), ],
      check.attributes = FALSE
    ), ## rownames ugh
    "visible portions of row df not identical between
visible_only and not"
  )

  allcvs <- cell_values(tab)
  allcvs_un <- unname(allcvs)
  pathres <- lapply(rdf1b$path, function(pth) unname(cell_values(tab, pth)))
  expect_identical(
    pathres,
    list(
      allcvs_un,
      allcvs_un[1:2], ## XXX this probably shouldn't be here
      unname(allcvs_un[[1]]),
      unname(allcvs_un[[1]]),
      unname(allcvs_un[[2]]),
      unname(allcvs_un[[2]]),
      allcvs_un[3:6], ## RACE
      allcvs_un[3:4], ## WHITE Tabletree
      allcvs_un[3:4], ## WHITE LabelRow
      unname(allcvs_un[[3]]), ## white age ElemtaryTable
      unname(allcvs_un[[3]]), ## white age DataRow
      unname(allcvs_un[[4]]), ## white compare ElemtaryTable
      unname(allcvs_un[[4]]), ## white compare DataRow
      allcvs_un[5:6], ## BLACK TableTree
      allcvs_un[5:6], ## BLACK LabelRow
      unname(allcvs_un[[5]]), ## black ageElemtaryTable
      unname(allcvs_un[[5]]), ## black age DataRow
      unname(allcvs_un[[6]]), ## black compare ElemtaryTable
      unname(allcvs_un[[6]])
    )
  ) ## black compare DataRow

  test_colpaths(tab)




  combodf <- tribble(
    ~valname, ~label, ~levelcombo, ~exargs,
    "A_", "Arm 1", c("A: Drug X"), list(),
    "B_C", "Arms B & C", c("B: Placebo", "C: Combination"), list()
  )

  l2 <- basic_table(show_colcounts = TRUE) %>%
    split_cols_by(
      "ARM",
      split_fun = add_combo_levels(combodf, keep_levels = c("A_", "B_C"))
    ) %>%
    analyze(c("AGE", "AGE"),
      afun = list(mean, range),
      show_labels = "hidden", table_names = c("AGE mean", "AGE range")
    )

  tab2 <- build_table(l2, DM)
  test_colpaths(tab2)
  cdf2 <- make_col_df(tab2)
  ## res5 <- lapply(cdf2$path, function(pth) subset)cols
})


test_that("Duplicate colvars path correctly", {
  l <- basic_table() %>%
    split_cols_by_multivar(c("AGE", "BMRKR1", "AGE"), varlabels = c("Age", "Biomarker 1", "Second Age")) %>%
    analyze_colvars(mean)

  tbl <- build_table(l, DM)

  matform <- matrix_form(tbl)
  expect_identical(
    matrix(
      c(
        "", "Age", "Biomarker 1", "Second Age",
        "mean", mean(DM$AGE), mean(DM$BMRKR1), mean(DM$AGE)
      ),
      nrow = 2, byrow = TRUE
    ),
    matform$strings
  )

  res <- cell_values(tbl, colpath = c("multivars", "AGE._[[2]]_."))
  expect_identical(
    list("AGE._[[2]]_." = mean(DM$AGE, na.rm = TRUE)),
    res
  )
})

test_that("top_left, title, footers retention behaviors are correct across all scenarios", {
  # topleft
  tlval <- "hi"

  # title
  ti <- "ti"
  sti <- "sti"

  # footers
  mf <- "mf"
  pf <- "pf"
  rf <- "rf"

  lyt <- basic_table(
    title = ti, subtitles = sti,
    main_footer = mf, prov_footer = pf
  ) %>%
    split_cols_by("ARM") %>%
    append_topleft(tlval) %>%
    split_rows_by("SEX") %>%
    analyze("AGE", mean)
  tbl <- build_table(lyt, DM)
  fnotes_at_path(tbl, rowpath = c("SEX", "F", "AGE", "mean")) <- rf
  fnotes_at_path(tbl, rowpath = c("SEX", "M", "AGE", "mean")) <- rf

  # topleft
  expect_identical(top_left(tbl), tlval)
  expect_identical(top_left(tbl[, 1]), tlval) ## default column-only subsetting is TRUE
  expect_identical(top_left(tbl[, 1, keep_topleft = FALSE]), character())
  expect_identical(top_left(tbl[, 1, keep_topleft = TRUE]), tlval)
  expect_identical(top_left(tbl[1, ]), character()) ## default with any row subsetting is FALSE
  expect_identical(top_left(tbl[1, , keep_topleft = FALSE]), character())
  expect_identical(top_left(tbl[1, , keep_topleft = TRUE]), tlval)
  expect_identical(top_left(tbl[1:2, 1:2]), character())
  expect_identical(top_left(tbl[1:2, 1:2, keep_topleft = FALSE]), character())
  expect_identical(top_left(tbl[1:2, 1:2, keep_topleft = TRUE]), tlval)

  # drop = TRUE works
  expect_identical(suppressWarnings(tbl[1, 1, drop = TRUE]), NULL)
  expect_warning(tbl[1, 1, drop = TRUE])
  expect_equal(tbl[2, 1, drop = TRUE], 33.71, tolerance = 0.01)

  # referential footnotes
  expect_identical(
    mf_rfnotes(matrix_form(tbl[2, 1])),
    paste0("{1} - ", rf)
  )
  expect_identical(
    mf_rfnotes(matrix_form(tbl[4, 1])),
    paste0("{1} - ", rf)
  )
  expect_identical(
    mf_rfnotes(matrix_form(tbl[4, 1, reindex_refs = FALSE])),
    paste0("{1} - ", rf)
  )
  expect_identical(mf_rfnotes(matrix_form(tbl[1, 1])), character())

  # titles and footers
  expect_identical(main_title(tbl[1, 1]), "")
  expect_identical(main_title(tbl[1, 1, keep_titles = FALSE]), "")
  expect_identical(main_footer(tbl[1, 1, keep_titles = FALSE]), character())
  expect_identical(main_title(tbl[1, 1, keep_titles = TRUE]), ti)
  expect_identical(subtitles(tbl[1, 1, keep_titles = TRUE]), sti)
  expect_identical(main_footer(tbl[1, 1, keep_footers = TRUE]), mf)
  expect_identical(prov_footer(tbl[1, 1, keep_footers = TRUE]), pf)

  # Further testing drop = TRUE
  tbl1 <- basic_table() %>%
    split_cols_by("ARM") %>%
    split_rows_by("SEX") %>%
    analyze("AGE", function(x) list("m (sd)" = c(mean(x), sd(x)))) %>%
    build_table(DM)
  tbl2 <- basic_table() %>%
    split_cols_by("ARM") %>%
    split_rows_by("SEX", child_labels = "hidden") %>%
    analyze("AGE", mean) %>%
    build_table(DM)
  # row with only numbers -> warning
  expect_warning(tbl[4, , drop = TRUE])
  # warnings for label row
  expect_warning(tbl[, 1, drop = TRUE])
  expect_warning(tbl[3, , drop = TRUE])
  # warnings for more than one values
  expect_warning(tbl1[4, , drop = TRUE])
  expect_warning(tbl1[2, 1:2, drop = TRUE])
})

test_that("setters work ok", {
  tlval <- "hi"
  lyt <- basic_table() %>%
    split_cols_by("ARM") %>%
    split_rows_by("SEX") %>%
    summarize_row_groups() %>%
    analyze("AGE", mean)
  tbl <- build_table(lyt, DM)

  tbl2 <- tbl

  tbl2[1, 1] <- CellValue(c(1, .1))
  matform2 <- matrix_form(tbl2)
  expect_identical("1 (10.0%)", matform2$strings[2, 2])

  tbl3 <- tbl
  tbl3[3, 1:2] <- list(CellValue(c(1, 1)), CellValue(c(1, 1)))
  matform3 <- matrix_form(tbl3)
  expect_identical(rep("1 (100.0%)", 2), matform3$strings[4, 2:3])

  tbl2 <- tbl
  tt_at_path(tbl2, c("SEX", "UNDIFFERENTIATED")) <- NULL
  expect_equal(nrow(tbl2), 6)

  tbl3 <- tbl
  tt_at_path(tbl3, c("SEX", "UNDIFFERENTIATED", "AGE", "mean")) <- NULL
  expect_equal(nrow(tbl3), 7)

  lyt4 <- basic_table() %>%
    split_cols_by("ARM") %>%
    split_rows_by("SEX") %>%
    analyze("AGE", mean)
  tbl4 <- build_table(lyt4, DM)

  tbl4[5:6, ] <- list(rrow("new label"), rrow("new mean", 5, 7, 8))
  mform4 <- matrix_form(tbl4)
  expect_identical(
    mform4$strings[6, , drop = TRUE],
    c("new label", "", "", "")
  )
  expect_identical(
    cell_values(tbl4)[["U.AGE.mean"]],
    list(5, 7, 8)
  )
})


test_that("cell_values and value_at work on row objects", {
  tbl <- basic_table() %>%
    split_cols_by("ARM") %>%
    split_cols_by("STRATA2") %>%
    analyze("AEDECOD") %>%
    build_table(ex_adae, ex_adsl)

  first_row <- collect_leaves(tbl)[[1]]

  va <- value_at(first_row, colpath = c("ARM", "A: Drug X", "STRATA2", "S2"))

  cv <- cell_values(first_row, colpath = c("ARM", "C: Combination"))

  expect_identical(va, 33L)

  expect_identical(
    cv,
    setNames(
      list(32L, 56L),
      c(
        "C: Combination.S1",
        "C: Combination.S2"
      )
    )
  )
})

test_that("label_at_path works", {
  lyt <- make_big_lyt()

  tab <- build_table(lyt, rawdat)
  orig_labs <- row.names(tab)

  tab4 <- tab

  label_at_path(tab4, c("root", "RACE", "WHITE", "FACTOR2", "B", "AGE")) <- NA_character_

  expect_identical(row.names(tab4), orig_labs[-9])

  tab5 <- tab

  newlab5 <- "race var label"
  label_at_path(tab5, c("root", "RACE")) <- newlab5
  expect_identical(row.names(tab5), c(newlab5, orig_labs))

  rps <- row_paths(tab)

  labs <- vapply(rps, function(pth) label_at_path(tab, pth), "",
    USE.NAMES = FALSE
  )
  expect_identical(labs, orig_labs)

  newthangalangs <- paste(orig_labs, "redux")

  tab7 <- tab
  for (i in seq_along(orig_labs)) label_at_path(tab7, rps[[i]]) <- newthangalangs[i]

  expect_identical(
    newthangalangs,
    row.names(tab7)
  )
})

test_that("insert_row_at_path works", {
  lyt <- basic_table() %>%
    split_rows_by("COUNTRY", split_fun = keep_split_levels(c("CHN", "USA"))) %>%
    summarize_row_groups() %>%
    analyze("AGE")

  tab <- build_table(lyt, DM)
  orig_rns <- row.names(tab)
  tab2 <- insert_row_at_path(
    tab, c("COUNTRY", "CHN", "AGE", "Mean"),
    rrow("new row", 555)
  )
  expect_identical(
    row.names(tab2),
    c(
      orig_rns[1],
      "new row",
      orig_rns[-1]
    )
  )

  tab3 <- insert_row_at_path(tab2, c("COUNTRY", "CHN", "AGE", "Mean"),
    rrow("new row redux", 888),
    after = TRUE
  )
  expect_identical(
    row.names(tab3),
    c(
      orig_rns[1],
      "new row",
      orig_rns[2],
      "new row redux",
      orig_rns[-c(1:2)]
    )
  )

  myrow <- rrow("whaaat", 578)
  rps <- row_paths(tab)
  msg <- "path must resolve fully to a non-content data row."
  expect_error(insert_row_at_path(tab, c("root", "COUNTRY"), myrow), msg)
  expect_error(insert_row_at_path(tab, c("root", "COUNTRY", "CHN"), myrow), msg)
  expect_error(insert_row_at_path(tab, c("root", "COUNTRY", "CHN", "AGE"), myrow), msg)
  expect_error(insert_row_at_path(tab, rps[[1]], myrow), msg)

  lyt4 <- basic_table() %>%
    split_rows_by("COUNTRY", split_fun = keep_split_levels(c("CHN", "USA"))) %>%
    analyze("AGE")

  tab4 <- build_table(lyt4, DM)

  expect_identical(
    label_at_path(tab4, c("COUNTRY", "CHN")),
    "CHN"
  )

  label_at_path(tab4, c("COUNTRY", "CHN")) <- "China"

  expect_identical(
    row.names(tab4),
    c("China", "Mean", "USA", "Mean")
  )

  label_at_path(tab4, c("COUNTRY", "CHN", "AGE", "Mean")) <- "Age Mean"
  expect_identical(
    row.names(tab4),
    c("China", "Age Mean", "USA", "Mean")
  )
})


test_that("bracket methods all work", {
  tbl <- tt_to_export()

  nrtot <- nrow(tbl)

  tbl_a_white <- tbl[1:19, ]
  expect_identical(
    tbl[rep(c(TRUE, FALSE), c(19, nrtot - 19)), ],
    tbl_a_white
  )
  expect_identical(
    tt_at_path(tbl_a_white, c("STRATA1", "A", "RACE", "WHITE")),
    tt_at_path(tbl, c("STRATA1", "A", "RACE", "WHITE"))
  )


  tbl_sub1 <- tbl[1:25, c(1, 4, 6)]

  expect_identical(
    tbl_sub1,
    tbl[
      rep(c(TRUE, FALSE), c(25, nrtot - 25)),
      c(TRUE, FALSE, FALSE, TRUE, FALSE, TRUE)
    ]
  )

  expect_identical(
    tbl[, c(1, 4, 6)],
    tbl[, c(TRUE, FALSE, FALSE, TRUE, FALSE, TRUE)]
  )
})

test_that("tt_at_path and cell_values work with values even if they differ in naming", {
  # see issue #794
  tbl <- basic_table() %>%
    split_cols_by(var = "ARM", split_label = "asdar") %>%
    # split_rows_by(var = "SEX") %>%
    add_colcounts() %>%
    analyze("AGE",
      afun = function(x) {
        out_list <- list(a = mean(x), b = 3)
        labs <- c("argh", "argh2")
        attr(out_list[[1]], "label") <- "aa"
        attr(out_list[[2]], "label") <- "aa2"
        in_rows(.list = out_list, .labels = labs, .names = labs)
      },
      show_labels = "visible", table_names = "nope"
    ) %>%
    build_table(df = DM)

  rdf <- make_row_df(tbl)
  names(rdf$path[[2]]) <- c("a", "b")
  expect_silent(tt_at_path(tbl, rdf$path[[2]]))
})
