
# Defines site header
argonHeader <- argonDash::argonDashHeader(
  gradient = TRUE,
  color = "primary",
  separator = FALSE,
  separator_color = "secondary",
  
  argonR::argonH1("EasyQrlabelr", display = 3, class = "text-center"),
  
  
  # Add a help info drop down menu to page; positioned at top-right corner
  argonR::argonRow(center = TRUE,
                   shinyWidgets::dropdownButton(
                     inputId = "help1",
                     label = "HELP!",
                     status = "success",
                     size = "default",
                     circle = FALSE,
                     inline = TRUE,
                     margin = "10%",
                     width = "200%",
                     icon = argonR::argonIcon(name="settings", color = "yellow"),
                     
                     # Help menu for import fieldbook tab
                     div(
                       actionLink(inputId = "help2", "Import fieldbook tab"),
                       
                       shinyBS::bsPopover(id = "help2",
                                          title = "Import fieldbook tab",
                                          placement = "bottom",
                                          trigger = "click",
                                          content = paste("<li>Click <strong>Browse</strong> to upload your fieldbook file in csv, xls, or xlsx format.",
                                                          "For programs with no access to BMS, we recommend using the free FieldHub Shiny app to generate a fieldbook.",
                                                          "Users using BMS to generate a fieldbook must remember to add a field map before exporting a study book",
                                                          sep = "<br><li>"),
                                          options = list(container = "body"))),
                     
                     br(),
                     # Help menu for Label information tab
                     div(
                       actionLink(inputId = "help3", "Label information tab"),
                       
                       shinyBS::bsPopover(id = "help3",
                                          title = "Label information tab",
                                          placement = "bottom",
                                          trigger = "click",
                                          content = paste("<li>Users must fill out all fields before generating QR codes.",
                                                          "The program can generate reproducible unique IDs for each plot if this option is selected below.",
                                                          "The program combines location, year, trial name, plot, row and column IDs to generate reproducible unique IDs.",
                                                          "The program can generate universal unique IDs (UUIDs)  for each plot if this option is selected below.",
                                                          "Note that UUIDs are randomly generated, hence, not reproducible and are uninformative.",
                                                          "Users must first generate QR codes before proceeding to other tabs or pages.",
                                                          sep = "<br><li>"),
                                          options = list(container = "body"))),
                     
                     br(),
                     # Help menu for Template setup tab
                     div(
                       actionLink(inputId = "help4", "Template setup tab"),
                       
                       shinyBS::bsPopover(id = "help4",
                                          title = "Template setup tab",
                                          placement = "bottom",
                                          trigger = "click",
                                          content = paste("<li>Select one of the available label templates from popular vendors.",
                                                          "See table below for details of available label templates.",
                                                          "Choose <strong>Custom</strong> if you do not find your template.",
                                                          sep = "<br><li>"),
                                          options = list(container = "body"))),
                     
                     br(),
                     # Help menu for page setup tab
                     div(
                       actionLink(inputId = "help5", "Page setup tab"),
                       
                       shinyBS::bsPopover(id = "help5",
                                          title = "Page setup tab",
                                          placement = "bottom",
                                          trigger = "click",
                                          content = paste("<li>Manually input page margin and size parameters (in inches) if you selected Custom label template in the Template setup widget",
                                                          "The inputed number of rows and columns for labels per page must be intergers.",
                                                          "Check the website of the label vendor to get the these page setting parameters.",
                                                          sep = "<br><li>"),
                                          options = list(container = "body"))),
                     
                     br(),
                     # Help menu for Label setup tab
                     div(
                       actionLink(inputId = "help6", "Label setup tab"),
                       
                       shinyBS::bsPopover(id = "help6",
                                          title = "Label setup tab",
                                          placement = "bottom",
                                          trigger = "click",
                                          content = paste("<li>Manually input label dimensions (in inches) if you selected Custom label template in the Template setup widget",
                                                          "Check the website of the label vendor to get these page setting parameters.",
                                                          "Use the label preview output to set an appropriate font size.",
                                                          sep = "<br><li>"),
                                          options = list(container = "body"))),
                     br(),
                     # Help menu for Generate labels tab
                     div(
                       actionLink(inputId = "help7", "Generate labels tab"),
                       
                       shinyBS::bsPopover(id = "help7",
                                          title = "Generate labels tab",
                                          placement = "bottom",
                                          trigger = "click",
                                          content = paste("<li>By default, the Generate label button is set to print labels by LOCATION subsets",
                                                          "Turn on the corresponding switches below to generate ALL labels or by REP and LOCATION subsets",
                                                          sep = "<br><li>"),
                                          options = list(container = "body")))
                     
                   )
                   
  )
  
)

# Defines site sidebar
argonSidebar <- argonDash::argonDashSidebar(
  vertical = TRUE,
  skin = "light",
  background = "white",
  size = "md",
  brand_logo = "qrlabelr.jpg",
  side = "left",
  
  id = "my_sidebar",
  
  argonDash::argonSidebarHeader(title = "Main Menu"),
  argonDash::argonSidebarMenu(
    argonDash::argonSidebarItem(
      tabName = "welcome",
      icon = argonR::argonIcon(name = "satisfied", color = "green"),
      "Welcome"
    ),
    
    argonDash::argonSidebarItem(
      tabName = "data_import",
      icon = argonR::argonIcon(name = "cloud-upload-96", color = "info"),
      "Import fieldbook"
    ),
    
    argonDash::argonSidebarItem(
      tabName = "label_info",
      icon = argonR::argonIcon(name = "tag", color = "green"),
      "Label information"
    ),
    
    argonDash::argonSidebarItem(
      tabName = "template_setup",
      icon = argonR::argonIcon(name = "palette", color = "default"),
      "Template setup"
    ),
    argonDash::argonSidebarItem(
      tabName = "page_setup",
      icon = argonR::argonIcon(name = "tv-2", color = "info"),
      "Page setup"
    ),
    argonDash::argonSidebarItem(
      tabName = "label_setup",
      icon = argonR::argonIcon(name = "settings", color = "green"),
      "Label setup"
    ),
    
    argonDash::argonSidebarItem(
      tabName = "generate_labels",
      icon = argonR::argonIcon(name = "button-play", color = "primary"),
      "Generate labels"
    )
  ),
  argonDash::argonSidebarDivider()
)

# Defines site footer
argonFooter <- argonDash::argonDashFooter(
  copyrights = "Copyright © 2023 Alexander Kena | Ebenezer Ogoe | Clara Burgos |
  Geoffrey Morris",
  src = NULL,
  argonDash::argonFooterMenu(
    argonDash::argonFooterItem("Submit issues on this Shiny app on GitHub",
                               src = "https://github.com/awkena/qrlabelr")
  )
)


