# ==========================================================
# Simple shiny web app to identify valid treatment sequences
# ==========================================================
# Note: Implementation of sequence explorer is not perfect - it works, but
# there are error messages that will appear for a microsecond and then vanish
# again (and remain in console), related to the circular logic used. I
# struggled to find another way of programming this, but if you can think of 
# one that would avoid this error, that would be ideal. Despite the error 
# though, the current implementation does work.
# ==========================================================

# Load required packages
library(shiny)
library(shinythemes)
library(shinyWidgets)
library(shinyjs)
library(data.table)
library(gtools)
library(DT)
library(markdown)
library(openxlsx)

# ======
# Inputs
# ======

# Define list of comparators (labels and values)
comparators_choice = c(
  "Nivolumab" = "nivolumab_monotherapy",
  "Cabozantinib plus nivolumab" = "cabozantinib_plus_nivolumab",
  "Nivolumab plus ipilimumab" = "nivolumab_plus_ipilimumab",
  "Lenvatinib plus pembrolizumab" = "lenvatinib_plus_pembrolizumab",
  "Avelumab plus axitinib" = "avelumab_plus_axitinib",
  "Pazopanib" = "pazopanib",
  "Tivozanib" = "tivozanib",
  "Sunitinib" = "sunitinib",
  "Cabozantinib" = "cabozantinib",
  "Lenvatinib plus everolimus" = "lenvatinib_plus_everolimus",
  "Everolimus" = "everolimus",
  "Axitinib" = "axitinib")
# Sorafenib and best supportive care are included by default
comparators_default = c("sorafenib", "placebo_BSC")
# Adapt to make list for use in sequence explorer
exp_comparators = append(comparators_choice, c(
  "Sorafenib" = "sorafenib",
  "Best supportive care" = "BSC"
))

# Define list of populations (labels and values)
populations = c(
  "Population 1" = 1,
  "Population 2" = 2,
  "Population 3" = 3,
  "Population 4" = 4)
# Adjust for use in sequence explorer
exp_populations <- sprintf("pop%s", populations)
names(exp_populations) <- names(populations)

# Import the sequencing functions
source("sequences.R")

# Import the fixed parameters (from .csv generated by convert_to_csv.R)
# and save as i, which is a list of lists
lists_df <- read.csv("data/lists.csv")
i <- lapply(lists_df, function(x) unlist(x)[!is.na(unlist(x))])
names(i) <- names(lists_df)

# Import table with all possible valid sequences (used by explorer)
exp_all_seq <- read.csv("data/valid_sequences.csv")

# =============================================
# User interface (layout and appearance of app)
# =============================================

ui <- fluidPage(
  # Website theme
  theme = shinytheme("flatly"),

  # Allows some JavaScript operations           
  useShinyjs(),
  
  # App title with logo
  titlePanel(
    title = span(img(src="exeter_pentag_small.png", height=60, style = "margin-right: 20px;"),
                 "Exeter Oncology Model: Renal Cell Carcinoma edition"),
    windowTitle = "EOM:RCC"),
  
  # Introductory paragraph
  includeMarkdown("txt/intro.md"),

  tabsetPanel(
    id = "tabset",
    # ====================
    # UI: Run analysis
    # ====================
    tabPanel(
      # Title for tab
      title = "Run analysis",
      # Header for panel
      h2("Find valid treatment sequences"),
      # Sidebar layout with input and output definitions
      sidebarLayout(
        
        # Sidebar panel for inputs
        sidebarPanel(
          
          h3("Inputs"),
          
          # Blank space before button
          headerPanel(""),
          
          # Button to reset inputs to default ("selected")
          actionButton(inputId = "reset",
                       label = "Reset inputs"),
          
          # Blank space after button
          headerPanel(""),
          
          # Number of populations (pop1-pop4)
          selectizeInput(inputId = "populations",
                         label = "Patient populations",
                         choices = populations,
                         selected = populations,
                         multiple = TRUE,
                         options = list(plugins = list("remove_button"))),
          
          # Number of treatment lines
          selectInput(inputId = "R_maxlines",
                      label = "Max lines within the R model",
                      choices = c(3, 4),
                      selected = 4),
          
          # Treatments
          selectizeInput(inputId = "chosen_comparators",
                         label = "Comparator list (includes sorafenib and best supportive care by default)",
                         choices = comparators_choice,
                         selected = comparators_choice,
                         multiple = TRUE,
                         options = list(plugins = list("remove_button"))),
          
          # Button to trigger creation of table of valid sequences
          actionButton(inputId = "seq_button",
                       label = "Find possible treatment sequences")
          
        ),
        
        # Main panel for displaying outputs
        mainPanel(
          h3("Results"),
          verbatimTextOutput("describe"),
          DT::DTOutput("sequences"),
          downloadButton(outputId = "download_table",
                         label = "Download table as an excel file")
        )
      )
    ),
    # =====================
    # UI: Sequence explorer
    # =====================
    tabPanel(
      # Title for tab
      title = "Sequence explorer",
      # Header for panel
      h2("Interactive sequence explorer"),
      # Sidebar layout with input and output definitions
      sidebarLayout(
        
        # Sidebar panel for inputs
        sidebarPanel(
          # Chosen population (pop1-pop4)
          selectInput(inputId = "exp_population",
                      label = "Patient population",
                      choices = exp_populations),
          
          # Number of treatment lines
          selectInput(inputId = "exp_R_maxlines",
                      label = "Max lines within the R model",
                      choices = c(3, 4),
                      selected = 4)
        ),
        mainPanel(
          # Lines of treatment
          uiOutput("exp_line1"),
          uiOutput("exp_line2"),
          uiOutput("exp_line3"),
          uiOutput("exp_line4"),
          uiOutput("exp_line5")
        )
      )
    )
  )
)

