---
title: "Levey-Jennings Raport: `r paste0('*', params$report_title, '*')`"
output: html_document
params:
  list_of_plates: !r NULL
  report_title: !r NULL
  dilutions: !r NULL
  additional_notes: !r NULL
  extra_args: !r NULL
---

```{r param-check, echo=FALSE}
list_of_plates <- params$list_of_plates
additional_notes <- params$additional_notes
extra_args <- params$extra_args


if (is.null(list_of_plates)) {
  stop("The `list_of_plates` must be provided when rendering the document.")
}
if (!is.list(list_of_plates)) {
  stop("The `list_of_plates` must be a list of `Plate` instances.")
}
if (length(list_of_plates) == 0) {
  stop("The `list_of_plates` must contain at least one `Plate` instance.")
}
if (length(list_of_plates) < 10) {
  warning("The `list_of_plates` should contain at least 10 `Plate` instances to generate a comprehensive report.")
}
if (!all(sapply(list_of_plates, inherits, "Plate"))) {
  stop("The list_of_plates contains objects that are not of class Plate.")
}
if (is.null(params$report_title)) {
  stop("The `report_title` must be provided when rendering the document.")
}
if (!is(params$report_title, "character")) {
  stop("The `report_title` must be a character value.")
}
if (is.null(params$dilutions)) {
  stop("The `dilutions` must be provided when rendering the document.")
}
if (!is.character(params$dilutions)) {
  stop("The `dilutions` must be a character value.")
}
if (!all(grepl("(^1\\s*)\\/(\\s*\\d+$)", params$dilutions))) {
  stop("The `dilutions` must be in the format '1/digit'.")
}
for (dilution in params$dilutions) {
  if (!all(sapply(list_of_plates, function(plate) dilution %in% plate$get_dilution("STANDARD CURVE")))) {
    plate_where_dilution_is_missing <- which(sapply(list_of_plates, function(plate) !(dilution %in% plate$get_dilution("STANDARD CURVE"))))
    stop("The dilution",
         dilution,
         "is not present in plates ",
         paste(plate_where_dilution_is_missing, collapse = ", "))
  }
}
all_analyte_names <- c()

intersection_analytes <- list_of_plates[[1]]$analyte_names

for (plate in list_of_plates) {
  all_analyte_names <- union(all_analyte_names, plate$analyte_names)
  intersection_analytes <- intersect(intersection_analytes, plate$analyte_names)
}

if (length(intersection_analytes) != length(all_analyte_names)) {
  warning("Not all plates contain the same analytes. The report will contain only the analytes that are present in all plates. Number of all analytes: ",
          length(all_analyte_names),
          ". Number of common analytes: ",
          length(intersection_analytes))
}

analyte_names <- intersection_analytes


if (!is.null(additional_notes) && !is(additional_notes, "character")) {
  stop("The `additional_notes` must be a character value.")
}

date_of_first_plate <- min(sapply(list_of_plates, function(plate) plate$plate_datetime))
date_of_last_plate <- max(sapply(list_of_plates, function(plate) plate$plate_datetime))

# i need to add this trick otherwise i get error in format function
# Error in prettyNum(.Internal(format(x, trim, digits, nsmall, width, 3L,  :
#  invalid 'trim' argument
# it may cause some problems with timezones
# but few hours difference is not a big deal
date_of_first_plate <- as.POSIXct(date_of_first_plate,
                                  origin = "1970-01-01",
                                  tz = "UTC")
date_of_last_plate <- as.POSIXct(date_of_last_plate,
                                 origin = "1970-01-01",
                                 tz = "UTC")
time_span <- difftime(date_of_last_plate, date_of_first_plate, units = "days")


# perform additional check for extra_args

# Validate extra_args: ensure it's a named list
if (!is.list(extra_args)) {
  stop("`extra_args` must be a list.")
}
if (length(extra_args) > 0 && (is.null(names(extra_args)) || any(names(extra_args) == ""))) {
  stop("All elements in `extra_args` must be named.")
}

# Hard-coded list of arguments passed explicitly in this Rmd script
reserved_names <- c(
  "list_of_plates", "analyte_name", "monochromatic"
)

# Check for forbidden overlaps
conflicting_args <- intersect(names(extra_args), reserved_names)
if (length(conflicting_args) > 0) {
  stop(
    "The following `extra_args` fields are not allowed, as they are explicitly passed in the report script: ",
    paste(conflicting_args, collapse = ", "),
    ". Please rename or remove them."
  )
}

```

Report generated on:  `r format(Sys.time(), SerolyzeR.env$report_datetime_format)`.  
First plate was run on: `r if(!is.null(date_of_first_plate)) format(date_of_first_plate, SerolyzeR.env$report_datetime_format) else "Date of running plate was not found in Luminex file"`.  
Last plate was run on: `r if(!is.null(date_of_last_plate)) format(date_of_last_plate, SerolyzeR.env$report_datetime_format) else "Date of running plate was not found in Luminex file"`.  
Time span: `r if(!is.null(time_span)) paste0(round(time_span, 2), " days") else "Dates were not found in Luminex file"`.  
Number of plates used in report: `r length(list_of_plates)`.  
Plates have `r paste0(length(analyte_names), " analytes")`.  
Standard curve sample dilutions: `r format_dilutions(list_of_plates[[1]]$dilutions, list_of_plates[[1]]$dilution_values, list_of_plates[[1]]$sample_types)`.

------------------

`r if(!is.null(additional_notes)) "### Additional notes \n" `  

`r if(!is.null(additional_notes)) additional_notes `  

`r if(!is.null(additional_notes)) "\n -------------------" ` 

### Plates used in this report

<details open>
  <summary>Click to show/hide list</summary>
```{r list-of-plates, echo=FALSE, results='asis'}
for (plate in list_of_plates) {
  cat(paste0("- ", plate$plate_name, "\n"))
}
```
</details>

### Plate layout

<details open>
  <summary>Click to show/hide layout</summary>
```{r plate-layout, fig.width=7, fig.height=4, fig.align='center', dev='jpeg', echo=FALSE, dpi=72}
plot_layout(list_of_plates[[1]])
```
</details>

------------------
 
### Details for given analyte {.tabset .tabset-fade}

```{r quality-control, results='asis', echo=FALSE, message=FALSE, out.width="50%", out.height="325", dev='svglite', dpi=72, warning=FALSE}
# Code used to create dynamic tabs based on the number of analytes
for (i in seq_along(analyte_names)) {
  cat(paste0("#### ", analyte_names[i], "\n"))

  # Plot stacked curves monochromatic
  print(inject(plot_standard_curve_stacked(list_of_plates = list_of_plates, analyte_name = analyte_names[i], monochromatic = TRUE, !!!extra_args)))

  # Plot stacked curves colored
  print(inject(plot_standard_curve_stacked(list_of_plates = list_of_plates,
                                    analyte_name = analyte_names[i],
                                    monochromatic = FALSE, 
                                    !!!extra_args)))

  for (dilution in params$dilutions) {
    # Plot levey-jennings
    print(inject(plot_levey_jennings(list_of_plates = list_of_plates, analyte_name = analyte_names[i], dilution = dilution, !!!extra_args)))
  }

  cat("\n\n")
}
```

------------------

### &nbsp;

<hr />
<p style="text-align: center;">Generated using the <a href="https://github.com/mini-pw/SerolyzeR">SerolyzeR </a> package </p>