# Welcome page
pg_welcome <- argonDash::argonTabItem(
  tabName = "welcome",
  argonR::argonRow(center = TRUE,
                   
                   argonR::argonColumn(width = 6,
                                       
                                       tags$head(
                                         tags$style(
                                           HTML("#logos {
                         padding-top: 5px;
                         padding-left: 3px;
                         padding-right: 3px;
                         margin-bottom: -15px;
                         max-width: 100%;
                         height: auto;
                       }" ))),
                       
                       argonR::argonCarousel(id = "logos",
                                             floating = TRUE,
                                             width = 12,
                                             
                                             div(style = "margin-bottom: -150px;",
                                                 argonR::argonCarouselItem(
                                                   src = "logos.png",
                                                   active = TRUE)
                                             )
                                             
                       ))
                   
  ),
  
  
  br(),
  
  # Some intro text that may need to be summarized into two paragraphs or less
  argonR::argonH1("Welcome!", display = 4),
  
  p("Welcome to EasyQrlabelR: a BrAPI-compliant shiny app for the qrlabelr package for designing print-ready
    plot labels affixed with QR codes. This app simplifies the complicated process
    of label design. It generates plot labels that are compatible with the
    widely used digital data collection mobile app, Field Book.",
    style = "text-align: justify; margin-top: 10px;"),
  
  p("Users can upload a field/study book either from a local source (csv, xls, or xlsx file format)
    or from a BrAPI database. The supported BrAPI databases are BMS and BreedBase.
    The imported data should contain plot or sample attributes.",
    style = "text-align: justify; margin-top: 10px;"),
  
  p("Users can either choose from a list of preset common label templates or opt to
    design any custom rectangular label given the page and label setting parameters.",
    style = "text-align: justify; margin-top: 10px;"),
  
  p(" The app outputs a downloadable PDF file based on user-defined page
  and label setting parameters. Users can also download an updated fieldbook for
  digital data collection.", style = "text-align: justify; margin-top: 10px;"),
  
  br(),
  
  argonR::argonImage(
    src = "workflow.png",
    card_mode = TRUE,
  ),
  
  br(),
  
  argonR::argonH1("How to use this Shiny app", display = 4),
  
  # Instruction infographic
  argonR::argonImage(
    src = "instructions.png",
    card_mode = TRUE,
  )
  
)

# Fieldbook import tab setup
pg_data_import <- argonDash::argonTabItem(
  tabName = "data_import",
  
  argonR::argonCard(
    width = 12,
    title = "Upload your data",
    src = NULL,
    hover_lift = FALSE,
    shadow = TRUE,
    shadow_size = NULL,
    hover_shadow = FALSE,
    border_level = 0,
    icon = argonR::argonIcon("atom"),
    status = "primary",
    background_color = NULL,
    gradient = FALSE,
    floating = FALSE,
    
    p(tags$strong("Select input data source:")),
    
    argonR::argonRow(
      argonR::argonColumn(width = 6,
                          shinyWidgets::prettySwitch(inputId = "from_local",
                                                     label = "From local source",
                                                     value = FALSE, status = "primary", fill = FALSE))),
    
    argonR::argonRow(
      argonR::argonColumn(width = 6,
                          shinyWidgets::prettySwitch(inputId = "brapi",
                                                     label = "From BrAPI Databases",
                                                     value = FALSE, status = "primary", fill = FALSE))
    ),
    
    br(),
    
    div(id = "local_source",
        # Custom CSS to style the file upload widget. The specific classes and IDs were
        # identified with Mozilla Firefox's Inspect element
        tags$style(HTML('#datUploader_progress {height: 15px !important;}
                    .input-group .form-control:not(:first-child) {
                    padding-left: 10px; border-left: 0;}
                    #my_sidebar > div > a > img {
                    max-height: 8.5rem !important;}
                    ')),
        
        fileInput(inputId = "datUploader", "Upload a Fieldbook file in CSV, XLS, or
              XLSX format:",
              accept = c(".csv", ".xls", ".xlsx"),
              width = '50%',
              placeholder = "  No file selected"),
        
        argonR::argonRow(center = TRUE,
                         argonR::argonColumn(width = 6,
                                             shinyjs::disabled(shinyWidgets::prettySwitch(inputId = "from_fieldhub",
                                                                                          label = "From FieldHub",
                                                                                          value = FALSE, status = "primary", fill = TRUE)),
                                             
                                             shinyBS::bsPopover(id = "from_fieldhub", title = "FieldHub switch",
                                                                content = "Turn on the switch if imported fieldbook was generated using the FieldHub package",
                                                                placement = "top",
                                                                trigger = "focus",
                                                                options = list(container = "body"))
                                             
                                             # shinyjs::disabled(shinyWidgets::prettySwitch(inputId = "from_BMS",
                                             #                                              label = "From BMS",
                                             #                                              value = FALSE, status = "primary", fill = TRUE)),
                                             # 
                                             # shinyBS::bsPopover(id = "from_BMS", title = "BMS switch",
                                             #                    content = "Turn on the switch if imported fieldbook was generated in BMS",
                                             #                    placement = "top",
                                             #                    trigger = "focus",
                                             #                    options = list(container = "body")),
                                             # 
                                             # shinyjs::disabled(shinyWidgets::prettySwitch(inputId = "preview_dat",
                                             #                                              label = "Preview Fieldbook",
                                             #                                              value = FALSE, status = "primary", fill = TRUE)),
                                             # 
                                             # shinyBS::bsPopover(id = "preview_dat", title = "Preview fieldbook switch",
                                             #                    content = "Turn on the switch to preview the imported fieldbook",
                                             #                    placement = "top",
                                             #                    trigger = "focus",
                                             #                    options = list(container = "body"))
                         )
        ))
    
    
    
  ),
  
  # Card for BrAPI
  argonR::argonCard(
    width = 12,
    title = "Import from BrAPI supported databases",
    src = NULL,
    hover_lift = FALSE,
    shadow = TRUE,
    shadow_size = NULL,
    hover_shadow = FALSE,
    border_level = 0,
    icon = argonR::argonIcon("atom"),
    status = "primary",
    background_color = NULL,
    gradient = FALSE,
    floating = FALSE,
    
    
    div(id = "brapi_inputs",
        
        
        argonR::argonRow(
          argonR::argonColumn(width = 4,
                              textInput("login_lk", "Enter link to login page:")),
          
          argonR::argonColumn(width = 4,
                              selectInput("brapi_engine", "Select engine:", choices = c("bms", "breedbase"))),
          
          argonR::argonColumn(width = 4,
                              shinyWidgets::prettyCheckbox(inputId = "no_auth", 
                                                           label = "No authentication?", 
                                                           status = "primary", 
                                                           shape = "curve",
                                                           value = FALSE))
          
          
          
        ),
        
        p("Do not expose your login credentials"),
        p("Use database login credentials to sign in"),
        
        argonR::argonRow(
          argonR::argonColumn(width = 4,
                              textInput("user_name", "User name:")),
          
          argonR::argonColumn(width = 4,
                              passwordInput("pwd", "Password:")),
          
          argonR::argonColumn(width = 4,
                              selectInput("brapi_crops", "Select crop:", choices = "none"))
          
          
        ),
        
        argonR::argonRow(
          
          # After this Shiny app is converted into a package
          argonR::argonColumn(width = 4, center = TRUE,
                              actionButton(inputId = "brapi_login", "Connect", icon = NULL, width = NULL,
                                           span(id="Animate", class=""))),
          
          argonR::argonColumn(width = 4, offset = 4, center = TRUE,
                              actionButton("GET1", "GET program", icon = NULL, width = NULL,
                                           span(id="Animate", class="")))
          
        ),
        
        
        
        br(), br(),
        p("Select program after successful connection"),
        argonR::argonRow(
          
          argonR::argonColumn(width = 4,
                              selectizeInput("brapi_prgs", "Select program:", choices = "none")),
          
          argonR::argonColumn(width = 4,
                              selectInput("brapi_trials", "Select trial:", choices = "none")),
          
          argonR::argonColumn(width = 4,
                              selectizeInput("brapi_studies", "Select study:", choices = "none"))
          
          
        ),
        
        argonR::argonRow(
          
          
          argonR::argonColumn(width = 4, center = TRUE,
                              actionButton("GET2", "GET trial", icon = NULL, width = NULL,
                                           span(id="Animate", class=""))),
          
          argonR::argonColumn(width = 4, center = TRUE,
                              actionButton("GET3", "GET study", icon = NULL, width = NULL,
                                           span(id="Animate", class=""))),
          
          argonR::argonColumn(width = 4, center = TRUE,
                              actionButton("GET4", "GET data", icon = NULL, width = NULL,
                                           span(id="Animate", class="")))
          
          
        )
    )
  ),
  
  div(id = "fieldbookcard",
      argonR::argonCard(
        width = 12,
        title = "Imported Field book",
        src = NULL,
        hover_lift = FALSE,
        shadow = TRUE,
        shadow_size = NULL,
        hover_shadow = FALSE,
        border_level = 0,
        icon = argonR::argonIcon("atom"),
        status = "primary",
        background_color = NULL,
        gradient = FALSE,
        floating = FALSE,
        
        argonR::argonRow(
          argonR::argonColumn(width = 12,
                              shinyjs::disabled(actionButton(inputId = "submit_dat", "Submit Fieldbook")))
        ),
        
        br(), 
        
        # Output for imported field book
        reactable::reactableOutput(outputId = "imported_fieldbook"),
        
        br(), br(), br(),
        
        argonR::argonRow(
          argonR::argonColumn(width = 12, offset = 8,
                              actionButton(inputId = "npg1", label = div("Next", icon("chevron-right")))
                              
                              
          )),
      )
  )
)

# Label information tab setup
warn <- "Submit a Fieldbook first"
warn_2 <- "Upload label data sheet"

# Generate labels tab setup
pg_generate_labels <- argonDash::argonTabItem(
  tabName = "generate_labels",
  
  
  # Mimics a classic ArgonUI card
  argonR::argonCard(
    # Card configuration
    width = 12,
    title = "Page parameters",
    src = NULL,
    hover_lift = FALSE,
    shadow = TRUE,
    shadow_size = NULL,
    hover_shadow = FALSE,
    border_level = 0,
    icon = argonR::argonIcon("atom"),
    status = "primary",
    background_color = NULL,
    gradient = FALSE,
    floating = FALSE,
    
    # Page items
    argonR::argonRow(
      argonR::argonColumn(width = 3,
                          textInput("filename", "Enter pdf file name prefix", value = "PlotLabel"))
    ),
    
    
    actionButton(inputId = "gen_labels", label = ("Generate labels "),
                 icon = NULL, width = NULL, span(id="UpdateAnimate", class="")),
    
    br(), br(), br(),
    
    argonR::argonRow(
      argonR::argonColumn(width = 12,
                          shinyjs::disabled(downloadButton(outputId = "down_labels",
                                                           "Download labels"))
      )),
    
    br(), br(),
    
    argonR::argonRow(center = TRUE,
                     shinyjs::disabled(downloadButton(outputId = "down_fieldbook",
                                                      "Download Fieldbook"))
    )
    
  )
  
)


pg_label_info <- argonDash::argonTabItem(
  tabName = "label_info",
  
  
  # Mimics a classic ArgonUI card
  argonR::argonCard(
    # Card configuration
    width = 12,
    title = "Page parameters",
    src = NULL,
    hover_lift = FALSE,
    shadow = TRUE,
    shadow_size = NULL,
    hover_shadow = FALSE,
    border_level = 0,
    icon = argonR::argonIcon("atom"),
    status = "primary",
    background_color = NULL,
    gradient = FALSE,
    floating = FALSE,
    
    argonR::argonRow(
      argonR::argonColumn(width = 6,
                          
                          shinyBS::popify(shinyWidgets::pickerInput(inputId = "label_type",
                                                                    label = "Select type of label",
                                                                    choices = c("Field plot label" = "field",
                                                                                "General-purpose landscape text label" = "gp",
                                                                                "General-purpose portrait text label" = "gpp"),
                                                                    selected = "Field plot label with QR code",
                                                                    width = "75%",
                                                                    options = list(style = "btn-primary")),
                                          trigger = "focus",
                                          title = "Type of label to design", placement = "top",
                                          content =  "Select from the available options the type of label to design."),
                          
                          shinyBS::popify(shinyWidgets::pickerInput(inputId = "uniqueids",
                                                                    label = "Select method for unique IDs",
                                                                    choices = c("Reproducible Unique IDs" = "get_unique_id",
                                                                                "Universal Unique IDs" = "uuids", "Custom Unique IDs" = "use_my_id"),
                                                                    selected = "Reproducible Unique IDs",
                                                                    width = "75%",
                                                                    options = list(style = "btn-primary")),
                                          
                                          trigger = "focus",
                                          title = "Method for generating unique IDs", placement = "top",
                                          content =  "Select the <strong>Custom</strong> option if imported fieldbook contains a unique ID column for QR codes."),
      ),
      
      argonR::argonColumn(width = 6,
                          shinyBS::popify(
                            shinyjs::disabled(
                              sliderInput(inputId = "ec_level", label = "QR code error level",
                                          min = 0, max = 3, step = 1, value = 3)),
                            
                            trigger = "focus",
                            title = "QR code error correction level", placement = "right",
                            content =  "Use error correction level of 3 if labels will be used in the field."),
                          
                          shinyjs::disabled(actionButton(inputId = "gen_qrcode",
                                                         label = "Generate QR codes",
                                                         icon = NULL, width = NULL,
                                                         span(id="Animate", class=""))
                          ))),
    br(),
    
    argonR::argonRow(center = TRUE,
                     
                     argonR::argonColumn(width = 6,
                                         
                                         shinyBS::popify(shinyWidgets::prettyCheckbox(inputId = "IBlock", label = "Incomplete blocks",
                                                                                      value = FALSE, status = "primary", shape = "curve",
                                                                                      outline = TRUE),
                                                         
                                                         trigger = "focus",
                                                         title = "iBlock switch", placement = "top",
                                                         content = "Turn on the switch if imported fieldbook contains incomplete blocks within REPS"),
                                         
                                         shinyBS::popify(shinyWidgets::prettyCheckbox(inputId = "seed_source", inline = TRUE,
                                                                                      label = "Show seed source",
                                                                                      value = FALSE, status = "primary", shape = "curve",
                                                                                      outline = TRUE),
                                                         
                                                         trigger = "focus",
                                                         title = "Seed Source Switch", placement = "bottom",
                                                         content = "Turn on the switch to show input widget for seed source.")
                     )
    )
  ),
  
  
  argonR::argonCard(
    # Card configuration
    width = 12,
    title = "Page parameters",
    src = NULL,
    hover_lift = FALSE,
    shadow = TRUE,
    shadow_size = NULL,
    hover_shadow = FALSE,
    border_level = 0,
    icon = argonR::argonIcon("atom"),
    status = "primary",
    background_color = NULL,
    gradient = FALSE,
    floating = FALSE,
    
    argonR::argonRow(
      
      argonR::argonColumn(width = 6,
                          
                          numericInput(inputId = "yr", label = "Input year of experiment",
                                       value = "", min = 1970, max = 2050)),
      
      argonR::argonColumn(width = 6,
                          shinyBS::popify(trigger = "focus",
                                          textInput(inputId = "tname", label = "Input trial name",
                                                    value = "PYT"),
                                          title = "Trial name", placement = "top",
                                          content =  "Input a short descriptive name for the trial before generating QR codes."))
    ),
    
    argonR::argonRow(
      
      argonR::argonColumn(width = 6,
                          textInput(inputId = "rname", label = "Input your name",
                                    value = "", placeholder = 'Initial(s) + Last name'),
      ),
      
      argonR::argonColumn(width = 6,
                          
                          selectInput(inputId = "seed", label = "Select seed source ID",
                                      choices = warn))
      
    ),
    
    argonR::argonRow(
      argonR::argonColumn(width = 6,
                          selectInput(inputId = "rep_id", "Select ID for REP", choices = warn),
                          selectInput(inputId = "row_id", "Select ID for ROW", choices = warn),
                          selectInput(inputId = "loc_id", "Select ID for LOCATION", choices = warn),
                          selectInput(inputId = "IBlock_id", "Select ID for IBlock", choices = warn)
      ),
      
      argonR::argonColumn(width = 6,
                          selectInput("plot_id", "Select ID for PLOT", choices = warn),
                          selectInput("col_id", "Select ID for COLUMN", choices = warn),
                          selectInput("entry_id", "Select ID for TREATMENT/ENTRY", choices = warn),
                          selectInput("unique_id", "Select ID for UNIQUE IDs", choices = warn)
      )
    ), # End of input widgets for field plot labels
    
    
    # Input widgets for general purpose labels with QR code (15 widgets)
    argonR::argonRow(center = TRUE,
                     shinyWidgets::pickerInput(inputId = "QRcode_id", label = "Select QR code ID",
                                               choices = warn_2, options = list(style = "btn-primary"))
    ),
    
    br(),
    
    argonR::argonRow(
      argonR::argonColumn(width = 6,
                          shinyWidgets::dropdownButton(
                            inputId = "toplt",
                            label = "Top-left position",
                            status = "success",
                            icon = argonR::argonIcon(name = "tag", color = "yellow"),
                            width = "250%",
                            margin = "5%",
                            circle = FALSE,
                            size = "sm",
                            
                            argonR::argonRow(
                              
                              argonR::argonColumn(width = 6,
                                                  textInput(inputId = "toplt_txt_r1", label = "ROW 1 text prefix",
                                                            value = "", placeholder = "Enter a short text"),
                                                  textInput(inputId = "toplt_txt_r2", label = "ROW 2 text prefix",
                                                            value = "", placeholder = "Enter a short text")),
                              
                              argonR::argonColumn(width = 6,
                                                  selectInput("toplt_sel_r1", "Select ID for ROW 1", choices = warn_2),
                                                  selectInput("toplt_sel_r2", "Select ID for ROW 2", choices = warn_2))
                              
                            ))),
      
      br(), br(), br(),
      
      argonR::argonColumn(width = 6,
                          shinyWidgets::dropdownButton(
                            inputId = "centrt",
                            label = "Center-right position",
                            status = "success",
                            icon = argonR::argonIcon(name = "tag", color = "yellow"),
                            width = "250%",
                            margin = "5%",
                            circle = FALSE,
                            size = "sm",
                            
                            argonR::argonRow(
                              
                              argonR::argonColumn(width = 6,
                                                  textInput(inputId = "centrt_txt_r1", label = "ROW 1 text prefix",
                                                            value = "", placeholder = "Enter a short text"),
                                                  textInput(inputId = "centrt_txt_r2", label = "ROW 2 text prefix",
                                                            value = "", placeholder = "Enter a short text"),
                                                  textInput(inputId = "centrt_txt_r3", label = "ROW 3 text prefix",
                                                            value = "", placeholder = "Enter a short text")),
                              
                              argonR::argonColumn(width = 6,
                                                  selectInput("centrt_sel_r1", "Select ID for ROW 1", choices = warn_2),
                                                  selectInput("centrt_sel_r2", "Select ID for ROW 2", choices = warn_2),
                                                  selectInput("centrt_sel_r3", "Select ID for ROW 3", choices = warn_2))
                              
                            )))
    ),
    
    br(), br(), br(),
    
    argonR::argonRow(
      argonR::argonColumn(width = 6,
                          shinyWidgets::dropdownButton(
                            inputId = "toprt",
                            label = "Top-right position",
                            status = "success",
                            icon = argonR::argonIcon(name = "tag", color = "yellow"),
                            width = "250%",
                            margin = "5%",
                            circle = FALSE,
                            size = "sm",
                            
                            
                            argonR::argonRow(
                              argonR::argonColumn(width = 6,
                                                  textInput(inputId = "toprt_txt_r1", label = "ROW 1 text prefix",
                                                            value = "", placeholder = "Enter a short text"),
                                                  textInput(inputId = "toprt_txt_r2", label = "ROW 2 text prefix",
                                                            value = "", placeholder = "Enter a short text")),
                              
                              argonR::argonColumn(width = 6,
                                                  selectInput("toprt_sel_r1", "Select ID for ROW 1", choices = warn_2),
                                                  selectInput("toprt_sel_r2", "Select ID for ROW 2", choices = warn_2))
                              
                            ))),
      
      br(), br(), br(),
      
      argonR::argonColumn(width = 6,
                          shinyWidgets::dropdownButton(
                            inputId = "botlt",
                            label = "Bottom-left position",
                            status = "success",
                            icon = argonR::argonIcon(name = "tag", color = "yellow"),
                            width = "250%",
                            margin = "5%",
                            circle = FALSE,
                            size = "sm",
                            
                            argonR::argonRow(
                              argonR::argonColumn(width = 6,
                                                  textInput(inputId = "botlt_txt_r1", label = "ROW 1 text prefix",
                                                            value = "", placeholder = "Enter a short text"),
                                                  textInput(inputId = "botlt_txt_r2", label = "ROW 2 text prefix",
                                                            value = "", placeholder = "Enter a short text")),
                              
                              argonR::argonColumn(width = 6,
                                                  selectInput("botlt_sel_r1", "Select ID for ROW 1", choices = warn_2),
                                                  selectInput("botlt_sel_r2", "Select ID for ROW 2", choices = warn_2))
                              
                            )))
    ),
    
    #-----------------------------------------------------------------------------------------------#
    # Input widgets for general purpose labels with portrait text orientation (15 widgets)
    argonR::argonRow(center = TRUE,
                     shinyWidgets::pickerInput(inputId = "QRcode_id2", label = "Select QR code ID",
                                               choices = warn_2, options = list(style = "btn-primary"))
    ),
    
    br(),
    
    argonR::argonRow(
      argonR::argonColumn(width = 6,
                          shinyWidgets::dropdownButton(
                            inputId = "toptxt",
                            label = "Top text positions",
                            status = "success",
                            icon = argonR::argonIcon(name = "tag", color = "yellow"),
                            width = "250%",
                            margin = "5%",
                            circle = FALSE,
                            size = "sm",
                            
                            argonR::argonRow(
                              
                              argonR::argonColumn(width = 6,
                                                  textInput(inputId = "top_txt1", label = "ROW 1 text prefix",
                                                            value = "", placeholder = "Enter a short text"),
                                                  textInput(inputId = "top_txt2", label = "ROW 2 text prefix",
                                                            value = "", placeholder = "Enter a short text"),
                                                  textInput(inputId = "top_txt3", label = "ROW 3 text prefix",
                                                            value = "", placeholder = "Enter a short text")
                              ),
                              
                              argonR::argonColumn(width = 6,
                                                  selectInput("top_sel1", "Select ID for ROW 1", choices = warn_2),
                                                  selectInput("top_sel2", "Select ID for ROW 2", choices = warn_2),
                                                  selectInput("top_sel3", "Select ID for ROW 3", choices = warn_2)
                              )
                              
                            ))),
      
      br(), br(), br(),
      
      argonR::argonColumn(width = 6,
                          shinyWidgets::dropdownButton(
                            inputId = "centtxt",
                            label = "Center text positions",
                            status = "success",
                            icon = argonR::argonIcon(name = "tag", color = "yellow"),
                            width = "250%",
                            margin = "5%",
                            circle = FALSE,
                            size = "sm",
                            
                            argonR::argonRow(
                              
                              argonR::argonColumn(width = 6,
                                                  textInput(inputId = "cent_txt1", label = "ROW 1 text prefix",
                                                            value = "", placeholder = "Enter a short text"),
                                                  textInput(inputId = "cent_txt2", label = "ROW 2 text prefix",
                                                            value = "", placeholder = "Enter a short text"),
                                                  textInput(inputId = "cent_txt3", label = "ROW 3 text prefix",
                                                            value = "", placeholder = "Enter a short text"),
                                                  textInput(inputId = "cent_txt4", label = "ROW 4 text prefix",
                                                            value = "", placeholder = "Enter a short text")),
                              
                              argonR::argonColumn(width = 6,
                                                  selectInput("cent_sel1", "Select ID for ROW 1", choices = warn_2),
                                                  selectInput("cent_sel2", "Select ID for ROW 2", choices = warn_2),
                                                  selectInput("cent_sel3", "Select ID for ROW 3", choices = warn_2),
                                                  selectInput("cent_sel4", "Select ID for ROW 4", choices = warn_2)
                              )
                              
                            )))
    ),
    
    br(), br(), br(),
    
    argonR::argonRow(
      
      argonR::argonColumn(width = 6,
                          shinyWidgets::dropdownButton(
                            inputId = "bottxt",
                            label = "Bottom text positions",
                            status = "success",
                            icon = argonR::argonIcon(name = "tag", color = "yellow"),
                            width = "250%",
                            margin = "5%",
                            circle = FALSE,
                            size = "sm",
                            
                            argonR::argonRow(
                              argonR::argonColumn(width = 6,
                                                  textInput(inputId = "bot_txt1", label = "ROW 1 text prefix",
                                                            value = "", placeholder = "Enter a short text"),
                                                  textInput(inputId = "bot_txt2", label = "ROW 2 text prefix",
                                                            value = "", placeholder = "Enter a short text"),
                                                  textInput(inputId = "bot_txt3", label = "ROW 3 text prefix",
                                                            value = "", placeholder = "Enter a short text")
                              ),
                              
                              argonR::argonColumn(width = 6,
                                                  selectInput("bot_sel1", "Select ID for ROW 1", choices = warn_2),
                                                  selectInput("bot_sel2", "Select ID for ROW 2", choices = warn_2),
                                                  selectInput("bot_sel3", "Select ID for ROW 3", choices = warn_2),
                              )
                              
                            )))
    ),
    
    
    
    #----------------------------------------------------------------------------------------------#   
    
    
    br(),
    
    
    
    argonR::argonRow(
      argonR::argonColumn(width = 4,
                          actionButton(inputId = "npg2", label = div("Next", icon("chevron-right"))))
    )
  )
)

# Label setting tab setup
pg_label_setup <- argonDash::argonTabItem(
  tabName = "label_setup",
  
  
  # Mimics a classic ArgonUI card
  argonR::argonCard(
    # Card configuration
    width = 12,
    title = "Page parameters",
    src = NULL,
    hover_lift = FALSE,
    shadow = TRUE,
    shadow_size = NULL,
    hover_shadow = FALSE,
    border_level = 0,
    icon = argonR::argonIcon("atom"),
    status = "primary",
    background_color = NULL,
    gradient = FALSE,
    floating = FALSE,
    
    # Page items
    h4("Label dimensions"),
    argonR::argonRow(
      argonR::argonColumn(width = 6,
                          numericInput(inputId = "wdt", "Label width (inches)", value = 2, min = 2, max = 4)
      ),
      
      argonR::argonColumn(width = 6,
                          numericInput(inputId = "hgt", "Label height (inches)", value = 1, min = 1, max = 3))
    ),
    
    br(),
    
    argonR::argonRow(
      argonR::argonColumn(width = 6,
                          shinyWidgets::pickerInput(inputId = "family", label = h4("Choose font family"),
                                                    choices = c("Helvetica" = "sans", "Times" = "serif",
                                                                "Courier" = "mono"),
                                                    selected = "sans",
                                                    options = list(title = "None selected", style = "btn-primary"))
      ),
      
      argonR::argonColumn(width = 6,
                          shinyBS::popify(trigger = "focus",
                                          numericInput(inputId = "font_size", h4("Set Font Size:"), value = 8,
                                                       min = 1, max = 28),
                                          title = "Font Size", placement = "top",
                                          content =  "Use the label preview below to choose an appropriate font size.")
      )
    ),
    
    br(),
    
    argonR::argonRow(
      argonR::argonColumn(width = 6,
                          shinyWidgets::prettyCheckbox(inputId = "rounded", label = "Round corner labels",
                                                       value = TRUE, status = "primary", shape = "curve", outline = TRUE)),
      
      argonR::argonColumn(width = 6,
                          shinyWidgets::prettyCheckbox(inputId = "rect", label = "Draw rectangle around label",
                                                       value = TRUE, status = "primary", shape = "curve", outline = TRUE)),
      
      argonR::argonColumn(width = 6,
                          shinyWidgets::prettyCheckbox(inputId = "print_across", label = "Fill page by row",
                                                       value = TRUE, status = "primary", shape = "curve", outline = TRUE))),
    
    br(),
    
    argonR::argonRow(
      argonR::argonColumn(width = 4,
                          actionButton(inputId = "npg5", label = div("Next", icon("chevron-right"))))
    )
  ),
  
  argonR::argonCard(
    width = 12,
    title = "Preview label",
    src = NULL,
    hover_lift = FALSE,
    shadow = TRUE,
    shadow_size = NULL,
    hover_shadow = FALSE,
    border_level = 0,
    icon = argonR::argonIcon("atom"),
    status = "primary",
    background_color = NULL,
    gradient = FALSE,
    floating = FALSE,
    
    #p("Alternatively, launch the FielDHub Shiny app to generate a FieldBook"),
    #p("Currently points to the GitHub's page of package author"),
    argonR::argonRow(
      argonR::argonColumn(width = 6,
                          shinyBS::popify(trigger = "focus",
                                          numericInput(inputId = "lab_sel", h4("Input label to preview:"),
                                                       value = 1, min = 1),
                                          title = "Label to preview", placement = "top",
                                          content =  "Input the row number of any plot in your fieldbook to preview its label.")
                          
      )),
    
    br(),
    # Plot output
    plotOutput(outputId = "preview", height = "800px")
  )
)

# Page settings tab setup
pg_page_setup <- argonDash::argonTabItem(
  tabName = "page_setup",
  
  # Mimics a classic ArgonUI card
  argonR::argonCard(
    # Card configuration
    width = 12,
    title = "Page parameters",
    src = NULL,
    hover_lift = FALSE,
    shadow = TRUE,
    shadow_size = NULL,
    hover_shadow = FALSE,
    border_level = 0,
    icon = argonR::argonIcon("atom"),
    status = "primary",
    background_color = NULL,
    gradient = FALSE,
    floating = FALSE,
    
    # Page items
    # Margins
    argonR::argonRow(argonR::argonColumn(width = 6,
                                         h4("Height margins (inches)"),
                                         numericInput(inputId = "top_mar", "Top", value = 0.625, min = 0.5,
                                                      max = 2),
                                         numericInput(inputId = "bot_mar", "Bottom", value = 0.625, min = 1,
                                                      max = 2)),
                     
                     argonR::argonColumn(width = 6,
                                         h4("Width margins (inches)"),
                                         numericInput(inputId = "left_mar", "Left", value = 0.625,
                                                      min = 0.5, max = 2),
                                         numericInput(inputId = "right_mar", "Right", value = 0.625,
                                                      min = 1, max = 2)
                     )
    ),
    
    br(),
    h4("Labels per page:"),
    argonR::argonRow(
      argonR::argonColumn(width = 6,
                          
                          numericInput(inputId = "numrow", "Number of rows", value = 8,
                                       min = 1, max = 3),
                          
                          numericInput(inputId = "numcol", "Number of columns", value = 3,
                                       min = 1, max = 3)),
      
      argonR::argonColumn(width = 6,
                          numericInput(inputId = "page_wdt", "Page width (inches)", value = 8.5,
                                       min = 1, max = 3, step = 0.1),
                          numericInput(inputId = "page_hgt", "Page height (inches)", value = 11,
                                       min = 1, max = 3, step = 0.1))
    ),
    
    argonR::argonRow(
      argonR::argonColumn(width = 4,
                          actionButton(inputId = "npg4", label = div("Next", icon("chevron-right"))))
    )
  )
)

# Label template tab setup
pg_template_setup <- argonDash::argonTabItem(
  tabName = "template_setup",
  
  
  # Mimics a classic ArgonUI card
  argonR::argonCard(
    # Card configuration
    width = 12,
    title = "Select any of the templates provided. Choose 'Custom' to define desired values.",
    src = NULL,
    hover_lift = FALSE,
    shadow = TRUE,
    shadow_size = NULL,
    hover_shadow = FALSE,
    border_level = 0,
    icon = argonR::argonIcon("atom"),
    status = "primary",
    background_color = NULL,
    gradient = FALSE,
    floating = FALSE,
    
    # Page items
    shinyBS::popify(trigger = "focus",
                    shinyWidgets::pickerInput(inputId = "templates", label = h4("Select a desired template"),
                                              choices = c("Custom","Avery 94220", "Avery 94200", "Avery 94224",
                                                          "Avery 94237", "Avery 94207", "Avery 94241",
                                                          "Avery 94213", "Avery 94242", "OnlineLabel OL5125",
                                                          "OnlineLabel RL778", "OnlineLabel RL2800",
                                                          "OnlineLabel RL782", "Treetag LTS14"),
                                              selected = "Avery 94220",
                                              options = list(style = "btn-primary")),
                    
                    title = "Custom setting", placement = "top",
                    content =  "Choose <strong>Custom</strong> to define your own values in the Page setup and Label setup tabs."),
    
    br(),
    
    argonR::argonRow(
      argonR::argonColumn(width = 4,
                          actionButton(inputId = "npg3", label = div("Next", icon("chevron-right"))))
    ),
    
    br(),
    
    argonR::argonH1("Common labels", display = 4),
    shinycssloaders::withSpinner(reactable::reactableOutput(outputId = "common_labels")),
    
    br(), br(),
    
    
  )
)


# Piece everything together in UI
ui <- function(request) {
  argonDash::argonDashPage(
    title = "EasyQrlabelr",
    author = "Alexander Wireko Kena, Ebenezer Ogoe, Clara Cruet Burgos, Geoffrey Preston Morris",
    description = "A Shiny app to generate custom print-ready plot labels affixed with QR codes",
    sidebar = argonSidebar,
    navbar = NULL,
    header = argonHeader,
    body = argonDash::argonDashBody(
      
      tags$head(
        tags$style(
          HTML(".shiny-notification {
              height: 100px;
              width: 300px;
              position:fixed;
              top: calc(25% - 30px);;
              left: calc(80% - 200px);;
            }
           "
          )
        )
      ),
      
      shinyjs::useShinyjs(),
      argonDash::argonTabItems(
        pg_welcome,
        pg_data_import,
        pg_label_info,
        pg_template_setup,
        pg_page_setup,
        pg_label_setup,
        pg_generate_labels
      ),
      
    ),
    footer = argonFooter
    
    
  )
}

# Server component of app
server <- function(input, output, session) {
  
  error_numeric <- "must be a positive numeric value."
  error_string <- "must be string value."
  
  # stop app when app is closed
  session$onSessionEnded(function() {
    stopApp()
    
  })
  
  
  # Event to navigate from data import tab to label info tab
  
  observeEvent(input$npg1, {
    shinyjs::runjs("$('a[data-value=\"label_info\"]').tab('show');")
    
  })
  
  
  # Event to navigate from label info tab to template setup tab
  
  observeEvent(input$npg2, {
    tryCatch({
      assertthat::assert_that(is.valid_count(input$yr) && nchar(input$yr) == 4,
                              msg = paste("Please provide a valid year."))
      assertthat::assert_that(assertthat::is.string(input$tname),
                              msg = paste("'Trial name'", error_string))
      assertthat::assert_that(assertthat::is.string(input$rname),
                              msg = paste("'Researcher name'", error_string))
      shinyjs::runjs("$('a[data-value=\"template_setup\"]').tab('show');")
      
    },
    warning = function(cond) {
      showModal(modalDialog(title = "Warning",
                            "Warnings were generated. Please double-check the entered
                            values and try again."))
    },
    error = function(cond) {
      showModal(modalDialog(title = "Error",
                            paste("The following error was generated:",
                                  cond$message, "Rectify before proceeding.")))
    })
  })
  
  
  # Event to navigate from template setup page to page setup tab
  
  observeEvent(input$npg3, {
    shinyjs::runjs("$('a[data-value=\"page_setup\"]').tab('show');")
    
  })
  
  # Event to navigate from page setup tab to label setup tab
  
  observeEvent(input$npg4, {
    tryCatch({
      assertthat::assert_that(is.valid_number(input$top_mar),
                              msg = paste("'Top margin'", error_numeric))
      assertthat::assert_that(is.valid_number(input$bot_mar),
                              msg = paste("'Bottom margin'", error_numeric))
      assertthat::assert_that(is.valid_number(input$left_mar),
                              msg = paste("'Left margin'", error_numeric))
      assertthat::assert_that(is.valid_number(input$right_mar),
                              msg = paste("'Right margin'", error_numeric))
      assertthat::assert_that(is.valid_number(input$page_wdt),
                              msg = paste("'Page width'", error_numeric))
      assertthat::assert_that(is.valid_number(input$page_hgt),
                              msg = paste("'Page height'", error_numeric))
      assertthat::assert_that(is.valid_count(input$numrow),
                              msg = paste("'Number of rows'", "must be a positive integer"))
      assertthat::assert_that(is.valid_count(input$numcol),
                              msg = paste("'Number of columns'", "must be a positive integer"))
      
      shinyjs::runjs("$('a[data-value=\"label_setup\"]').tab('show');")
    },
    warning = function(cond) {
      showModal(modalDialog(title = "Warning",
                            "Warnings were generated. Please double-check the entered
                            values and try again."))
    },
    error = function(cond) {
      showModal(modalDialog(title = "Error",
                            paste("The following error was generated:",
                                  cond$message, "Rectify before proceeding.")))
    })
    
  })
  
  # Event to navigate from label setup tab to generate labels tab
  
  observeEvent(input$npg5, {
    tryCatch({
      assertthat::assert_that(is.valid_number(input$wdt),
                              msg = paste("'Label width'", error_numeric))
      assertthat::assert_that(is.valid_number(input$hgt),
                              msg = paste("'Label height'", error_numeric))
      assertthat::assert_that(is.valid_number(input$font_size),
                              msg = paste("'Font size'", error_numeric))
      assertthat::assert_that(is.valid_count(input$lab_sel),
                              msg = paste("'Label to preview'", "must be a positive integer"))
      shinyjs::runjs("$('a[data-value=\"generate_labels\"]').tab('show');")
      
    },
    warning = function(cond) {
      showModal(modalDialog(title = "Warning",
                            "Warnings were generated. Please double-check the entered
                            values and try again."))
    },
    error = function(cond) {
      showModal(modalDialog(title = "Error",
                            paste("The following error was generated:",
                                  cond$message, "Rectify before proceeding.")))
    })
  })
  
  #+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++#
  #                         Section 1. Global variables                                     #
  #+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++#
  dat <- c()
  dat_columns <- c()
  pdf_filename <- c()
  ext <- c()
  updated_fieldbook_filename <- c()
  
  
  #+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++#
  #                       Section 2. ObserveEvent() Expressions                             #
  #+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++#
  ## Triggered on clicking the 'Upload Fieldbook' button
  observeEvent(input$datUploader, {
    
    # Set 'Generated with FieldHub' switch to false on file upload
    shinyWidgets::updatePrettySwitch(inputId = "from_fieldhub", value = FALSE)
    #shinyWidgets::updatePrettySwitch(inputId = "from_BMS", value = FALSE)
    
    tryCatch({
      dat <<- input$datUploader
      ext <<- tools::file_ext(dat$datapath)
      req(dat)
      
      if (ext == "xls" || ext == "xlsx") {
        dat <<- as.data.frame(readxl::read_excel(dat$datapath))
      } else {
        
        # Read the submitted fieldbook into the global 'dat' variable
        dat <<- read.csv(dat$datapath, header = TRUE) }
      
      # Update input widgets with column names obtained from the data
      dat_columns <<- colnames(dat)
      
      if(input$from_fieldhub == TRUE) {
        autoset_fieldhub()
      } else if(input$from_fieldhub == FALSE) {
        init_label_info()
        
      }
      
      # Enable the initially disabled Preview fieldbook and Generated with FieldHub
      # and BMS switches and submit data action button
      # shinyjs::enable(id = "preview_dat")
      shinyjs::enable(id = "from_fieldhub")
      # shinyjs::enable(id = "from_BMS")
      shinyjs::enable(id = "submit_dat")
      
    },
    warning = function(cond) {
      showModal(modalDialog(title = "Warning",
                            "Warnings were generated. Please double-check the submitted
                            file and try again."))
    },
    error = function(cond) {
      showModal(modalDialog(title = "Error",
                            "An error occurred. Please check to see whether the submitted
                            file is of the accepted type CSV (Comma-Separated Values), XLS,
                            or XLSX.
                            Also confirm if the uploaded fieldbook was generated with
                            FieldHub. Either turn off the 'Generated with FieldHub' switch
                            from the Data import page."))
    })
  })
  
  
  # BrAPI BMS codes
  
  observeEvent(input$brapi_login,{
    
    # Show the spinning animation
    shinyjs::addClass(id = "Animate", class = "fas fa-spinner fa-spin")
    
    tryCatch({
      
      if (input$brapi == TRUE) {
        
        if (input$brapi_engine == "bms") {
          
          # config your BMS connection (by providing your BMS login page URL)
          QBMS::set_qbms_config(input$login_lk, 
                                time_out = 300,
                                no_auth = input$no_auth,
                                engine = "bms")
          
          # login using your BMS account (interactive mode)
          # or pass your BMS username and password as parameters (batch mode)
          QBMS::login_bms(username = input$user_name, password = input$pwd)
          
        } else {
          
          # config your BMS connection (by providing your breedbase login page URL)
          QBMS::set_qbms_config(input$login_lk, 
                                time_out = 300, 
                                no_auth = input$no_auth,
                                engine = "breedbase")
          
        }
        
        
        # list supported crops in the current bms server
        crops <- QBMS::list_crops() # character vector
        
        # Update widget for BMS crops
        updateSelectInput(inputId = "brapi_crops", choices = c(crops))
      }
    },
    
    warning = function(cond) {
      showModal(modalDialog(title = "Warning",
                            paste("Warnings were generated:", cond$message)))
    },
    
    error = function(cond) {
      showModal(modalDialog(title = "Error",
                            paste("The following error was generated:", cond$message)))
    })
    
    # stop the spinning animation
    shinyjs::removeClass(id = "Animate", class = "fas fa-spinner fa-spin")
    
  })
  
  
  # GET programs 
  observeEvent(input$GET1,{
    
    # Show the spinning animation
    shinyjs::addClass(id = "Animate", class = "fas fa-spinner fa-spin")
    
    tryCatch({
      
      if (input$brapi_crops != "none") {
        QBMS::set_crop(input$brapi_crops)
        
        # list all breeding programs in the selected crop
        prg <- QBMS::list_programs() # data frame
        prg <- prg[,1]
        
        # Update widget for BMS programs
        updateSelectInput(inputId = "brapi_prgs", choices = c(prg))
      }
      
    },
    
    warning = function(cond) {
      showModal(modalDialog(title = "Warning",
                            paste("Warnings were generated:", cond$message)))
    }, 
    
    error = function(cond) {
      showModal(modalDialog(title = "Error",
                            paste("The following error was generated:", cond$message)))
    })
    
    # stop the spinning animation
    shinyjs::removeClass(id = "Animate", class = "fas fa-spinner fa-spin")
    
  })
  
  
  # GET trials
  observeEvent(input$GET2,{
    # Show the spinning animation
    shinyjs::addClass(id = "Animate", class = "fas fa-spinner fa-spin")
    
    tryCatch({
      
      if (input$brapi_prgs != "none") {
        QBMS::set_program(input$brapi_prgs) 
        # list all studies/trials in the selected program
        trials <- QBMS::list_trials() # data frame
        trials <- trials[,1] # Convert to a character vector
        # Update widget for BMS programs
        updateSelectInput(inputId = "brapi_trials", choices = c(trials))
      }
    },
    
    warning = function(cond) {
      showModal(modalDialog(title = "Warning",
                            paste("Warnings were generated:", cond$message)))
    }, 
    
    error = function(cond) {
      showModal(modalDialog(title = "Error",
                            paste("The following error was generated:", cond$message)))
    })
    
    # stop the spinning animation
    shinyjs::removeClass(id = "Animate", class = "fas fa-spinner fa-spin")
    
  })
  
  
  # GET studies
  observeEvent(input$GET3,{
    
    # Show the spinning animation
    shinyjs::addClass(id = "Animate", class = "fas fa-spinner fa-spin")
    
    tryCatch({
      
      if (input$brapi_trials != "none") {
        
        # select a specific study/trial by name
        QBMS::set_trial(input$brapi_trials)
        
        # list all environments/locations information in the selected study/trial
        studies <- QBMS::list_studies()
        
        studies <- studies[1:nrow(studies), 1] # Convert studies to a character vector
        
        updateSelectInput(inputId = "brapi_studies", choices = c(studies))
      }
    },
    
    warning = function(cond) {
      showModal(modalDialog(title = "Warning",
                            paste("Warnings were generated:", cond$message)))
    }, 
    
    error = function(cond) {
      showModal(modalDialog(title = "Error",
                            paste("The following error was generated:", cond$message)))  
    })
    
    # stop the spinning animation
    shinyjs::removeClass(id = "Animate", class = "fas fa-spinner fa-spin")
    
  })
  
  # GET data
  observeEvent(input$GET4,{
    
    # Show the spinning animation
    shinyjs::addClass(id = "Animate", class = "fas fa-spinner fa-spin")
    
    shinyjs::enable(id = "submit_dat")
    tryCatch({
      if (input$brapi_studies != "none") {
        QBMS::set_study(input$brapi_studies)
        
        dat <<- QBMS::get_study_data()
        dat <<- dat
        # Update input widgets with column names obtained from the data
        dat_columns <<- colnames(dat)
        init_label_info()
      }
    },
    
    warning = function(cond) {
      showModal(modalDialog(title = "Warning",
                            paste("Warnings were generated:", cond$message)))
    }, 
    
    error = function(cond) {
      showModal(modalDialog(title = "Error",
                            paste("The following error was generated:", cond$message))) 
    })
    
    # stop the spinning animation
    shinyjs::removeClass(id = "Animate", class = "fas fa-spinner fa-spin")
    
  })
  
  
  
  # Update year input widgets with current year; user can input year manually
  yrs <- format(Sys.time(),'%Y')
  updateTextInput(inputId = "yr", value = yrs)
  
  
  ## Triggered on clicking the 'Submit Fieldbook' button
  observeEvent(input$submit_dat,{
    
    # Reactivate GR code and error correction level buttons
    shinyjs::enable(id = "gen_qrcode")
    shinyjs::enable(id = "ec_level")
    
    # Displays the imported fieldbook
    output$imported_fieldbook <- reactable::renderReactable({
      tryCatch({
        reactable::reactable(data.frame(dat), fullWidth = TRUE, defaultPageSize = 10, columns = NULL,
                             bordered = TRUE, highlight = TRUE, resizable = TRUE)
      },
      warning = function(cond) {
        showModal(modalDialog(title = "Warning",
                              "Warnings. Please double-check entered values in order to
                            produce the expected results."))
      },
      error = function(cond) {
        showModal(modalDialog(title = "Error",
                              "An error occurred. Double-check the submitted file to be
                                sure it is of the correct format. The app expects a CSV,
                                XLS, or XLSX file containing rows and columns. Column
                                headers are required and must be present to produce the
                                desired output.
                                "))
      })
    })
  })
  
  # Hide and show BrAPI widgets
  observe({
    
    if (input$brapi == FALSE) {
      
      shinyjs::hide(id = "brapi_inputs")
      shinyjs::enable(id = "from_local")
      
    } else {
      
      shinyjs::show(id = "brapi_inputs")
      shinyjs::disable(id = "from_local")
    }
    
  })
  
  observe({
    
    if (input$from_local == FALSE) {
      
      shinyjs::hide(id = "local_source")
      shinyjs::enable(id = "brapi")
      
    } else {
      
      shinyjs::show(id = "local_source")
      shinyjs::disable(id = "brapi")
    }
  })
  
  
  observe({
    
    if (input$no_auth == TRUE) {
      
      shinyjs::disable(id = "pwd")
      shinyjs::disable(id = "user_name")
      
      
      
    } else {
      
      shinyjs::enable(id = "pwd")
      shinyjs::enable(id = "user_name")
      
    }
  })
  
  ## Triggered on clicking the 'Generate labels' button
  observeEvent(input$gen_labels, {
    
    # Show the spinning animation
    shinyjs::addClass(id = "UpdateAnimate", class = "fas fa-spinner fa-spin")
    
    # Disable the buttons so the user does not click them in the middle of processing
    shinyjs::disable(id = "gen_labels")
    shinyjs::disable(id = "down_fieldbook")
    shinyjs::disable(id = "down_labels")
    
    
    tryCatch({
      if (input$label_type == "field" || input$label_type == "gp") {
        reactive_create_label <- reactive(create_label())
        reactive_create_label()
        
      } else if (input$label_type == "gpp") {
        
        reactive_gp_label_portrait <- reactive(gp_label_portrait())
        reactive_gp_label_portrait()
        
      }
    },
    warning = function(cond) {
      showModal(modalDialog(title = "Warning",
                            "Warnings. Please double-check entered values in order to
                            produce the expected results."))
    },
    error = function(cond) {
      showModal(modalDialog(title = "Error",
                            "An error occurred. Please check to see if all requirements
                            have been met."))
    },
    finally = {
      # In case the label generation fails, reset the button for the user to retry
      shinyjs::enable(id = "gen_labels")
      shinyjs::removeClass(id = "UpdateAnimate", class = "fas fa-spinner fa-spin")
    })
    
    # Reset the button after successful label generation
    shinyjs::enable(id = "gen_labels")
    shinyjs::removeClass(id = "UpdateAnimate", class = "fas fa-spinner fa-spin")
  })
  
  
  
  #+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++#
  #                 Section 3. Observe() Expressions and Downloaders                        #
  #+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++#
  
  ## Input widget controls if type of label = field plot labels
  observe({
    if (input$label_type == "field"){
      
      shinyjs::show(id = "IBlock")
      shinyjs::show(id = "uniqueids")
      shinyjs::show(id = "seed_source")
      shinyjs::show(id = "rname")
      shinyjs::show(id = "plot_id")
      shinyjs::show(id = "rep_id")
      shinyjs::show(id = "row_id")
      shinyjs::show(id = "col_id")
      shinyjs::show(id = "entry_id")
      shinyjs::show(id = "loc_id")
      
      
      ## Hide the input widget for IBlock if the respective checkbox is set to false  
      if (input$IBlock == FALSE ) {
        shinyjs::hide(id = "IBlock_id")
      } else {
        shinyjs::show(id = "IBlock_id")
      }
      
      # Show the input widget for setting the Unique ID 
      if (input$uniqueids == "use_my_ids") {
        shinyjs::show(id = "unique_id")
      } else {
        shinyjs::hide(id = "unique_id")
      }  
      
      # Show the input widget for trial name and year of experiment
      if (input$uniqueids == "uuids" | input$uniqueids == "use_my_ids") {
        shinyjs::hide(id = "tname")
        shinyjs::hide(id = "yr")
      } else if (input$uniqueids == "get_unique_id") {
        shinyjs::show(id = "tname")
        shinyjs::show(id = "yr")
      }
      
      ## Show the input widget for setting seed source if the respective checkbox is true
      if(input$seed_source == FALSE) {
        shinyjs::hide(id = "seed")
        
      } else {
        shinyjs::show(id = "seed")
      }
      # Hide all widgets for general purpose labels -- landscape
      shinyjs::hide(id = "QRcode_id")
      shinyjs::hide(id = "toplt")
      shinyjs::hide(id = "toprt")
      shinyjs::hide(id = "centrt")
      shinyjs::hide(id = "botlt")
      
      shinyjs::hide(id = "QRcode_id2")
      shinyjs::hide(id = "toptxt")
      shinyjs::hide(id = "centtxt")
      shinyjs::hide(id = "bottxt")
      
      
    } else {
      shinyjs::hide(id = "tname")
      shinyjs::hide(id = "yr")
      
    }
  })
  
  
  # Hide all widgets for field plot labels and gp portrait if label type is 
  # gp landscape
  observe({
    if (input$label_type == "gp") {
      
      shinyjs::show(id = "toplt")
      shinyjs::show(id = "toprt")
      shinyjs::show(id = "centrt")
      shinyjs::show(id = "botlt")
      
      # Hide widgets for field plot labels
      shinyjs::hide(id = "IBlock")
      # shinyjs::hide(id = "uniqueids")
      shinyjs::hide(id = "seed_source")
      shinyjs::hide(id = "seed")
      shinyjs::hide(id = "IBlock_id")
      shinyjs::hide(id = "rname")
      shinyjs::hide(id = "plot_id")
      shinyjs::hide(id = "rep_id")
      shinyjs::hide(id = "row_id")
      shinyjs::hide(id = "col_id")
      shinyjs::hide(id = "entry_id")
      shinyjs::hide(id = "loc_id")
      shinyjs::hide(id = "unique_id")
      
      shinyjs::hide(id = "QRcode_id2")
      shinyjs::hide(id = "toptxt")
      shinyjs::hide(id = "centtxt")
      shinyjs::hide(id = "bottxt")
      
      
      
      # Show the input widget for setting the QRcode ID for gp
      if (input$uniqueids == "use_my_ids") {
        shinyjs::show(id = "QRcode_id")
        
      } else {
        shinyjs::hide(id = "QRcode_id")
      }  
      
    } 
    
  })
  
  
  # Hide all widgets for gp portrait if label type is gp landscape 
  observe({
    if (input$label_type == "gpp") {
      
      shinyjs::show(id = "QRcode_id2")
      shinyjs::show(id = "toptxt")
      shinyjs::show(id = "centtxt")
      shinyjs::show(id = "bottxt")
      
      # Hide widgets for field plot labels
      shinyjs::hide(id = "IBlock")
      shinyjs::hide(id = "seed_source")
      shinyjs::hide(id = "seed")
      shinyjs::hide(id = "IBlock_id")
      shinyjs::hide(id = "rname")
      shinyjs::hide(id = "plot_id")
      shinyjs::hide(id = "rep_id")
      shinyjs::hide(id = "row_id")
      shinyjs::hide(id = "col_id")
      shinyjs::hide(id = "entry_id")
      shinyjs::hide(id = "loc_id")
      shinyjs::hide(id = "unique_id")
      
      
      shinyjs::hide(id = "QRcode_id")
      shinyjs::hide(id = "toplt")
      shinyjs::hide(id = "toprt")
      shinyjs::hide(id = "centrt")
      shinyjs::hide(id = "botlt")
      
    } else {
      
    }
    
  })
  
  
  
  
  ## Downloads generated labels
  output$down_labels <- downloadHandler(
    filename = function() {
      paste(basename(pdf_filename))
    },
    content = function(file) {
      file.copy(pdf_filename, file)
    }
  )
  
  ## Downloads updated Fieldbook with unique IDs
  output$down_fieldbook <- downloadHandler(
    filename = function() {
      paste(basename(updated_fieldbook_filename))
    },
    content = function(file) {
        target_dir = tempdir()
        file.copy(updated_fieldbook_filename, file)
    }
  )
  
  ## Show or hide the imported Fieldbook according to the state of the switch
  # observe({
  #   if (input$preview_dat == TRUE) {
  #     shinyjs::show(id = "fieldbookcard")
  #   } else {
  #     shinyjs::hideElement(id = "fieldbookcard")
  #   }
  # })
  
  # Create reactive object for common labels
  cls <- reactive({
    read.csv("data/common_labels.csv", header = TRUE,
             colClasses = c(rep("character",2), rep("numeric", 9), "logical"))
  })
  
  ## Load and render common labels in a table
  observe({
    output$common_labels <- reactable::renderReactable({
      isolate({reactable::reactable(cls(), fullWidth = TRUE, defaultPageSize = 15,
                                    bordered = TRUE, highlight = TRUE, resizable = TRUE)
      })
    })
  })
  
  # Update page and label setup inputs when label templates are selected
  observeEvent(input$templates,{
    
    clabs <- cls()
    
    updateNumericInput(session, inputId = "wdt",
                       value = clabs$Lab.W.in[clabs$Template == input$templates])
    
    updateNumericInput(session, inputId = "hgt",
                       value = clabs$Lab.H.in[clabs$Template == input$templates])
    
    updateNumericInput(session, inputId = "page_wdt",
                       value = clabs$pg.W.in[clabs$Template == input$templates])
    
    updateNumericInput(session, inputId = "page_hgt",
                       value = clabs$pg.H.in[clabs$Template == input$templates])
    
    
    updateNumericInput(session, inputId = "numrow",
                       value = clabs$nRows.pg[clabs$Template == input$templates])
    
    updateNumericInput(session, inputId = "numcol",
                       value = clabs$nColumns.pg[clabs$Template == input$templates])
    
    updateNumericInput(session, inputId = "top_mar",
                       value = clabs$Height.margin.in[clabs$Template == input$templates])
    
    updateNumericInput(session, inputId = "bot_mar",
                       value = clabs$Height.margin.in[clabs$Template == input$templates])
    
    updateNumericInput(session, inputId = "left_mar",
                       value = clabs$Width.margin.in[clabs$Template == input$templates])
    
    updateNumericInput(session, inputId = "right_mar",
                       value = clabs$Width.margin.in[clabs$Template == input$templates])
    
    shinyWidgets::updatePrettyCheckbox(session, inputId = "rounded",
                                       value = clabs$Rounded[clabs$Template == input$templates])
    
  })
  
  # Auto fill Label information tab with column names if field book was generated
  # using FieldHub or BMS
  observe({
    tryCatch({
      
      # If the user confirms the submitted Fieldbook was generated using FieldHub,
      # set the selectInputs to the right IDs automatically
      # Otherwise, update input widgets with column names obtained from the data
      if(input$from_fieldhub == TRUE ){
        autoset_fieldhub()
        
        # }else if(input$from_BMS == TRUE){
        #   autoset_BMS()
        
      } else {
        init_label_info()
        
      }
      
      
    },
    warning = function(cond) {
      showModal(modalDialog(title = "Warning",
                            "Warnings. Please double-check entered values in order to
                            produce the expected results."))
    },
    error = function(cond) {
      showModal(modalDialog(title = "Error",
                            "An error occurred. Please confirm if the uploaded fieldbook
                            was generated with FieldHub. Either turn off the 'Generated
                            with FieldHub' switch from the Data import page."))
    })
  })
  
  # Update numeric input widget for label preview; observed only when the submitted data
  # action button is clicked
  observe({
    req(input$submit_dat)
    updateNumericInput(session, inputId = "lab_sel", value = 1, step = 1,
                       min = 1, max = nrow(dat))
  })
  
  
  
  
  #+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++#
  #                   Section 4. Regular functions (the "workhorses")                       #
  #+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++#
  
  # Used in assertion to check for positive numbers
  is.valid_number <- function (x) {
    if (x >= 0 && assertthat::is.number(x)) return (TRUE) else return (FALSE)
  }
  
  # Used in assertions to check if number is an integer and positive
  is.valid_count <- function (x) {
    if (x > 0 && assertthat::is.count(x)) return (TRUE) else return (FALSE)
  }
  
  # Initialize label info
  init_label_info <- function() {
    updateSelectInput(inputId = "rep_id", choices = c("none", dat_columns))
    updateSelectInput(inputId = "row_id", choices = c("none", dat_columns))
    updateSelectInput(inputId = "loc_id", choices = c("none", dat_columns))
    updateSelectInput(inputId = "IBlock_id", choices = c("none", dat_columns))
    updateSelectInput(inputId = "plot_id", choices = c("none", dat_columns))
    updateSelectInput(inputId = "col_id", choices = c("none", dat_columns))
    updateSelectInput(inputId = "entry_id", choices = c("none", dat_columns))
    updateSelectInput(inputId = "unique_id", choices = c("none", dat_columns))
    updateSelectInput(inputId = "seed", choices = c("none", dat_columns))
    
    # Update select inputs for general purpose landscape labels
    updateSelectInput(inputId = "toplt_sel_r1", choices = c("none", dat_columns), selected = "none")
    updateSelectInput(inputId = "toplt_sel_r2", choices = c("none", dat_columns), selected = "none")
    updateSelectInput(inputId = "toprt_sel_r1", choices = c("none", dat_columns), selected = "none")
    updateSelectInput(inputId = "toprt_sel_r2", choices = c("none", dat_columns), selected = "none")
    updateSelectInput(inputId = "centrt_sel_r1", choices = c("none", dat_columns), selected = "none")
    updateSelectInput(inputId = "centrt_sel_r2", choices = c("none", dat_columns), selected = "none")
    updateSelectInput(inputId = "centrt_sel_r3", choices = c("none", dat_columns), selected = "none")
    updateSelectInput(inputId = "botlt_sel_r1", choices = c("none", dat_columns), selected = "none")
    updateSelectInput(inputId = "botlt_sel_r2", choices = c("none", dat_columns), selected = "none")
    shinyWidgets::updatePickerInput(session, inputId = "QRcode_id", choices = c("none", dat_columns), selected = "none")
    
    # Update select inputs for general purpose portrait labels
    updateSelectInput(inputId = "top_sel1", choices = c("none", dat_columns), selected = "none")
    updateSelectInput(inputId = "top_sel2", choices = c("none", dat_columns), selected = "none")
    updateSelectInput(inputId = "top_sel3", choices = c("none", dat_columns), selected = "none")
    updateSelectInput(inputId = "cent_sel1", choices = c("none", dat_columns), selected = "none")
    updateSelectInput(inputId = "cent_sel2", choices = c("none", dat_columns), selected = "none")
    updateSelectInput(inputId = "cent_sel3", choices = c("none", dat_columns), selected = "none")
    updateSelectInput(inputId = "cent_sel4", choices = c("none", dat_columns), selected = "none")
    updateSelectInput(inputId = "bot_sel1", choices = c("none", dat_columns), selected = "none")
    updateSelectInput(inputId = "bot_sel2", choices = c("none", dat_columns), selected = "none")
    updateSelectInput(inputId = "bot_sel3", choices = c("none", dat_columns), selected = "none")
    shinyWidgets::updatePickerInput(session, inputId = "QRcode_id2", choices = c("none", dat_columns), selected = "none")
    
  }
  
  
  
  
  # Invoked to automatically set the respective input widgets if a FieldHub-generated
  # fieldbook is uploaded
  autoset_fieldhub <- function() {
    updateSelectInput(inputId = "rep_id", choices = c("none", dat_columns), selected = "REP")
    updateSelectInput(inputId = "row_id", choices = c("none", dat_columns), selected = "ROW")
    updateSelectInput(inputId = "loc_id", choices = c("none", dat_columns), selected = "LOCATION")
    updateSelectInput(inputId = "IBlock_id", choices = c("none", dat_columns), selected = "IBLOCK")
    updateSelectInput(inputId = "plot_id", choices = c("none", dat_columns), selected = "PLOT")
    updateSelectInput(inputId = "col_id", choices = c("none", dat_columns), selected = "COLUMN")
    updateSelectInput(inputId = "entry_id", choices = c("none", dat_columns), selected = "TREATMENT")
  }
  
  autoset_BMS <- function() {
    if(ext == "xls" | ext == "xlsx" ){
      updateSelectInput(inputId = "rep_id", choices = c("none", dat_columns), selected = "REP_NO")
      updateSelectInput(inputId = "row_id", choices = c("none", dat_columns), selected = "FIELDMAP RANGE")
      updateSelectInput(inputId = "loc_id", choices = c("none", dat_columns), selected = "LOCATION_NAME")
      updateSelectInput(inputId = "IBlock_id", choices = c("none", dat_columns), selected = "BLOCK_NO")
      updateSelectInput(inputId = "plot_id", choices = c("none", dat_columns), selected = "PLOT_NO")
      updateSelectInput(inputId = "col_id", choices = c("none", dat_columns), selected = "FIELDMAP COLUMN")
      updateSelectInput(inputId = "entry_id", choices = c("none", dat_columns), selected = "DESIGNATION")
    } else {
      updateSelectInput(inputId = "rep_id", choices = c("none", dat_columns), selected = "REP_NO")
      updateSelectInput(inputId = "row_id", choices = c("none", dat_columns), selected = "FIELDMAP.RANGE")
      updateSelectInput(inputId = "loc_id", choices = c("none", dat_columns), selected = "LOCATION_NAME")
      updateSelectInput(inputId = "IBlock_id", choices = c("none", dat_columns), selected = "BLOCK_NO")
      updateSelectInput(inputId = "plot_id", choices = c("none", dat_columns), selected = "PLOT_NO")
      updateSelectInput(inputId = "col_id", choices = c("none", dat_columns), selected = "FIELDMAP.COLUMN")
      updateSelectInput(inputId = "entry_id", choices = c("none", dat_columns), selected = "DESIGNATION")
      
    }
    
  }
  
  # Update picker input for label unique ID generation method when
  # depending on the method selected for label generation
  observe({
    if (input$label_type == "gp"){
      
      shinyWidgets::updatePickerInput(session, inputId = "uniqueids", 
                                      label = "Select method for unique IDs",
                                      choices = c("Universal Unique IDs" = "uuids", 
                                                  "Custom Unique IDs" = "use_my_ids"))
      
    } else if (input$label_type == "field") {
      shinyWidgets::updatePickerInput(session, inputId = "uniqueids", 
                                      label = "Select method for unique IDs",
                                      choices = c("Reproducible Unique IDs" = "get_unique_id",
                                                  "Universal Unique IDs" = "uuids", 
                                                  "Custom Unique IDs" = "use_my_ids"))
    }
  })
  
  # Update picker input for label unique ID generation method when
  # depending on the method selected for label generation
  observe({
    if (input$label_type == "gpp"){
      
      shinyWidgets::updatePickerInput(session, inputId = "uniqueids", 
                                      label = "Select method for unique IDs",
                                      choices = c("Custom Unique IDs" = "use_my_ids"))
      
    } else if (input$label_type == "field") {
      shinyWidgets::updatePickerInput(session, inputId = "uniqueids", 
                                      label = "Select method for unique IDs",
                                      choices = c("Reproducible Unique IDs" = "get_unique_id",
                                                  "Universal Unique IDs" = "uuids", 
                                                  "Custom Unique IDs" = "use_my_ids"))
    }
  })
  
  
  # Update picker input for label templates depending on the method selected 
  # for label generation
  observe({
    if (input$label_type == "gpp"){
      
      shinyWidgets::updatePickerInput(session, inputId = "templates", label = "Select a desired template",
                                      choices = c("Custom","Avery 94220", "Avery 94200", "Avery 94224",
                                                  "Avery 94237", "Avery 94207", "Avery 94241",
                                                  "Avery 94213", "Avery 94242", "OnlineLabel OL5125",
                                                  "OnlineLabel RL778", "OnlineLabel RL2800",
                                                  "OnlineLabel RL782"),
                                      selected = "Avery 94220",
                                      options = list(style = "btn-primary"))
      
      
    } else {
      shinyWidgets::updatePickerInput(session, inputId = "templates", label = "Select a desired template",
                                      choices = c("Custom","Avery 94220", "Avery 94200", "Avery 94224",
                                                  "Avery 94237", "Avery 94207", "Avery 94241",
                                                  "Avery 94213", "Avery 94242", "OnlineLabel OL5125",
                                                  "OnlineLabel RL778", "OnlineLabel RL2800",
                                                  "OnlineLabel RL782", "Treetag LTS14"),
                                      selected = "Avery 94220",
                                      options = list(style = "btn-primary"))
    }
  })
  
  
  ## Create an augmented fieldbook containing unique IDs
  create_aug_fieldbook <- function(target_dir) {
    
    if (input$uniqueids == "get_unique_id" | input$uniqueids == "uuids") {
      
      updat <- dplyr::mutate(dat, UNIQUE_ID())
      colnames(updat)[ncol(updat)] <- 'UNIQUE_ID'
    } else {
      updat <- dat
    }
    
    if (colnames(updat)[1] == 'ID') {
      colnames(updat)[1] <- 'SN'
    } else {
      colnames(updat)[1] <- colnames(updat)[1] 
    }
    
    updated_fieldbook_filename <<- file.path(target_dir, "Updated_Fieldbook.csv")
    write.csv(updat, file = updated_fieldbook_filename, row.names = FALSE)
  }
  
  ## Function make QR codes as raster object
  ## Input file is the unique id created for each label
  #' New wrapper function for QR code generation -- 10x faster using the qrencode
  #' library
  #' @param my_id unique ID string to be encoded to QR code
  #' @param ec_level error correction level (`0` - `3`, lowest to highest)
  make_qrcode <- function(my_id, ec_level = input$ec_level){
    
    # Create qrcode and store as a rasterGrob image
    
    aa <- raster::raster(qrencoder::qrencode_raw(as.character(my_id), ec_level))
    qr <- grid::rasterGrob(raster::as.raster(aa, col = c('white','black')),
                           interpolate = FALSE)
    
    return(qr)
  }
  
  # Create reactive objects for plot, rep, row, column, loc and entry
  
  
  lab_inf <- reactive({
    
    if (input$label_type == "field") {
      #req(input$label_type == "field")
      
      if (input$plot_id != "none") {
        plott <- paste("Plot ID:", dat[, input$plot_id]) # Plot ids
      } else (plott <- NULL)
      
      if (input$rep_id != "none") {
        repp <- paste("Rep ID:", dat[, input$rep_id]) # Rep ids
      } else (repp <- NULL)
      
      if (input$loc_id != "none") {
        loc <- paste("Loc:", dat[, input$loc_id]) # Location ids
      } else (loc <- NULL)
      
      if (input$row_id != "none") {
        roww <- paste("Row ID:", dat[, input$row_id]) # Row ids
      } else (roww <- NULL)
      
      if (input$col_id != "none") {
        coll <- paste("Col. ID:", dat[, input$col_id]) # Column ids
      } else (coll <- NULL)
      
      if (input$entry_id != "none") {
        entry <-  dat[, input$entry_id]
      } else (entry <- NULL)
      
      rnames <- rep(input$rname, nrow(dat)) # Researcher's name
      
      #' Block ids if it is an incomplete block design
      
      if (input$IBlock == TRUE) {
        
        if (input$IBlock_id != "none") {
          iblock <- paste("B:", dat[, input$IBlock_id])
          
        } else (iblock <- NULL)
        
      } else (iblock <- NULL)
      
      
      if(input$seed_source == TRUE) {
        
        if (input$seed != "none") {
          
          
          sdsource  <- paste(dat[, input$seed])
          
        } else (sdsource  <- NULL)
        
      } else (sdsource  <- NULL)
      
      # Combine all results as a list for field plot labels
      fld_all <- list(plott, roww, repp, coll, iblock, sdsource, rnames, loc, entry)
      
    } else if (input$label_type == "gp") {
      #req(input$label_type == "gp")
      
      if (input$toplt_sel_r1 != "none") {
        tp_lt_r1 <- paste(input$toplt_txt_r1, dat[, input$toplt_sel_r1]) # top left position row 1
      } else {
        tp_lt_r1 <- rep(input$toplt_txt_r1, nrow(dat))
      }
      
      if (input$toplt_sel_r2 != "none") {
        tp_lt_r2 <- paste(input$toplt_txt_r2, dat[, input$toplt_sel_r2]) # top left position row 2
      } else {
        tp_lt_r2 <- rep(input$toplt_txt_r2, nrow(dat))
      }
      
      if (input$toprt_sel_r1 != "none") {
        tp_rt_r1 <- paste(input$toprt_txt_r1, dat[, input$toprt_sel_r1]) # top right position row 1
      } else {
        tp_rt_r1 <- rep(input$toprt_txt_r1, nrow(dat))
      }
      
      if (input$toprt_sel_r2 != "none") {
        tp_rt_r2 <- paste(input$toprt_txt_r2, dat[, input$toprt_sel_r2]) # top right position row 2
      } else {
        tp_rt_r2 <- rep(input$toprt_txt_r2, nrow(dat))
      }
      
      if (input$centrt_sel_r1 != "none") {
        ct_rt_r1 <- paste(input$centrt_txt_r1, dat[, input$centrt_sel_r1]) # center right position row 1
      } else {
        ct_rt_r1 <- rep(input$centrt_txt_r1, nrow(dat))
      }
      
      if (input$centrt_sel_r2 != "none") {
        ct_rt_r2 <- paste(input$centrt_txt_r2, dat[, input$centrt_sel_r2]) # center right position row 2
      } else {
        ct_rt_r2 <- rep(input$centrt_txt_r2, nrow(dat))
      }
      
      if (input$centrt_sel_r3 != "none"){
        ct_rt_r3 <- paste(input$centrt_txt_r3, dat[, input$centrt_sel_r3]) # center right position row 1
      } else {
        ct_rt_r3 <- rep(input$centrt_txt_r3, nrow(dat))
      }
      
      if (input$botlt_sel_r1 != "none"){
        bt_lt_r1 <- paste(input$botlt_txt_r1, dat[, input$botlt_sel_r1]) # bottom left position row 1
      } else {
        bt_lt_r1 <- rep(input$botlt_txt_r1, nrow(dat))
      }
      
      if (input$botlt_sel_r2 != "none"){
        bt_lt_r2 <- paste(input$botlt_txt_r2, dat[, input$botlt_sel_r2]) # bottom left position row 2
        
      } else {
        bt_lt_r2 <- rep(input$botlt_txt_r2, nrow(dat))
      }
      
      # Combine all results as a list for general purpose plot labels
      fld_all <- list(tp_lt_r1, tp_lt_r2, tp_rt_r1, tp_rt_r2, ct_rt_r1, ct_rt_r2,
                      ct_rt_r3, bt_lt_r1, bt_lt_r2)
      
    } else if (input$label_type == "gpp") {
      
      if (input$bot_sel1 != "none") {
        text1 <- paste(input$bot_txt1, dat[, input$bot_sel1]) # bot position row 1
      } else {
        text1 <- rep(input$bot_txt1, nrow(dat))
      }
      
      if (input$bot_sel2 != "none") {
        text2 <- paste(input$bot_txt2, dat[, input$bot_sel2]) # bot position row 2
      } else {
        text2 <- rep(input$bot_txt2, nrow(dat))
      }
      
      if (input$bot_sel3 != "none") {
        text3 <- paste(input$bot_txt3, dat[, input$bot_sel3]) # bot position row 3
      } else {
        text3 <- rep(input$bot_txt3, nrow(dat))
      }
      
      if (input$cent_sel1 != "none") {
        text4 <- paste(input$cent_txt1, dat[, input$cent_sel1]) # center position row 1
      } else {
        text4 <- rep(input$cent_txt1, nrow(dat))
      }
      
      if (input$cent_sel2 != "none") {
        text5 <- paste(input$cent_txt2, dat[, input$cent_sel2]) # center position row 2
      } else {
        text5 <- rep(input$cent_txt2, nrow(dat))
      }
      
      if (input$cent_sel3 != "none") {
        text6 <- paste(input$cent_txt3, dat[, input$cent_sel3]) # center position row 3
      } else {
        text6 <- rep(input$cent_txt3, nrow(dat))
      }
      
      if (input$cent_sel4 != "none") {
        text7 <- paste(input$cent_txt4, dat[, input$cent_sel4]) # center position row 4
      } else {
        text7 <- rep(input$cent_txt4, nrow(dat))
      }
      
      if (input$top_sel1 != "none") {
        text8 <- paste(input$top_txt1, dat[, input$top_sel1]) # top position row 1
      } else {
        text8 <- rep(input$top_txt1, nrow(dat))
      }
      
      if (input$top_sel2 != "none") {
        text9 <- paste(input$top_txt2, dat[, input$top_sel2]) # top position row 2
      } else {
        text9 <- rep(input$top_txt2, nrow(dat))
      }
      
      if (input$top_sel3 != "none") {
        text10 <- paste(input$top_txt3, dat[, input$top_sel3]) # top position row 3
      } else {
        text10 <- rep(input$top_txt3, nrow(dat))
      }
      
      # Combine all results as a list for general purpose plot labels
      fld_all <- list(text1, text2, text3, text4, text5, text6, text7, text8,
                      text9, text10)
      
    }
    
    fld_all
  })
  
  # Generate unique ids for all plots
  
  UNIQUE_ID <- reactive({
    if (input$label_type == "field") {
      if (input$uniqueids == "get_unique_id") {
        
        trial_name <- gsub(" ", "_", input$tname)
        
        if (input$loc_id != "none") {
          loc2 <- dat[, input$loc_id]
        } else (loc2 <- rep("none", nrow(dat)))
        
        if (input$plot_id != "none") {
          plott2 <- dat[, input$plot_id]
        } else (plott2 <- rep(0, nrow(dat)))
        
        
        if (input$row_id != "none") {
          rows <- dat[, input$row_id]
        } else (rows <- rep(0, nrow(dat)))
        
        if (input$col_id != "none") {
          cols <- dat[, input$col_id]
        } else (cols <- rep(0, nrow(dat)))
        
        ids <- paste(paste0(gsub(" ", "", loc2), input$yr), trial_name,
                     plott2, rows, cols, sep = "_" )
        
      } else if (input$uniqueids == "uuids") {
        ids <- uuid::UUIDgenerate(use.time = TRUE, n = nrow(dat), output = "string")
        
      } else if (input$uniqueids == "use_my_ids") {
        
        ids <- dat[, input$unique_id]
      }
      
    } else if (input$label_type == "gp") {
      
      if (input$uniqueids == "uuids") {
        ids <- uuid::UUIDgenerate(use.time = TRUE, n = nrow(dat), output = "string")
        
      } else if (input$uniqueids == "use_my_ids") {
        
        
        ids <- dat[, input$QRcode_id]
      }
      
    } else if (input$label_type == "gpp") {
      
      ids <- dat[, input$QRcode_id2]
      
    }
    ids
  })
  
  # Store qr codes as reactive values
  bb <- reactiveValues(bb = NULL)
  
  observeEvent(input$gen_qrcode,{
    
    # Show the spinning animation
    shinyjs::addClass(id = "Animate", class = "fas fa-spinner fa-spin")
    req(UNIQUE_ID())
    
    # Disable the buttons so the user does not click them in the middle of processing
    shinyjs::disable(id = "gen_qrcode")
    
    shinyjs::disable(id = "ec_level")
    
    withProgress(message = paste("Generating", length(UNIQUE_ID()), "QR codes."),
                 detail = 'This may take a while...',
                 value = 0, {
                   
                   
                   bb$bb <- purrr::map(UNIQUE_ID(), make_qrcode, .progress = TRUE)
                   
                 })
    
    
    shinyjs::enable(id = "gen_qrcode")
    shinyjs::enable(id = "ec_level")
    # stop the spinning animation
    shinyjs::removeClass(id = "Animate", class = "fas fa-spinner fa-spin")
    
    # Show a modal on successful generation of QR codes
    showModal(modalDialog(title = "QR codes have been successfully generated!",
                          "Proceed to the 'Template setup' to select a label template or create a
                          custom label.", "When done, click the 'Generate labels' button to design labels.",
                          footer = modalButton("OK"),
                          easyClose = TRUE))
    
    
  })
  
  # Preview labels
  
  observeEvent(input$submit_dat,{
    
    output$preview <- renderPlot({
      
      tryCatch({
        
        # Define new coordinates for QR code
        wdt1 <- 0.5 * input$wdt
        hgt1 <- 0.5 * input$hgt
        
        qry <- hgt1/1.2
        
        bold_font <- grid::gpar(fontface = "bold", fontsize = input$font_size,
                                fontfamily = input$family)
        bold_font2 <- grid::gpar(fontface = "bold", fontsize = input$font_size-2,
                                 fontfamily = input$family)
        plain_font2 <- grid::gpar(fontface = "plain", fontsize = input$font_size-2,
                                  fontfamily = input$family)
        bold_font3 <- grid::gpar(fontface = "bold", fontsize = input$font_size-4,
                                 fontfamily = input$family)
        plain_font3 <- grid::gpar(fontface = "plain", fontsize = input$font_size-4,
                                  fontfamily = input$family)
        plain_font4 <- grid::gpar(fontface = "plain", fontsize = input$font_size-floor(input$font_size/2.5),
                                  fontfamily = input$family)
        bold_font4 <- grid::gpar(fontface = "bold", fontsize = input$font_size-floor(input$font_size/2.5),
                                 fontfamily = input$family)
        
        if (input$label_type == "gp" || input$label_type == "field") {
          if (input$templates == "Treetag LTS14") {
            
            
            tt <- grid::viewport(x = grid::unit(0, "npc"),
                                 y = grid::unit(1, "npc"),
                                 width = grid::unit(input$wdt, "in"),
                                 height = grid::unit(input$hgt, "in"),
                                 just = c('left','top'))
            
            # Viewport for first QR codes
            qq <- grid::viewport(x = grid::unit(0.57, "npc"),
                                 y = grid::unit(0.3, "npc"),
                                 angle = 90,
                                 width = grid::unit(wdt1, "in"),
                                 height = grid::unit(qry, "in"),
                                 just = c('right','center'))
            
            # Viewport for IBlock
            bl <- grid::viewport(x = grid::unit(0.1, "npc"),
                                 y = grid::unit(0.3, "npc"),
                                 angle = 90,
                                 width = grid::unit(0.55*input$wdt, "in"),
                                 height = grid::unit(0.8*hgt1, "in"),
                                 just = "left")
            
            # Viewport for second QR code
            qq2 <- grid::viewport(x = grid::unit(0.5, "npc"),
                                  y = grid::unit(0.9, "npc"),
                                  width = grid::unit(wdt1, "inches"),
                                  height = grid::unit(qry, "inches"),
                                  just = c('center'))
            
            px <- 0.11*input$wdt # x coordinate for plot
            
            py <- 0.05*input$hgt # y coordinate for plot
            
            rx <- 0.27*input$wdt # x coordinate for row
            
            ry <- 0.4*input$hgt # y coordinate for Rep
            
            lx <- 0.9*input$wdt # x coordinate for location
            
            ly <- 0.4*input$hgt # y coordinate for location
            
            ex <- 0.9*input$wdt # x coordinate for first entry
            
            ee <- 0.85*input$wdt # x coordinate for second entry
            
            ey <- 0.83*input$hgt # y coordinate for second entry
            
            nx <- 0.6*input$wdt # x coordinate for researcher's name
            
            
            grid::pushViewport(tt)
            
            # if (input$rounded == TRUE) {
            #   grid::grid.roundrect(gp = grid::gpar(lwd = 0.5))
            # } else (grid::grid.rect(gp = grid::gpar(lwd = 0.5)))
            
            # Draw rectangle around labels
            if (input$rect == TRUE) {
              
              if (input$rounded == TRUE) {
                grid::grid.roundrect(gp = grid::gpar(lwd = 0.5))
              } else (grid::grid.rect(gp = grid::gpar(lwd = 0.5)))
              
            } 
            
            # Add Plot ID to label; note coordinates
            grid::grid.text(label = lab_inf()[[1]][input$lab_sel],
                            x = grid::unit(px, "in"),
                            y = grid::unit(py, "in"), rot = 90,
                            gp = bold_font, hjust = 0, vp = tt)
            
            # Add Rep ID to label; note coordinates
            grid::grid.text(label = lab_inf()[[3]][input$lab_sel],
                            x= grid::unit(px, "in"),
                            y = grid::unit(ry, "in"), rot = 90,
                            gp = bold_font, hjust = 0, vp = tt)
            
            # Add Row ID to label; note coordinates
            grid::grid.text(label = lab_inf()[[2]][input$lab_sel],
                            x = grid::unit(rx, "in"),
                            y = grid::unit(py, "in"), rot = 90,
                            gp = bold_font2, hjust = 0, vp = tt)
            
            # Add column ID to label; note coordinates
            grid::grid.text(label = lab_inf()[[4]][input$lab_sel],
                            x = grid::unit(rx, "in"),
                            y = grid::unit(ry, "in"), rot = 90,
                            gp = bold_font2, hjust = 0, vp = tt)
            
            
            # Define viewport for QR code; note coordinates and dimension
            
            grid::pushViewport(qq)
            
            # Add first QR code
            grid::grid.draw(bb$bb[[input$lab_sel]])
            grid::popViewport()
            
            # Define viewport for Block ID if it is an incomplete block design
            
            grid::pushViewport(bl)
            
            # Add Block ID to label; note coordinates
            grid::grid.text(label = lab_inf()[[5]][input$lab_sel],
                            x = grid::unit(0.2, "npc"),
                            y = grid::unit(0.35, "npc"),
                            rot = 360, gp = bold_font2,
                            hjust = 0)
            
            
            # Go back to label viewport
            grid::upViewport()
            
            # Add location of experiment to label
            # grid::grid.text(label = lab_inf()[[8]][input$lab_sel],
            #                 rot = 90,
            #                 x = grid::unit(lx, "in"),
            #                 y = grid::unit(ly, "in"),
            #                 gp = bold_font3, hjust = 0, vp = tt)
            
            grid::grid.text(label = UNIQUE_ID()[input$lab_sel],
                            rot = 90,
                            x = grid::unit(lx, "in"),
                            y = grid::unit(ly, "in"),
                            gp = bold_font3, hjust = 0, vp = tt)
            
            
            # Add seed source to label; note coordinates
            grid::grid.text(label = lab_inf()[[6]][input$lab_sel],
                            x = grid::unit(0.6, "npc"),
                            y = grid::unit(0.35, "npc"),
                            rot = 90, vp = tt,
                            gp = bold_font3, hjust = 0, )
            
            # Add researcher's name to label; note coordinates
            grid::grid.text(label = lab_inf()[[7]][input$lab_sel],
                            x = grid::unit(0.72, "npc"),
                            y = grid::unit(0.35, "npc"),
                            rot = 90, vp = tt,
                            gp = bold_font3, hjust = 0, )
            
            
            # Add entry or treatment name to label
            grid::grid.text(label = lab_inf()[[9]][input$lab_sel], rot = 90,
                            x= grid::unit(ex, "in"),
                            y = grid::unit(py, "in"),
                            gp = bold_font3, hjust = 0, vp = tt)
            
            # Add entry or treatment name to label
            grid::grid.text(label = lab_inf()[[9]][input$lab_sel], rot = 90,
                            x = grid::unit(ee, "in"),
                            y = grid::unit(ey, "in"),
                            gp = bold_font4, hjust = 0, vp = tt)
            
            grid::pushViewport(qq2)
            
            # Add second QR code
            grid::grid.draw(bb$bb[[input$lab_sel]])
            
            grid::popViewport()
            # End for treetag field plot label preview
            
          } else if (input$templates != "Treetag LTS14") {
            
            
            #' Create a viewport for each label
            aa <- grid::viewport(x = grid::unit(0, "npc"),
                                 y = grid::unit(1, "npc"),
                                 width = grid::unit(input$wdt, "in"),
                                 height = grid::unit(input$hgt, "in"),
                                 just = c('left','top'))
            
            # Define viewport for QR code; note coordinates and dimension
            
            qq <- grid::viewport(x = grid::unit(0.5, "npc"),
                                 width = grid::unit(wdt1, "in"),
                                 height = grid::unit(qry, "in"),
                                 just = c('right','center'))
            
            # Define viewport for Block ID if it is an incomplete block design
            
            bl <- grid::viewport(x = grid::unit(0.47, "npc"),
                                 width = grid::unit(0.55*input$wdt, "in"),
                                 height = grid::unit(0.8*hgt1, "in"),
                                 just = "left")
            
            # Coordinates for adding text labels to grids
            px <- 0.1*input$wdt # x coordinate for plot
            
            py <- 0.92*input$hgt # y coordinate for plot
            
            rx <- 0.6*input$wdt # x coordinate for rep
            
            ry <- 0.78*input$hgt # y coordinate for row
            
            ly <- 0.22*input$hgt # y coordinate for location
            
            ex <- 0.05*input$wdt # x coordinate for entry
            
            ey <- 0.1*input$hgt # y coordinate for entry
            
            grid::pushViewport(aa)
            
            # if (input$rounded == TRUE) {
            #   grid::grid.roundrect(gp = grid::gpar(lwd = 0.5))
            # } else (grid::grid.rect(gp = grid::gpar(lwd = 0.5)))
            
            # Draw rectangle around labels
            if (input$rect == TRUE) {
              
              if (input$rounded == TRUE) {
                grid::grid.roundrect(gp = grid::gpar(lwd = 0.5))
              } else (grid::grid.rect(gp = grid::gpar(lwd = 0.5)))
              
            } 
            
            # Add Plot ID to label; note coordinates
            grid::grid.text(label = lab_inf()[[1]][input$lab_sel],
                            x = grid::unit(px, "in"),
                            y = grid::unit(py, "in"),
                            gp = bold_font, hjust = 0, vp = aa)
            
            # Add Rep ID to label; note coordinates
            grid::grid.text(label = lab_inf()[[3]][input$lab_sel],
                            x = grid::unit(rx, "in"),
                            y = grid::unit(py, "in"),
                            gp = bold_font, hjust = 0, vp = aa)
            
            # Add Row ID to label; note coordinates
            grid::grid.text(label = lab_inf()[[2]][input$lab_sel],
                            x = grid::unit(px, "in"),
                            y = grid::unit(ry, "in"),
                            gp = bold_font2, hjust = 0, vp = aa)
            
            # Add column ID to label; note coordinates
            grid::grid.text(label = lab_inf()[[4]][input$lab_sel],
                            x = grid::unit(rx, "in"),
                            y = grid::unit(ry, "in"),
                            gp = bold_font2, hjust = 0, vp = aa)
            
            # Add seed source to label; note coordinates
            grid::grid.text(label = lab_inf()[[6]][input$lab_sel],
                            x = grid::unit(0.42, "npc"),
                            y = grid::unit(0.47, "npc"),
                            gp = bold_font3, hjust = 0, vp = aa)
            
            # Add researcher's name to label; note coordinates
            grid::grid.text(label = lab_inf()[[7]][input$lab_sel],
                            x = grid::unit(0.42, "npc"),
                            y = grid::unit(0.35, "npc"),
                            gp = bold_font3, hjust = 0, vp = aa)
            
            
            # Push viewport for qr code
            
            grid::pushViewport(qq)
            
            # Add QR code
            grid::grid.draw(bb$bb[[input$lab_sel]])
            grid::popViewport()
            
            # Define viewport for Block ID if it is an incomplete block design
            
            grid::pushViewport(bl)
            
            # Add Block ID to label; note coordinates
            
            grid::grid.text(label = lab_inf()[[5]][input$lab_sel],
                            x = grid::unit(0.01, "npc"),
                            y = grid::unit(0.8, "npc"),
                            gp = bold_font2, hjust = 0)
            
            # Go back to label viewport
            grid::upViewport()
            
            # Add location of experiment to label
            # grid::grid.text(label = lab_inf()[[8]][input$lab_sel],
            #                 x= grid::unit(px, "in"),
            #                 y = grid::unit(ly, "in"),
            #                 gp = bold_font3, hjust = 0, vp = aa)
            
            grid::grid.text(label = UNIQUE_ID()[input$lab_sel],
                            x= grid::unit(px, "in"),
                            y = grid::unit(ly, "in"),
                            gp = bold_font3, hjust = 0, vp = aa)
            
            # Add entry or treatment name to label
            grid::grid.text(label = lab_inf()[[9]][input$lab_sel],
                            x= grid::unit(ex, "in"),
                            y = grid::unit(ey, "in"),
                            gp = bold_font3, hjust = 0, vp = aa)
            
            grid::popViewport()
            
          }
          
        } else if (input$label_type == "gpp"){
          if (input$templates != "Treetag LTS14") {
            qq <- grid::viewport(x = grid::unit(1, "npc"),
                                 width = grid::unit(wdt1, "in"),
                                 height = grid::unit(qry, "in"),
                                 just = c('right','center'))
            
            # Create a viewport for each label
            aa <- grid::viewport(x = grid::unit(0, "npc"),
                                 y = grid::unit(1, "npc"),
                                 width = grid::unit(input$wdt, "in"),
                                 height = grid::unit(input$hgt, "in"),
                                 just = c('left','top'))
            
            txt1x <- 0.95*input$wdt # x coordinate for txt1
            
            txt1y <- 0.05*input$hgt # y coordinate for txt1
            
            txt2x <- 0.9*input$wdt # x coordinate for txt2
            
            txt3x <- 0.6*input$wdt # y coordinate for txt3
            
            txt4x <- 0.5*input$wdt # y coordinate for txt4
            
            txt5x <- 0.4*input$wdt # x coordinate for txt5
            
            txt6x <- 0.3*input$wdt # x coordinate for txt6 and 7
            
            txt7y <- 0.55*input$hgt # y coordinate for txt7 and 9
            
            txt8x <- 0.2*input$wdt # x coordinate for txt8 and txt9
            
            txt10x <- 0.05*input$wdt # y coordinate for txt10
            
            grid::pushViewport(aa)
            
            # if (input$rounded == TRUE) {
            #   grid::grid.roundrect(gp = grid::gpar(lwd = 0.5))
            # } else (grid::grid.rect(gp = grid::gpar(lwd = 0.5)))
            
            # Draw rectangle around labels
            if (input$rect == TRUE) {
              
              if (input$rounded == TRUE) {
                grid::grid.roundrect(gp = grid::gpar(lwd = 0.5))
              } else (grid::grid.rect(gp = grid::gpar(lwd = 0.5)))
              
            } 
            
            # Add text1 to label (bottom position 1); note coordinates
            grid::grid.text(label = lab_inf()[[1]][input$lab_sel],
                            x = grid::unit(txt1x, "in"),
                            y = grid::unit(txt1y, "in"), rot = 90,
                            gp = bold_font2, hjust = 0, vp = aa)
            
            # Add text2 to label (bottom position 2); note coordinates
            grid::grid.text(label = lab_inf()[[2]][input$lab_sel],
                            x = grid::unit(txt2x, "in"),
                            y = grid::unit(txt1y, "in"), rot = 90,
                            gp = bold_font4, hjust = 0, vp = aa)
            
            
            # Add text3 to label (bottom position 3); note coordinates
            grid::grid.text(label = lab_inf()[[3]][input$lab_sel],
                            x = grid::unit(txt3x, "in"),
                            y = grid::unit(txt1y, "in"), rot = 90,
                            gp = plain_font3, hjust = 0, vp = aa)
            
            # Add text4 to label (center position 1); note coordinates
            grid::grid.text(label = lab_inf()[[4]][input$lab_sel],
                            x = grid::unit(txt4x, "in"),
                            y = grid::unit(txt1y, "in"), rot = 90,
                            gp = plain_font3, hjust = 0, vp = aa)
            
            # Add text5 to label (center position 2); note coordinates
            grid::grid.text(label = lab_inf()[[5]][input$lab_sel],
                            x = grid::unit(txt5x, "in"),
                            y = grid::unit(txt1y, "in"), rot = 90,
                            gp = bold_font2, just = c(-0.5, 0.5), vp = aa)
            
            
            # Define viewport for QR code; note coordinates and dimension
            
            grid::pushViewport(qq)
            
            # Add first QR code
            grid::grid.draw(bb$bb[[input$lab_sel]])
            # grid::popViewport()
            
            
            # Go back to label viewport
            grid::upViewport()
            
            # Add text6 to label (center position 3); note coordinates
            grid::grid.text(label = lab_inf()[[6]][input$lab_sel],
                            x = grid::unit(txt6x, "in"),
                            y = grid::unit(txt1y, "in"), rot = 90,
                            gp = bold_font3, hjust = 0, vp = aa)
            
            
            # Add text7 to label (center position 4); note coordinates
            grid::grid.text(label = lab_inf()[[7]][input$lab_sel],
                            x = grid::unit(txt6x, "in"),
                            y = grid::unit(txt7y, "in"), rot = 90,
                            gp = bold_font3, hjust = 0, vp = aa)
            
            
            # Add text8 to label (top position 1); note coordinates
            grid::grid.text(label = lab_inf()[[8]][input$lab_sel],
                            x = grid::unit(txt8x, "in"),
                            y = grid::unit(txt1y, "in"), rot = 90,
                            gp = bold_font3, hjust = 0, vp = aa)
            
            
            # Add text9 to label (top position 2); note coordinates
            grid::grid.text(label = lab_inf()[[9]][input$lab_sel],
                            x = grid::unit(txt8x, "in"),
                            y = grid::unit(txt7y, "in"), rot = 90,
                            gp = bold_font3, hjust = 0, vp = aa)
            
            
            # Add text10 to label (top position 3); note coordinates
            grid::grid.text(label = lab_inf()[[10]][input$lab_sel],
                            x = grid::unit(txt10x, "in"),
                            y = grid::unit(txt1y, "in"), rot = 90,
                            gp = bold_font, hjust = 0, vp = aa)
            
            
            grid::popViewport()
            
          }
        }
        
      },
      warning = function(cond) {
        showModal(modalDialog(title = "Warning",
                              "Warnings. Please double-check entered values in order to
                            produce the expected results."))
      },
      error = function(cond) {
        showModal(modalDialog(title = "Error",
                              "A label preview error occurred. Check the page/label setting parameters or
                           the input for label to preview."))
        
      })
      
    }) # end of label preview
    
  })
  
  
  # Generate labels functions
  create_label <- function(){
    
    # Calculate space between label columns if any
    if (input$numcol == 1) {
      col_space <- 0
    } else {col_space <- (input$page_wdt - input$left_mar - input$right_mar -
                            input$numcol*input$wdt)/(input$numcol-1)
    }
    
    # Calculate space between label rows if any
    if (input$numrow == 1) {
      row_space <- 0
    } else {row_space <- (input$page_hgt - input$top_mar - input$bot_mar -
                            input$numrow*input$hgt)/(input$numrow-1)
    }
    
    #' Check if page setup matches label setup per page.
    #' Error message if either column spaces or the row spaces between labels 
    #' are less than zero
    
    if (col_space < 0 | row_space < 0) {
      
      showModal(modalDialog(title = "Error",
                            "Page setup does not match label setup per page!"))
    }
    
    # clean up any open graphical devices if function fails
    on.exit(grDevices::graphics.off())
    
    
    if (input$label_type == "field") {
      plotid <- lab_inf()[[1]] # Plot ids
      repid <- lab_inf()[[2]] # Rep ids
      rowid <- lab_inf()[[3]] # Row ids
      colid <- lab_inf()[[4]]   # Column ids
      Blkid <- lab_inf()[[5]] # iBlocks
      seed_src <- lab_inf()[[6]] # seed source
      rname <- lab_inf()[[7]]
      ids <-  UNIQUE_ID() # unique ids
      Entry <- lab_inf()[[9]]# Entry or treatment ids
      
      qrcds <- bb$bb # QR codes
      
    } else if (input$label_type == "gp") {
      plotid <- lab_inf()[[1]] # Top-left row 1
      repid <- lab_inf()[[3]] # Top-left row 2
      rowid <- lab_inf()[[2]] # Top-right row 1
      colid <- lab_inf()[[4]] # Top-right row 2
      Blkid <- lab_inf()[[5]] # Center-right row 1
      seed_src <- lab_inf()[[6]] # Center-right row 2
      rname <- lab_inf()[[7]] # Center-right row 3
      ids <-  lab_inf()[[8]] # Bottom-left row 1
      Entry <- lab_inf()[[9]]# Bottom-left row 2
      
      qrcds <- bb$bb # QR codes
    }
    
    nn <- length(qrcds)
    
    # Use common tempdir to write app's outputs
    temp_directory <- tempdir()

    # Call the function to create the augmented fieldbook containing unique IDs
    create_aug_fieldbook(target_dir = temp_directory)
    
    
    #' Generate label positions -- prints across rows of grid layout
    #pos <- expand.grid(x = 1:input$numcol, y = 1:input$numrow)
    
    # Generate label positions -- prints across rows of grid layout
    if (input$print_across == TRUE) {
      
      pos <- expand.grid(x = 1:input$numcol, y = 1:input$numrow)
      
    } else {
      
      pos <- expand.grid(y = 1:input$numrow, x = 1:input$numcol)
      
    }
    
    
    duplication <- ceiling(nn/nrow(pos))
    
    label_pos <- do.call("rbind", replicate(duplication, pos, simplify = FALSE))
    
    corx <- label_pos$x # label x coordinate
    
    cory <- label_pos$y # label y coordinate
    
    #' Create pdf file to be saved in temp_directory 
    pdf_filename <<- file.path(temp_directory,
                            paste0(input$filename, paste0(input$wdt,'in'), 'x',
                            paste0(input$hgt,'in'), Sys.time())) # name of pdf file 
    
    pdf_filename <<- paste0(gsub(":","_", pdf_filename), ".pdf")
    
    
    #' Font size to print text on labels
    fsize <- input$font_size
    
    # Define new coordinates for QR code
    wdt1 <- 0.5 * input$wdt
    hgt1 <- 0.5 * input$hgt
    
    qry <- hgt1/1.2
    
    #' Create pdf file
    #' The argument input$family specifies the initial/default font input$family to be
    #' used. Device-independent fonts include "sans", "serif", and "mono",
    
    grDevices::pdf(pdf_filename,
                   width = input$page_wdt,
                   height = input$page_hgt,
                   onefile = TRUE,
                   family = input$family) # Letter size paper from Avery
    
    #' Grid layout for labels
    label_layout <- grid::grid.layout(input$numrow, input$numcol,
                                      widths = grid::unit(c(rep(input$wdt + col_space,input$numcol-1),
                                                            input$wdt), "in"),
                                      heights = grid::unit(c(rep(input$hgt + row_space,input$numrow-1),
                                                             input$hgt), "in"))
    
    
    if (input$templates == "Treetag LTS14") {
      # Viewport for first QR codes
      qq <- grid::viewport(x = grid::unit(0.57, "npc"),
                           y = grid::unit(0.3, "npc"),
                           angle = 90,
                           width = grid::unit(wdt1, "in"),
                           height = grid::unit(qry, "in"),
                           just = c('right','center'))
      
      # Viewport for IBlock
      bl <- grid::viewport(x = grid::unit(0.1, "npc"),
                           y = grid::unit(0.3, "npc"),
                           angle = 90,
                           width = grid::unit(0.55*input$wdt, "in"),
                           height = grid::unit(0.8*hgt1, "in"),
                           just = "left")
      
      # Viewport for second QR code
      qq2 <- grid::viewport(x = grid::unit(0.5, "npc"),
                            y = grid::unit(0.9, "npc"),
                            width = grid::unit(wdt1, "inches"),
                            height = grid::unit(qry, "inches"),
                            just = c('center'))
      
      px <- 0.11*input$wdt # x coordinate for plot
      
      py <- 0.05*input$hgt # y coordinate for plot
      
      rx <- 0.27*input$wdt # x coordinate for row
      
      ry <- 0.4*input$hgt # y coordinate for Rep
      
      lx <- 0.9*input$wdt # x coordinate for location
      
      ly <- 0.4*input$hgt # y coordinate for location
      
      ex <- 0.9*input$wdt # x coordinate for first entry
      
      ee <- 0.85*input$wdt # x coordinate for second entry
      
      ey <- 0.83*input$hgt # y coordinate for second entry
      
      nx <- 0.6*input$wdt # x coordinate for researcher's name
      
    } else {
      #' Create a viewport for each label
      aa <- grid::viewport(x = grid::unit(0, "npc"),
                           y = grid::unit(1, "npc"),
                           width = grid::unit(input$wdt, "in"),
                           height = grid::unit(input$hgt, "in"),
                           just = c('left','top'))
      
      # Define viewport for QR code; note coordinates and dimension
      
      qq <- grid::viewport(x = grid::unit(0.5, "npc"),
                           width = grid::unit(wdt1, "in"),
                           height = grid::unit(qry, "in"),
                           just = c('right','center'))
      
      # Define viewport for Block ID if it is an incomplete block design
      
      bl <- grid::viewport(x = grid::unit(0.47, "npc"),
                           width = grid::unit(0.55*input$wdt, "in"),
                           height = grid::unit(0.8*hgt1, "in"),
                           just = "left")
      
      # Coordinates for adding text labels to grids
      px <- 0.1*input$wdt # x coordinate for plot
      
      py <- 0.92*input$hgt # y coordinate for plot
      
      rx <- 0.6*input$wdt # x coordinate for rep
      
      ry <- 0.78*input$hgt # y coordinate for row
      
      ly <- 0.22*input$hgt # y coordinate for location
      
      ex <- 0.05*input$wdt # x coordinate for entry
      
      ey <- 0.1*input$hgt # y coordinate for entry
      
    } # end of if statement to create viewports
    
    # Viewport for a new page
    new.page <- grid::viewport(width = grid::unit(input$page_wdt, "in"),
                               height = grid::unit(input$page_hgt, "in"))
    
    #' Create a viewport for each page using grid layout
    lab_vp <- grid::viewport(layout = label_layout)
    grid::pushViewport(lab_vp)
    
    bold_font <- grid::gpar(fontface = "bold", fontsize = fsize)
    bold_font2 <- grid::gpar(fontface = "bold", fontsize = fsize-2)
    plain_font2 <- grid::gpar(fontface = "plain", fontsize = fsize-2)
    plain_font3 <- grid::gpar(fontface = "plain", fontsize = fsize-4)
    bold_font3 <- grid::gpar(fontface = "bold", fontsize = fsize-4)
    bold_font4 <- grid::gpar(fontface = "bold", fontsize = floor(fsize/2.5))
    plain_font4 <- grid::gpar(fontface = "plain", fontsize = floor(fsize/2.5))
    
    withProgress(message = paste("Designing", nn, "labels."), value = 0, {
      
      for (i in seq_len(nn)) {
        
        # Increment the progress bar, and update the detail text.
        incProgress(1/nn, detail = paste("Label", i))
        
        label_posn <- c(x = corx[i], y = cory[i])
        
        # Generate QR code
        #bb <- make_qr(UNIQUE_ID[i])
        
        if (all(i != 1 & label_posn == c(1, 1))) {
          grid::grid.newpage()
          
          grid::pushViewport(new.page)
          grid::pushViewport(lab_vp)
          
        }
        
        if (input$templates == "Treetag LTS14") {
          
          tt <- grid::viewport(layout.pos.row = label_posn['y'],
                               layout.pos.col = label_posn['x'])
          
          
          grid::pushViewport(tt)
          
          # if (input$rounded == TRUE) {
          #   grid::grid.roundrect(gp = grid::gpar(lwd = 0.5))
          # } else (grid::grid.rect(gp = grid::gpar(lwd = 0.5)))
          
          # Draw rectangle around labels
          if (input$rect == TRUE) {
            
            if (input$rounded == TRUE) {
              grid::grid.roundrect(gp = grid::gpar(lwd = 0.5))
            } else (grid::grid.rect(gp = grid::gpar(lwd = 0.5)))
            
          } 
          
          # Add Plot ID to label; note coordinates
          grid::grid.text(label = plotid[i],
                          x = grid::unit(px, "in"),
                          y = grid::unit(py, "in"), rot = 90,
                          gp = bold_font, hjust = 0, vp = tt)
          
          # Add Rep ID to label; note coordinates
          grid::grid.text(label = repid[i],
                          x = grid::unit(px, "in"),
                          y = grid::unit(ry, "in"), rot = 90,
                          gp = bold_font, hjust = 0, vp = tt)
          
          # Add Row ID to label; note coordinates
          grid::grid.text(label = rowid[i],
                          x = grid::unit(rx, "in"),
                          y = grid::unit(py, "in"), rot = 90,
                          gp = bold_font2, hjust = 0, vp = tt)
          
          # Add column ID to label; note coordinates
          grid::grid.text(label = colid[i],
                          x = grid::unit(rx, "in"),
                          y = grid::unit(ry, "in"), rot = 90,
                          gp = bold_font2, hjust = 0, vp = tt)
          
          
          # Define viewport for QR code; note coordinates and dimension
          
          grid::pushViewport(qq)
          
          # Add first QR code
          grid::grid.draw(qrcds[[i]])
          grid::popViewport()
          
          # Define viewport for Block ID if it is an incomplete block design
          
          grid::pushViewport(bl)
          
          # Add Block ID to label; note coordinates
          grid::grid.text(label = Blkid[i],
                          x = grid::unit(0.2, "npc"),
                          y = grid::unit(0.35, "npc"),
                          rot = 360, gp = plain_font2, hjust = 0)
          
          
          # Go back to label viewport
          grid::upViewport()
          
          # Add Unique ID to label
          grid::grid.text(label = ids[i], rot = 90,
                          x= grid::unit(lx, "in"),
                          y = grid::unit(ly, "in"),
                          gp = plain_font4, hjust = 0, vp = tt)
          
          # Add seed source to label; note coordinates
          grid::grid.text(label = seed_src[i],
                          x = grid::unit(0.6, "npc"),
                          y = grid::unit(0.35, "npc"),
                          rot = 90, vp = tt,
                          gp = plain_font3, hjust = 0, )
          
          # Add researcher's name to label; note coordinates
          grid::grid.text(label = rname[i],
                          x = grid::unit(0.72, "npc"),
                          y = grid::unit(0.35, "npc"),
                          rot = 90, vp = tt,
                          gp = plain_font3, hjust = 0, )
          
          
          # Add entry or treatment name to label
          grid::grid.text(label = Entry[i], rot = 90,
                          x= grid::unit(ex, "in"),
                          y = grid::unit(py, "in"),
                          gp = bold_font3, hjust = 0, vp = tt)
          
          # Add entry or treatment name to label tear-off
          grid::grid.text(label = Entry[i], rot = 90,
                          x = grid::unit(ee, "in"),
                          y = grid::unit(ey, "in"),
                          gp = bold_font3, hjust = 0, vp = tt)
          
          # Add 'qrlabelr' branding at the extreme right edge
          grid::grid.text(
            label = "qrlabelr",
            x = grid::unit(0.5 * input$wdt, "in"),
            y = grid::unit(0.02 * input$hgt, "in"),
            rot = 180,
            gp = grid::gpar(fontface = "plain", fontsize = plain_font4, 
                            col = "gray30"),
            just = "center",
            vp = tt)
          
          grid::pushViewport(qq2)
          
          # Add second QR code
          grid::grid.draw(qrcds[[i]])
          
          grid::popViewport(2)
          
        } else {
          grid::pushViewport(grid::viewport(layout.pos.row=label_posn['y'],
                                            layout.pos.col=label_posn['x']))
          grid::pushViewport(aa)
          
          # if(input$rounded == TRUE){
          #   grid::grid.roundrect(gp = grid::gpar(lwd = 0.5))
          # }else(grid::grid.rect(gp = grid::gpar(lwd = 0.5)))
          
          # Draw rectangle around labels
          if (input$rect == TRUE) {
            
            if (input$rounded == TRUE) {
              grid::grid.roundrect(gp = grid::gpar(lwd = 0.5))
            } else (grid::grid.rect(gp = grid::gpar(lwd = 0.5)))
            
          } 
          
          # Add Plot ID to label; note coordinates
          grid::grid.text(label = plotid[i],
                          x = grid::unit(px, "in"),
                          y = grid::unit(py, "in"),
                          gp = bold_font, hjust = 0, vp = aa)
          
          # Add Rep ID to label; note coordinates
          grid::grid.text(label = repid[i],
                          x = grid::unit(rx, "in"),
                          y = grid::unit(py, "in"),
                          gp = bold_font, hjust = 0, vp = aa)
          
          # Add Row ID to label; note coordinates
          grid::grid.text(label = rowid[i],
                          x = grid::unit(px, "in"),
                          y = grid::unit(ry, "in"),
                          gp = bold_font2, hjust = 0, vp = aa)
          
          # Add column ID to label; note coordinates
          grid::grid.text(label = colid[i],
                          x = grid::unit(rx, "in"),
                          y = grid::unit(ry, "in"),
                          gp = bold_font2, hjust = 0, vp = aa)
          
          # Add seed source to label; note coordinates
          grid::grid.text(label = seed_src[i],
                          x = grid::unit(0.42, "npc"),
                          y = grid::unit(0.47, "npc"),
                          gp = plain_font3, hjust = 0, vp = aa)
          
          # Add researcher's name to label; note coordinates
          grid::grid.text(label = rname[i],
                          x = grid::unit(0.42, "npc"),
                          y = grid::unit(0.35, "npc"),
                          gp = plain_font3, hjust = 0, vp = aa)
          
          # Push viewport for qr code
          
          grid::pushViewport(qq)
          
          # Add QR code
          grid::grid.draw(qrcds[[i]])
          grid::popViewport()
          
          # Define viewport for Block ID if it is an incomplete block design
          
          grid::pushViewport(bl)
          
          # Add Block ID to label; note coordinates
          grid::grid.text(label = Blkid[i],
                          x = grid::unit(0.01, "npc"),
                          y = grid::unit(0.8, "npc"),
                          gp = plain_font2, hjust = 0)
          
          # Go back to label viewport
          grid::upViewport()
          
          # Add Unique ID to label
          grid::grid.text(label = ids[i],
                          x= grid::unit(px, "in"),
                          y = grid::unit(ly, "in"),
                          gp = plain_font4, hjust = 0, vp = aa)
          
          # Add entry or treatment name to label
          grid::grid.text(label = Entry[i],
                          x= grid::unit(ex, "in"),
                          y = grid::unit(ey, "in"),
                          gp = bold_font3, hjust = 0, vp = aa)
          
          # Add 'qrlabelr' branding at the extreme left edge
          grid::grid.text(
            label = "qrlabelr",
            x = grid::unit(0.02 * input$wdt, "in"),
            y = grid::unit(0.5 * input$hgt, "in"),
            rot = 90,
            gp = grid::gpar(fontface = "plain", fontsize = plain_font4, 
                            col = "gray30"),
            just = "center",
            vp = aa)
          
          grid::popViewport(2)
        }
        
      }
    })
    #grDevices::dev.off()
    
    # Show a modal on successful generation of labels
    showModal(modalDialog(title = "Success", "Labels have been successfully generated!
                          Click the 'Download labels' button to download a PDF file
                          containing the generated labels to your computer.",
                          footer = modalButton("OK"),
                          easyClose = TRUE))
    
    # Enable the initially disabled 'Download labels' button
    shinyjs::enable(id = "down_labels")
    shinyjs::enable(id = "down_fieldbook")
  } # End of create_label for field plot and gp landscape
  
  
  #---------------------------------------------------------------------------------------#
  
  gp_label_portrait <- function() {
    
    # Calculate space between label columns if any
    if (input$numcol == 1) {
      col_space <- 0
    } else {col_space <- (input$page_wdt - input$left_mar - input$right_mar -
                            input$numcol*input$wdt)/(input$numcol-1)
    }
    
    # Calculate space between label rows if any
    if (input$numrow == 1) {
      row_space <- 0
    } else {row_space <- (input$page_hgt - input$top_mar - input$bot_mar -
                            input$numrow*input$hgt)/(input$numrow-1)
    }
    
    #' Check if page setup matches label setup per page.
    #' Error message if either column spaces or the row spaces between labels 
    #' are less than zero
    
    if (col_space < 0 | row_space < 0) {
      
      showModal(modalDialog(title = "Error",
                            "Page setup does not match label setup per page!"))
    }
    
    # clean up any open graphical devices if function fails
    on.exit(grDevices::graphics.off())
    
    if (input$label_type == "gpp") {
      text1 <- lab_inf()[[1]] # Top-left row 1
      text2 <- lab_inf()[[2]] # Top-left row 2
      text3 <- lab_inf()[[3]] # Top-right row 1
      text4 <- lab_inf()[[4]] # Top-right row 2
      text5 <- lab_inf()[[5]] # Center-right row 1
      text6 <- lab_inf()[[6]] # Center-right row 2
      text7 <- lab_inf()[[7]] # Center-right row 3
      text8 <-  lab_inf()[[8]] # Bottom-left row 1
      text9 <- lab_inf()[[9]]# Bottom-left row 2
      text10 <- lab_inf()[[10]]# Bottom-left row 2
      
      qrcds <- bb$bb # QR codes
    }
    
    nn <- length(qrcds)
    
    #' Generate label positions -- prints across rows of grid layout
    # pos <- expand.grid(x = 1:input$numcol, y = 1:input$numrow)
    # Generate label positions -- prints across rows of grid layout
    if (input$print_across == TRUE) {
      
      pos <- expand.grid(x = 1:input$numcol, y = 1:input$numrow)
      
    } else {
      
      pos <- expand.grid(y = 1:input$numrow, x = 1:input$numcol)
      
    }
    
    duplication <- ceiling(nn/nrow(pos))
    
    label_pos <- do.call("rbind", replicate(duplication, pos, simplify = FALSE))
    
    corx <- label_pos$x # label x coordinate
    
    cory <- label_pos$y # label y coordinate
    

    # Use common tempdir to write app's outputs
    # TODO: this funcitonality should moved into a function (DRY)
    temp_directory <- tempdir()
 
    #' Create pdf file to be saved in temp_directory 
    pdf_filename <<- file.path(temp_directory,
                            paste0(input$filename, paste0(input$wdt,'in'), 'x',
                            paste0(input$hgt,'in'), Sys.time())) # name of pdf file 

    pdf_filename <<- paste0(gsub(":","_", pdf_filename), ".pdf")

    #' Font size to print text on labels
    fsize <- input$font_size
    
    # Define new coordinates for QR code
    wdt1 <- 0.5 * input$wdt
    hgt1 <- 0.5 * input$hgt
    
    qry <- hgt1/1.2
    
    #' Create pdf file
    #' The argument input$family specifies the initial/default font input$family to be
    #' used. Device-independent fonts include "sans", "serif", and "mono",
    
    grDevices::pdf(pdf_filename,
                   width = input$page_wdt,
                   height = input$page_hgt,
                   onefile = TRUE,
                   family = input$family) # Letter size paper from Avery
    
    #' Grid layout for labels
    label_layout <- grid::grid.layout(input$numrow, input$numcol,
                                      widths = grid::unit(c(rep(input$wdt + col_space,input$numcol-1),
                                                            input$wdt), "in"),
                                      heights = grid::unit(c(rep(input$hgt + row_space,input$numrow-1),
                                                             input$hgt), "in"))
    
    qq <- grid::viewport(x = grid::unit(1, "npc"),
                         width = grid::unit(wdt1, "in"),
                         height = grid::unit(qry, "in"),
                         just = c('right','center'))
    
    # Create a viewport for each label
    aa <- grid::viewport(x = grid::unit(0, "npc"),
                         y = grid::unit(1, "npc"),
                         width = grid::unit(input$wdt, "in"),
                         height = grid::unit(input$hgt, "in"),
                         just = c('left','top'))
    
    txt1x <- 0.95*input$wdt # x coordinate for txt1
    
    txt1y <- 0.05*input$hgt # y coordinate for txt1
    
    txt2x <- 0.9*input$wdt # x coordinate for txt2
    
    txt3x <- 0.6*input$wdt # y coordinate for txt3
    
    txt4x <- 0.5*input$wdt # y coordinate for txt4
    
    txt5x <- 0.4*input$wdt # x coordinate for txt5
    
    txt6x <- 0.3*input$wdt # x coordinate for txt6 and 7
    
    txt7y <- 0.55*input$hgt # y coordinate for txt7 and 9
    
    txt8x <- 0.2*input$wdt # x coordinate for txt8 and txt9
    
    txt10x <- 0.05*input$wdt # y coordinate for txt10
    
    
    
    # Viewport for a new page
    new.page <- grid::viewport(width = grid::unit(input$page_wdt, "in"),
                               height = grid::unit(input$page_hgt, "in"))
    
    # Create a viewport for each page using grid layout
    lab_vp <- grid::viewport(layout = label_layout)
    grid::pushViewport(lab_vp)
    
    bold_font <- grid::gpar(fontface = "bold", fontsize = fsize)
    bold_font2 <- grid::gpar(fontface = "bold", fontsize = fsize-2)
    plain_font2 <- grid::gpar(fontface = "plain", fontsize = fsize-2)
    plain_font3 <- grid::gpar(fontface = "plain", fontsize = fsize-4)
    bold_font3 <- grid::gpar(fontface = "bold", fontsize = fsize-4)
    bold_font4 <- grid::gpar(fontface = "plain", fontsize = floor(fsize/2.5))
    
    withProgress(message = paste("Designing", nn, "labels."), value = 0, {
      
      for (i in seq_len(nn)) {
        
        # Increment the progress bar, and update the detail text.
        incProgress(1/nn, detail = paste("Label", i))
        
        label_posn <- c(x = corx[i], y = cory[i])
        
        # Generate QR code
        #bb <- make_qr(UNIQUE_ID[i])
        
        if (all(i != 1 & label_posn == c(1, 1))) {
          grid::grid.newpage()
          
          grid::pushViewport(new.page)
          grid::pushViewport(lab_vp)
          
        }
        
        grid::pushViewport(grid::viewport(layout.pos.row=label_posn['y'],
                                          layout.pos.col=label_posn['x']))
        grid::pushViewport(aa)
        
        # if (input$rounded == TRUE) {
        #   grid::grid.roundrect(gp = grid::gpar(lwd = 0.5))
        # } else (grid::grid.rect(gp = grid::gpar(lwd = 0.5)))
        
        
        # Draw rectangle around labels
        if (input$rect == TRUE) {
          
          if (input$rounded == TRUE) {
            grid::grid.roundrect(gp = grid::gpar(lwd = 0.5))
          } else (grid::grid.rect(gp = grid::gpar(lwd = 0.5)))
          
        } 
        
        # Add text1 to label (bottom position 1); note coordinates
        grid::grid.text(label = text1[i],
                        x = grid::unit(txt1x, "in"),
                        y = grid::unit(txt1y, "in"), rot = 90,
                        gp = bold_font2, hjust = 0, vp = aa)
        
        # Add text2 to label (bottom position 2); note coordinates
        grid::grid.text(label = text2[i],
                        x = grid::unit(txt2x, "in"),
                        y = grid::unit(txt1y, "in"), rot = 90,
                        gp = bold_font4, hjust = 0, vp = aa)
        
        
        # Add text3 to label (bottom position 3); note coordinates
        grid::grid.text(label = text3[i],
                        x = grid::unit(txt3x, "in"),
                        y = grid::unit(txt1y, "in"), rot = 90,
                        gp = plain_font3, hjust = 0, vp = aa)
        
        # Add text4 to label (center position 1); note coordinates
        grid::grid.text(label = text4[i],
                        x = grid::unit(txt4x, "in"),
                        y = grid::unit(txt1y, "in"), rot = 90,
                        gp = plain_font3, hjust = 0, vp = aa)
        
        # Add text5 to label (center position 2); note coordinates
        grid::grid.text(label = text5[i],
                        x = grid::unit(txt5x, "in"),
                        y = grid::unit(txt1y, "in"), rot = 90,
                        gp = bold_font2, just = c(-0.5, 0.5), vp = aa)
        
        
        # Define viewport for QR code; note coordinates and dimension
        
        grid::pushViewport(qq)
        
        # Add first QR code
        grid::grid.draw(qrcds[[i]])
        # grid::popViewport()
        
        
        # Go back to label viewport
        grid::upViewport()
        
        # Add text6 to label (center position 3); note coordinates
        grid::grid.text(label = text6[i],
                        x = grid::unit(txt6x, "in"),
                        y = grid::unit(txt1y, "in"), rot = 90,
                        gp = bold_font3, hjust = 0, vp = aa)
        
        
        # Add text7 to label (center position 4); note coordinates
        grid::grid.text(label = text7[i],
                        x = grid::unit(txt6x, "in"),
                        y = grid::unit(txt7y, "in"), rot = 90,
                        gp = bold_font3, hjust = 0, vp = aa)
        
        
        # Add text8 to label (top position 1); note coordinates
        grid::grid.text(label = text8[i],
                        x = grid::unit(txt8x, "in"),
                        y = grid::unit(txt1y, "in"), rot = 90,
                        gp = bold_font3, hjust = 0, vp = aa)
        
        
        # Add text9 to label (top position 2); note coordinates
        grid::grid.text(label = text9[i],
                        x = grid::unit(txt8x, "in"),
                        y = grid::unit(txt7y, "in"), rot = 90,
                        gp = bold_font3, hjust = 0, vp = aa)
        
        
        # Add text10 to label (top position 3); note coordinates
        grid::grid.text(label = text10[i],
                        x = grid::unit(txt10x, "in"),
                        y = grid::unit(txt1y, "in"), rot = 90,
                        gp = bold_font, hjust = 0, vp = aa)
        
        # Add 'qrlabelr' branding at the extreme left edge
        grid::grid.text(
          label = "qrlabelr",
          x = grid::unit(0.7 * input$wdt, "in"),
          y = grid::unit(0.96 * input$hgt, "in"),
          gp = grid::gpar(fontface = "plain", fontsize = bold_font4, 
                          col = "gray30"),
          just = "center",
          vp = aa)
        
        grid::popViewport(2)
        
        
      } 
      
    })
    
    # Show a modal on successful generation of labels
    showModal(modalDialog(title = "Success", "Labels have been successfully generated!
                          Click the 'Download labels' button to download a PDF file
                          containing the generated labels to your computer.",
                          footer = modalButton("OK"),
                          easyClose = TRUE))
    
    # Enable the initially disabled 'Download labels' button
    shinyjs::enable(id = "down_labels")
    shinyjs::enable(id = "down_fieldbook")
    
  }# End of gp_label_portrait ()
  #----------------------------------------------------------------------------------------#
  session$onSessionEnded(function(){
    list_of_pdfs <- list.files(pattern = "\\.pdf$|\\.csv$")
    
    if(!is.null(list_of_pdfs)) {
      file.remove(list_of_pdfs)
    }
  })
  
  # Automatically bookmark every time an input changes
  # observe({
  #   reactiveValuesToList(input)
  #   session$doBookmark()
  # })
  
  # Update the query string
  #onBookmarked(updateQueryString)
  
}

shinyApp(ui, server)








