library(shiny)
library(hrtlFMC)
library(shinybusy)

ui <- fluidPage(
  tags$head(
    tags$style(HTML("
      pre, code, .shiny-text-output, .verbatim-text-output {
        font-family:  'sans-serif','Arial'  !important;
        font-size: 16px;
        color: black;
      }
    "))
  ),
  tags$div(
    "Minimally Changed Two-Level Half-Fractional Factorial Designs",
    style = "font-weight: bold; color: red; font-size: 28px; text-align: center; margin-bottom: 15px;"
  ),

  sidebarLayout(

    # Sidebar Panel
    sidebarPanel(
      style = "background-color: #F5DEB3; padding: 15px; border-radius: 10px;",


      h3("Enter Number of Factors",
         style = "font-weight: bold; font-size: 20px; color: blue;text-align: center;"),
      helpText(tags$div("[Number of factors must be greater than 2]",
                        style = "font-weight: bold;font-size: 14px; color: purple;")),
      numericInput("num_factors", label=NULL,value = 3, min = 3, step = 1)
      ,

      h3("Trend Factor Range",
         style = "font-weight: bold; font-size: 20px; color: blue;text-align: center;"),

      helpText(tags$div("[Enter a range between 0 and 1.  The upper bound must be greater than the lower bound (e.g: 0.56 to 0.65)]",
                        style = "font-weight: bold;font-size: 14px; color: purple;")),

      numericInput("lower_bound", "Lower Bound", value = 0.56, min = 0, max = 1, step = 0.01),
      numericInput("upper_bound", "Upper Bound", value = 0.65, min = 0, max = 1, step = 0.01),

      actionButton("run_button", "Generate",
                   style = "background-color: blue; color: white; font-size: 18px; width: 100%;")
    ),

    mainPanel(
      uiOutput("main_ui")  # <- Dynamically rendered after "Generate"
    )
  )
)




# Server
server <- function(input, output) {
  result_all <- reactiveVal(NULL)
  observeEvent(input$run_button, {
   show_modal_spinner(
      spin = "circle",
      color = "#007BFF",
      text = "Generating, please wait..."   # (Optional text under spinner)
    )
    # Simulated delay
    Sys.sleep(1)
    result <- min2HalfFFD:::minHalfFact(input$num_factors, input$lower_bound, input$upper_bound)
    result_all(result)

    # Render the full main panel only after processing
    output$main_ui <- renderUI({

      div(style = "background: #FFFFE0; padding: 15px; border-radius: 10px;",

          h3("Results", style = "font-size: 24px; font-weight: bold; text-align: center; color: green"),

          selectInput("result_selector", "Select Result to Display:",
                      choices = c(
                        "Total Change" = "totalchange",
                        "Total Number of Minimally Changed Designs" = "total",
                        "All Minimally Changed Designs" = "minimal",
                        "All Minimally Changed Designs with D, Dt, Trend Factor" = "all_d_dt",
                        "Maximum D Value" = "max_d",
                        "D-Optimal Designs" = "d_opt",
                        "Maximum Dt Value" = "max_dt",
                        "Dt-Optimal Designs" = "dt_opt",
                        "Maximum Trend Factor" = "max_trend",
                        "Number of Minimally Changed Designs with Maximum Trend Factor Value"="designs_max_trend",
                        "Minimally Changed Designs in Trend Factor Range" = "trend_range"
                      ),
                      selected = "totalchange",
                      width = "100%"),
          conditionalPanel("input.result_selector == 'totalchange'",
                           div(style = "background: #FFC0CB; padding: 15px; border-radius: 10px;font-weight: bold;",
                               verbatimTextOutput("total_change_value"))),
          conditionalPanel("input.result_selector == 'total'",
                           div(style = "background: #FFC0CB; padding: 15px; border-radius: 10px;font-weight: bold;",
                               verbatimTextOutput("total_designs"))),

          conditionalPanel("input.result_selector == 'minimal'",
                           div(style = "background: #FFC0CB; padding: 15px; border-radius: 10px;
                                        max-height: 400px; overflow-y: auto; white-space: pre; font-size: 18px; font-weight: bold;",
                               verbatimTextOutput("minimal_designs"))),

          conditionalPanel("input.result_selector == 'all_d_dt'",
                           div(style = "background: #FFC0CB; padding: 15px; border-radius: 10px;
                                        max-height: 400px; overflow-y: auto; white-space: pre; font-size: 18px; font-weight: bold;",
                               verbatimTextOutput("all_designs_d_dt_trend"))),

          conditionalPanel("input.result_selector == 'max_d'",
                           div(style = "background: #FFC0CB; padding: 15px; border-radius: 10px;font-weight: bold;",
                               verbatimTextOutput("max_d_value"))),

          conditionalPanel("input.result_selector == 'd_opt'",
                           div(style = "background: #FFC0CB; padding: 15px; border-radius: 10px;
                                        max-height: 400px; overflow-y: auto; white-space: pre; font-size: 18px; font-weight: bold;",
                               verbatimTextOutput("d_optimal_designs"))),

          conditionalPanel("input.result_selector == 'max_dt'",
                           div(style = "background: #FFC0CB; padding: 15px; border-radius: 10px;font-weight: bold;",
                               verbatimTextOutput("max_dt_value"))),

          conditionalPanel("input.result_selector == 'dt_opt'",
                           div(style = "background: #FFC0CB; padding: 15px; border-radius: 10px;
                                        max-height: 400px; overflow-y: auto; white-space: pre; font-size: 18px; font-weight: bold;",
                               verbatimTextOutput("dt_optimal_designs"))),

          conditionalPanel("input.result_selector == 'max_trend'",
                           div(style = "background: #FFC0CB; padding: 15px; border-radius: 10px;font-weight: bold;",
                               verbatimTextOutput("max_trend_factor_value"))),

          conditionalPanel("input.result_selector == 'designs_max_trend'",
                           div(style = "background: #FFC0CB; padding: 15px; border-radius: 10px;font-weight: bold;",
                               verbatimTextOutput("designs_with_max_trend_factor"))),

          conditionalPanel("input.result_selector == 'trend_range'",
                           div(style = "background: #FFC0CB; padding: 15px; border-radius: 10px;
                                        max-height: 400px; overflow-y: auto; white-space: pre; font-size: 18px; font-weight: bold;",
                               verbatimTextOutput("designs_in_trend_range")))
      )
    })


    remove_modal_spinner()  # <- Hide spinner after result is set
  })

  # Display Total number of factor level changes
  output$total_change_value <- renderPrint({
    req(result_all())
    total_chg <- result_all()$Total_change
    # print nicely
    cat("Total Change:", total_chg, "\n")
  })


  output$total_designs <- renderPrint({
    req(result_all())
    total <- result_all()$Total_Minimally_Changed_Factorial_Run_Orders
    cat("Total Number of Minimally Changed Designs:", total, "\n")
  })


  # Display Minimally Changed Run Orders
  output$minimal_designs <- renderPrint({
    req(result_all())
    cat("All Minimally Changed  Designs:\n\n")
    # Extracting the designs list
    designs1 <- result_all()$Minimally_Changed_Factorial_Run_Orders

    # Print each design in a structured format
    for (i in seq_along(designs1)) {
      cat("Design", i, ":\n")

      # Print matrix row-wise with proper spacing
      apply(designs1[[i]], 1, function(row) cat(paste(sprintf("%3d", row), collapse = "  "), "\n"))

      cat("\n------------------------------\n\n") # Separator line
    }
  })


  # Display All Designs with D, Dt, and Trend Factor
  output$all_designs_d_dt_trend <- renderPrint({
    req(result_all())
    cat("All Minimally Changed Designs with D, Dt, Trend Factor:\n\n")
    # Extracting the designs list
    designs <- result_all()$All_Minimally_Changed_Factorial_Run_Orders_with_D_Dt_Trend_Factor

    # Print each design in a clear format
    for (i in seq_along(designs)) {
      cat("Design", i, ":\n")

      # Print the design matrix row-wise
      apply(designs[[i]][[1]], 1, function(row) cat(paste(sprintf("%3d", row), collapse = "  "), "\n"))

      # Print D, Dt, and Trend Factor values
      cat("D value:", designs[[i]]$D_value, "\n")
      cat("Dt value:", designs[[i]]$Dt_value, "\n")
      cat("Trend factor:", designs[[i]]$Trend_factor, "\n")
      cat("\n------------------------------\n\n") # Separator line
    }
  })




  # Display Maximum D Value
  output$max_d_value <- renderPrint({
    req(result_all())
    max_d <- result_all()$Max_D_value
    cat("Maximum D Value:", max_d, "\n")  # Ensure consistent formatting
  })

  # Display D-Optimal Designs
  output$d_optimal_designs <- renderPrint({
    req(result_all())
    d_optimal <- result_all()$D_optimal_designs

    # Case 1: Check if it's the predefined "No D optimal designs found." message
    if (is.character(d_optimal) && length(d_optimal) == 1 && d_optimal == "No D optimal designs found.") {
      cat(d_optimal, "\n")  # Print the message
    }
    # Case 2: Check if d_optimal contains actual designs
    else {
      cat("D-Optimal Minimally Changed Designs:\n\n")

      # Print each design in a structured format
      for (i in seq_along(d_optimal)) {
        cat("Design", i, ":\n")

        # Print the design matrix row-wise
        apply(d_optimal[[i]][[1]], 1, function(row) cat(paste(sprintf("%3d", row), collapse = "  "), "\n"))

        # Print D, Dt, and Trend Factor values
        cat("D value:", d_optimal[[i]]$D_value, "\n")
        cat("Dt value:", d_optimal[[i]]$Dt_value, "\n")
        cat("Trend factor:", d_optimal[[i]]$Trend_factor, "\n")
        cat("\n------------------------------\n\n")  # Separator line
      }
    }
  })



  # Display Maximum Dt Value
  output$max_dt_value <- renderPrint({
    req(result_all())
    max_dt <- result_all()$Max_Dt_value
    cat("Maximum Dt Value:", max_dt, "\n")  # Ensure consistent formatting
  })

  # Display Dt-Optimal Designs
  output$dt_optimal_designs <- renderPrint({
    req(result_all())
    dt_optimal <- result_all()$Dt_optimal_designs

    # Case 1: Check if it's the predefined "No Dt optimal designs found." message
    if (is.character(dt_optimal) && length(dt_optimal) == 1 && dt_optimal == "No Dt optimal designs found.") {
      cat(dt_optimal, "\n")  # Print the message
    }
    # Case 2: Check if dt_optimal contains actual designs
    else {
      cat("Dt-Optimal Minimally Changed Designs:\n\n")

      # Print each design in a structured format
      for (i in seq_along(dt_optimal)) {
        cat("Design", i, ":\n")

        # Print the design matrix row-wise
        apply(dt_optimal[[i]][[1]], 1, function(row) cat(paste(sprintf("%3d", row), collapse = "  "), "\n"))

        # Print D, Dt, and Trend Factor values
        cat("D value:", dt_optimal[[i]]$D_value, "\n")
        cat("Dt value:", dt_optimal[[i]]$Dt_value, "\n")
        cat("Trend factor:", dt_optimal[[i]]$Trend_factor, "\n")
        cat("\n------------------------------\n\n")  # Separator line
      }
    }
  })


  # Display Maximum Trend Factor Value
  output$max_trend_factor_value <- renderPrint({
    req(result_all())
    trend_factor <- result_all()$Max_Trend_factor_value
    cat("Maximum Trend Factor Value:", trend_factor, "\n")  # Ensure consistent formatting

  })

  # Display Designs with Maximum Trend Factor Value
  output$designs_with_max_trend_factor <- renderPrint({
    req(result_all())
    designs_trend_factor <- result_all()$Number_of_Designs_Max_Trend_Factor
    cat("Number of Minimally Changed Designs with Maximum Trend Factor Value:", designs_trend_factor, "\n")  # Ensure consistent formatting

  })

  # Display Designs in Trend Factor Range
  output$designs_in_trend_range <- renderPrint({
    req(result_all())
    trend_designs <- result_all()$Minimally_Changed_Factorial_Run_Orders_in_trend_factor_range

    # Case 1: Check if it's the predefined "No designs found within the specified range of trend factor" message
    if (is.character(trend_designs) && length(trend_designs) == 1 && trend_designs == "No designs found within the specified range of trend factor") {
      cat(trend_designs, "\n")  # Print the message
    }
    # Case 2: Check if trend_designs contains actual designs
    else {
      cat("Minimally Changed Designs within specified Trend Factor Range:\n\n")

      # Print each design in a structured format
      for (i in seq_along(trend_designs)) {
        cat("Design", i, ":\n")

        # Print the design matrix row-wise
        apply(trend_designs[[i]][[1]], 1, function(row) cat(paste(sprintf("%3d", row), collapse = "  "), "\n"))

        # Print D, Dt, and Trend Factor values
        cat("D value:", trend_designs[[i]]$D_value, "\n")
        cat("Dt value:", trend_designs[[i]]$Dt_value, "\n")
        cat("Trend factor:", trend_designs[[i]]$Trend_factor, "\n")
        cat("\n------------------------------\n\n")  # Separator line
      }
    }
  })
}

# Run the app
shinyApp(ui = ui, server = server)