# ==========================================
# Server (instructions for building the app)
# ==========================================

server <- function(input, output) {

  # ====================
  # Server: Run analysis
  # ====================
  # Reactive expression to produce data table of valid sequences for each population
  valid_seq <- reactive({

    # Find all possible treatment combinations, including sorafeinb and
    # best supportive care alongside the list of chosen comparators
    all_seq <- as.data.frame(f_generate_sequences(
      comparators = append(input$chosen_comparators, comparators_default),
      maxlines = as.numeric(input$R_maxlines)))
  
    seqs <- NULL
    # Loop through each population
    for (population in input$populations) {
      s <- f_path_tx_restrict(
        sequences                = all_seq,
        allowed                  = f_get_allowed_lists(i, population), #overall list of allowed drugs in this popn
        L1                       = f_get_L1_lists(i, population), # 1L drugs allowed in this popn
        L2                       = f_get_L2_lists(i, population), # 2L drugs allowed in this popn
        L3                       = f_get_L3_lists(i, population), # 3L drugs allowed in this popn
        L4                       = f_get_L4_lists(i, population), # 4L drugs allowed in this popn
        only_after               = f_get_only_after_lists(i, population), #list of restrictions where tx can be only after the listed txs
        not_immediate_after      = f_get_not_immediate_after_lists(i, population), #list of restrictions where tx can be only immediately before the listed txs
        one_in_list              = f_get_one_in_list_lists(i, population), #list of restrictions where only one of the tx in each list is allowed 
        only_after_one           = f_get_only_after_one_lists(i, population), #list of restrictions where only one of the listed treatments is allowed prior to current therapy 
        L2_only_after            = f_get_2L_only_after_lists(i, population), #list of 2L+ restrictions: if drug is used 2L, 3L or 4L, can only be after drug x
        L2_only_immediate_after  = f_get_2L_only_immediate_after_lists(i, population), #list of 2L+ restrictions: if drug is used 2L, 3L or 4L, can only be immediately after drug x
        L2_only_one              = f_get_2L_only_one_lists(i, population) #list of 2L+ drugs where only one of them allowed in a given sequence
      )
      s <- cbind(rep(paste0("pop", population),nrow(s)), s)
      colnames(s) <- paste0('V', seq_len(ncol(s)))
      seqs <- rbind(seqs, s)
    }
    return(seqs)
  }) |>
    bindEvent(input$seq_button)

  # Render table
  output$describe <- renderText(paste0(
    "There are ", nrow(valid_seq()), " possible treatment sequences."))
  output$sequences <- DT::renderDT(
    {valid_seq()},
    rownames = FALSE,
    options = list(autoWidth = TRUE)) #, stringsAsFactors = TRUE),
    #filter = list(position = "top"))

  # If click button, reset inputs
  observeEvent(input$reset, {
    reset("populations")
    reset("R_maxlines")
    reset("chosen_comparators")
    hide("sequences")
    hide("describe")
    hide("download_table")
  })
  
  # If click button, show main panel outputs
  observeEvent(input$seq_button, {
    show("sequences")
    show("describe")
    show("download_table")
  })
  
  # If change inputs, hide main panel outputs
  observeEvent(input$populations, {
    hide("sequences")
    hide("describe")
    hide("download_table")
  })
  observeEvent(input$R_maxlines, {
    hide("sequences")
    hide("describe")
    hide("download_table")
  })
  observeEvent(input$chosen_comparators, {
    hide("sequences")
    hide("describe")
    hide("download_table")
  })

  # If click download button, download .xlsx file with table
  output$download_table <- downloadHandler(
    filename = "valid_sequences.xlsx",
    content = function(file) {
      # Write the dataset to the file that will be download
      write.xlsx(valid_seq(), file)
    }
  )
  
  # ========================
  # Server: Sequence explorer
  # =========================

  # Reactive expression to filter data table to chosen population and lines
  seq_start <- reactive({
    # Filter to chosen population
    seq <- exp_all_seq[exp_all_seq$V1 == input$exp_population,]
    # If max lines is 3, remove rows with BSC in V6 (as with four max lines,
    # any combination with 4 treatments will then have BSC as the final
    # treatment, but those with less will have an empty final column)
    if (input$exp_R_maxlines == 3) {
      seq <- seq[seq$V6 != "BSC",]
    }
    return(seq)
  })

  # Reactive filtering of dataframe based on chosen treatments
  seq_line1 <- reactive({
    seq <- seq_start()
    seq <- seq[seq$V2 == input$exp_l1_chosen,]
    return(seq)
  })
  seq_line2 <- reactive({
    seq <- seq_line1()
    seq <- seq[seq$V3 == input$exp_l2_chosen,]
    return(seq)
  })
  seq_line3 <- reactive({
    seq <- seq_line2()
    seq <- seq[seq$V4 == input$exp_l3_chosen,]
    return(seq)
  })
  seq_line4 <- reactive({
    seq <- seq_line3()
    seq <- seq[seq$V5 == input$exp_l4_chosen,]
    return(seq)
  })

  # Reactive display of possible treatments for each line
  output$exp_line1 <- renderUI({
    l1_values <- unique(seq_start()$V2)
    radioGroupButtons(inputId = "exp_l1_chosen",
                      label = "First line treatment",
                      choices = exp_comparators[exp_comparators %in% l1_values],
                      individual = TRUE,
                      checkIcon = list(
                        yes = icon("ok", lib = "glyphicon")))
  })
  output$exp_line2 <- renderUI({
    l2_values <- unique(seq_line1()$V3)
    radioGroupButtons(inputId = "exp_l2_chosen",
                      label = "Second line treatment",
                      choices = exp_comparators[exp_comparators %in% l2_values],
                      individual = TRUE,
                      checkIcon = list(
                        yes = icon("ok", lib = "glyphicon")))
  })
  output$exp_line3 <- renderUI({
    if (nrow(seq_line2()) > 1) {
      l3_values <- unique(seq_line2()$V4)
      radioGroupButtons(inputId = "exp_l3_chosen",
                        label = "Third line treatment",
                        choices = exp_comparators[exp_comparators %in% l3_values],
                        individual = TRUE,
                        checkIcon = list(
                          yes = icon("ok", lib = "glyphicon")))
    }
  })

  output$exp_line4 <- renderUI({
    if (nrow(seq_line3()) == 1) {
      if (seq_line3()$V5 != "") {
        l4_values <- unique(seq_line3()$V5)
        radioGroupButtons(inputId = "exp_l4_chosen",
                          label = "Fourth line treatment",
                          choices = exp_comparators[exp_comparators %in% l4_values],
                          individual = TRUE,
                          checkIcon = list(
                            yes = icon("ok", lib = "glyphicon")))
      }
    } else if (nrow(seq_line3()) >= 1) {
      l4_values <- unique(seq_line3()$V5)
      radioGroupButtons(inputId = "exp_l4_chosen",
                        label = "Fourth line treatment",
                        choices = exp_comparators[exp_comparators %in% l4_values],
                        individual = TRUE,
                        checkIcon = list(
                          yes = icon("ok", lib = "glyphicon")))
    }  
  })

  output$exp_line5 <- renderUI({
    if (nrow(seq_line4()) >= 1) {
      if (seq_line4()$V6 != "") {
        l5_values <- unique(seq_line4()$V6)
        radioGroupButtons(inputId = "exp_l5_chosen",
                          label = "Fifth line treatment",
                          choices = exp_comparators[exp_comparators %in% l5_values],
                          individual = TRUE,
                          checkIcon = list(
                            yes = icon("ok", lib = "glyphicon")))
      }
    }
  })
}

# ====================
# Create the shiny app
# ====================

shinyApp(ui, server)