# the CM SAF R Toolbox.
#
# You should not use this R-script on its own!
#
# Have fun with the CM SAF R TOOLBOX!
#                                              (Steffen Kothe / CM SAF 2024-05-07)
#__________________________________________________________________________________

# Function to compute first of month
firstOfMonth <- function(x) {
  x <- as.POSIXlt(x)
  x$mday <- 1
  as.Date(x)
}

getClaasAux <- function(tar_list){
  # Get CLAAS auxfile name
  claas_aux <<- "CLAAS_AUX_FILE"
  if ("CM_SAF_CLAAS2_L2_AUX.nc" %in% tar_list) (claas_aux <<- "CM_SAF_CLAAS2_L2_AUX.nc")
  if ("CM_SAF_CLAAS3_L2_AUX.nc" %in% tar_list) (claas_aux <<- "CM_SAF_CLAAS3_L2_AUX.nc")
  
  return(claas_aux)
}

# Get tarlist sorted by name.
getTarList <- function(path_to_tar, tar_flag = 1, includeClaasAux = FALSE) {
  
  ordname <- cmsafops::get_basename(path_to_tar)
  ordpath <- dirname(path_to_tar)

  if (identical(path_to_tar, character(0))) {
    stop(paste0("No infile!", var))
  }

  flist <- list.files(ordpath, substr(ordname, 1, 8), full.names = TRUE)
 
  tarlist <- NULL
  for (file in flist) {
    if (tar_flag == 1) {
      tarlist <- append(tarlist, utils::untar(file, list = TRUE, tar = "internal"))
    } else if (tar_flag == 2) {
      tarlist <- append(tarlist, utils::untar(file, list = TRUE, tar = Sys.getenv("TAR")))
    } else if (tar_flag == 3) {
      tarlist <- append(tarlist, utils::untar(file, list = TRUE, tar = "C:/Rtools/bin/tar.exe"))
    } else {
      tarlist <- append(tarlist, utils::untar(file, list = TRUE))
    }
  }
 
  claas_aux <- getClaasAux(tarlist)
  # Exlude claas aux file if not wanted.
  if (!includeClaasAux) {
    tarlist <- tarlist[tarlist != claas_aux
                       & tarlist != claas_aux]
  }

  tarlist <- sort(tarlist)
  
  return(tarlist)
}

# Get CLAAS AUX FLAG
getClaasAuxFlag <- function(tarlist) {
  return(claas_aux %in% tarlist)
}

# A function to extract ALL dates from a tar file.
extractAllDates <- function(path_to_tar, tar_flag) {
  # List the to be untared  file.
  tarlist <- getTarList(path_to_tar, tar_flag = tar_flag)

  # Timestep HAS TO BE RELEVANT FOR SOMETHING! FIND THAT OUT!!
  timestep <- substr(tarlist[1], 4, 4)

  allDates <- as.character(substr(tarlist, 6, 13))
  return(list(allDates = as.Date(allDates, "%Y%m%d"), timestep = timestep))
}

# A function to extract start and end dates.
extractDateRange <- function(path_to_tar, tar_flag) {

  tmp <- extractAllDates(path_to_tar, tar_flag = tar_flag)

  # Select earliest date from the files.
  date_from <- min(tmp$allDates)
  date_to   <- max(tmp$allDates)

  return(list(date_from = date_from, date_to = date_to, timestep = tmp$timestep))
}

# A function to extract ALL dates from .nc-files.
extractAllDatesNc <- function(path_to_nc, nc_flag) {
  
  ordname <- cmsafops::get_basename(path_to_nc)
  ordpath <- dirname(path_to_nc)
  
  if (identical(path_to_nc, character(0))) {
    stop(paste0("No infile!", var))
  }
  
  fileslist <- list.files(ordpath, full.names = TRUE)
  pattern <- "[^\\/]+(\\.nc)$" # regular exp. to extract filenames
  
  result.fileslist <- NULL
  for(i in 1:length(fileslist)){
    regex <- regmatches(fileslist[i], regexpr(pattern, fileslist[i]))
    if(!is.null(regex))
      result.fileslist <- append(result.fileslist, regex)
    regex <- NULL
  }
  result.fileslist <- sort(result.fileslist)
  
  timestep <- cmsafops::calc_timestepNc(result.fileslist, ordpath)
  
  # # Timestep HAS TO BE RELEVANT FOR SOMETHING! FIND THAT OUT!!
  # timestep <- substr(result.fileslist[1], 4, 4)
  allDates <- cmsafops::calc_allDatesNc(result.fileslist, ordpath)
  
  # allDates <- as.character(substr(result.fileslist, 6, 13))
  
  return(list(allDates = as.Date(allDates, "%Y%m%d"), timestep = timestep))
}

# A function to extract start and end dates of NetCDF files
extractDateRangeNc <- function(path_to_nc, nc_flag) {
  tmp <- extractAllDatesNc(path_to_nc, nc_flag = nc_flag)
  
  # Select earliest date from the files.
  date_from <- min(tmp$allDates)
  date_to   <- max(tmp$allDates)
  
  return(list(date_from = date_from, date_to = date_to, timestep = tmp$timestep))
}

# Function for OS-Independently choosing a directory
choose_directory <- function(caption = "Select data directory") {
  if (exists("utils::choose.dir") || exists("choose.dir")) {
    utils::choose.dir(caption = caption)
  } else {
    tcltk::tk_choose.dir(caption = caption)
  }
}

# Validate an .nc URL
# Parameters
# x: a string containing a URL to validate whether it leads to a .nc file
# Value
# -1 if cannot connect to the URL
# TRUE if URL appears to lead to a .nc file and FALSE if not.
# Details
# It is suggested to use this check only if ncdf4::nc_open() fails.
# Some valid .nc URLs do not return the "application/x-netcdf" content-type.
# An additional proxy check requiring a "text" or "application/octet-stream" content-type 
# and ".nc" appearing in the URL is used to ensure these URLs are considered valid.
# However, this may lead to some invalid URLs returning TRUE, 
# which will be detected later in the app.
valid_nc_url <- function(x) {
  con_type <- ""
  try({
    url_head <- httr::HEAD(x)
    con_type <- httr::headers(url_head)[["content-type"]]
    stat_code <- as.character(httr::status_code(url_head))
  })
  # If the content type is blank or the status code begins with 4 e.g. 404 
  # then it's likely the URL is invalid.
  if (con_type == "" || startsWith(stat_code, "4")) return(-1)
  else if (con_type %in% c("application/x-netcdf", "application/x-netcdf4")) return(TRUE)
  else {
    # Many URL which lead to NetCDF file e.g. links from THREDDS servers,
    # do not have the NetCDF content type, hence an additional check is needed.
    # These often have a "text" content type.
    # Some NetCDF files are also coded as "application/octet-stream" which is like "unknown" or "generic"
    return((startsWith(con_type, "text/plain") || startsWith(con_type, "text/html") || con_type == "application/octet-stream") && grepl(".nc", x))
  }
}

# Strips suffix of .nc URL to get base .nc URL
# e.g. by removing "dataset.html" or "dataset.xml" at the end of the URL provided by a user
base_ncss_url <- function(x) {
  if (!endsWith(x, ".nc")) {
    x <- gsub(pattern = "([^/]+$)", replacement = "", x)
    x <- gsub(pattern = "(\\/+$)", replacement = "", x)
    x
  } else x
}

# Gets the data description (XML file) from a NetCDF Subset Service (NCSS) URL.
# NULL is returned for invalid URLs.
# The data description is returned as a list constructed by xml2::as_list()
ncss_data_description <- function(x) {
  x <- base_ncss_url(x)
  # If the URL does not end in .nc then it will not be an ncss URL
  if (!endsWith(x, ".nc")) return(NULL)
  x <- paste0(x, "/dataset.xml")
  res <- try(xml2::read_xml(x))
  # If this fails then URL is not an ncss URL or no connection
  if (class(res) == "try-error") return(NULL)
  res <- xml2::as_list(res)
  res
}

# Constructs a query URL from an NCSS nc file.
# This is used to download a subset defined in panel_prepare_ncss_url_subset
construct_ncss_url <- function(base_url, var, north, west, east, south, h_stride = 1, time_start, time_end, time_stide = 1, accept = "netcdf") {
  if (missing(var)) stop("var must be supplied.")
  n_dir <- sum(!missing(north), !missing(west), !missing(east), !missing(south))
  if (n_dir > 0 & n_dir < 4) stop("All four lat/lon bounds must be supplied, or none for the full range.")
  if (missing(time_start) || missing(time_end)) stop("time_start and time_end must be supplied.")
  
  colon <- "%3A"
  q_url <- base_url
  q_url <- paste0(q_url, "?var=", var, "&")
  if (n_dir == 4) {
    q_url <- paste0(q_url, "north=", north, "&")
    q_url <- paste0(q_url, "west=", west, "&")
    q_url <- paste0(q_url, "east=", east, "&")
    q_url <- paste0(q_url, "south=", south, "&")
  }
  # This assumes time_start and time_end are "Date" types without time components
  # TODO add option for time_start and time_end to be different classes
  time_start <- paste0(time_start, "T", "00", colon, "00", colon, "00", "Z")
  time_end <- paste0(time_end, "T", "23", colon, "59", colon, "59", "Z")
  q_url <- paste0(q_url, "time_start=", time_start, "&")
  q_url <- paste0(q_url, "time_end=", time_end, "&")
  q_url <- paste0(q_url, "timeStride=", time_stide, "&")
  
  q_url <- paste0(q_url, "accept=", accept)
  q_url
}

months_list <- c("January", "February", "March", "April", "May", "June",
                 "July", "August", "September", "October", "November", "December")

# Constructs a list of query URLs from an NCSS nc file to extract a range of months for each year.
# This is used to download a subset defined in panel_prepare_ncss_url_subset
construct_ncss_url_month_extract <- function(base_url, var, north, west, east, south, h_stride = 1, month_start, month_end, year_start, year_end, accept = "netcdf") {
  month_min <- match(month_start, months_list)
  month_max <- match(month_end, months_list)
  month_max_next <- ifelse(month_max == 12, 1, month_max + 1)
  years <- year_start:year_end
  urls <- vector("character", length(years))
  for(i in seq_along(years)) {
    y_min <- years[i]
    y_max <- ifelse(month_min <= month_max, y_min, y_min + 1)
    time_start <- as.Date(paste(y_min, month_min, "1"), format = "%Y %m %d")
    # Get the first day of the next month and subtract 1 to get last day of month_max
    if (month_max == 12) time_end <- as.Date(paste(y_max + 1, month_max_next, "1"), format = "%Y %m %d")
    else time_end <- as.Date(paste(y_max, month_max_next, "1"), format = "%Y %m %d")
    time_end <- time_end - 1
    urls[i] <- construct_ncss_url(base_url = base_url, var = var, 
                                  north = north, west = west, east = east, south = south, 
                                  h_stride = h_stride,
                                  time_start, time_end, accept = "netcdf")
  }
  return(urls)
}
function(input, output, session) {
  #### Preparation and session set up ####
  # TODO: Setting the maximum request size. WARNING: NOT SURE WHAT'S A GOOD VALUE FOR THIS
  # FOR NOW SETTING TO 2.5 GB, as this exceeds the largest test data.
  options(shiny.maxRequestSize = 2500 * 1024^2)

  # Check if is running locally or on remote server
  # Variable can be found in global.R
  if (isRunningLocally) {
    shinyjs::show("tarFileLocal")
    shinyjs::show("ncFileLocal")
    shinyjs::show("or_prepare")
    shinyjs::show("ncURL")
    shinyjs::show("or_prepare2")
    shinyjs::show("ncFileLocal_analyze")
    shinyjs::show("ncFileLocal_visualize")
    shinyjs::show("shapefileLocal")

    # Let user be able to modify the output directory.
    shinyjs::show("modify_userDir")
    updateActionButton(inputId = "nc_url_download", label = "Download this file")
    updateActionButton(inputId = "ncss_subset_download", label = "Download this subset")
  } else {
    shinyjs::show("tarFileRemote")
    shinyjs::show("ncFileRemote")
    shinyjs::show("or_prepare")
    shinyjs::show("ncURL")
    shinyjs::show("or_prepare2")
    shinyjs::show("ncFileRemote_analyze")
    shinyjs::show("ncFileRemote_visualize")
    shinyjs::show("shapefileRemote")

    # Let user be able to download the output directory.
    shinyjs::show("downloader")
    
    updateActionButton(inputId = "nc_url_download", label = "Download to server")
    updateActionButton(inputId = "ncss_subset_download", label = "Download subset to server")
  }

  dir.create(config_directory, showWarnings = FALSE)

  if (file.exists(config_filepath)) {
    # Does user dir exist in config file?
    config_lines <- try(readLines(config_filepath))
  } else {
    config_lines <- ""
  }

  # Save user dir as a global variable.
  userDir <<- ""
  outputDir <<- ""
  action_userDir_change <- reactiveVal(0)

  # Number of remote files created by the user.
  # This is used to inform the user of any created files before exiting.
  n_remote_files <- reactiveVal(0)
  
  # 'Unique' session name
  # session$token is the recommended unique identifier
  # timestamps should be avoided in case of multiple users accessing instantaneously.
  sessionName <- session$token

  videoDir <- reactiveVal(file.path(getwd(), "www", "video"))
  observe({
    if (dir.exists(videoDir())) {
      unlink(videoDir(), recursive = TRUE, force = TRUE)
    }
  })

  # Compare data
  list_compare_data <<- list()
  
  # Merging nc-files (filetypes that can be merge)
  nc.merge.filetypes <<- c("AC_SAF", "ECMWF", "ERA5", "H_SAF", "LSA_SAF", "LSASAF_CLIMA", "OSI_SAF")
  
  #### Reactive values ####
  # Reactive value for tar-file-path. (update action if file stays the same on new upload)
  tar_path <- reactiveVal()
  tar_path_action <- reactiveVal(0)
  
  # Reactive value for nc-file-path.
  nc_path <- reactiveVal("")
  nc_path_action <- reactiveVal(0)
  
  # Reactive value for the URL and data description of an NCSS .nc URL
  ncss_url <- reactiveVal(NULL)
  ncss_url_data_desc <- reactiveVal(NULL)
  
  # Reactive value set after untaring files
  untarVals <- reactiveVal()

  # Reactive value for date range
  dateRange_prep <- reactiveVal()
  
  # Reactive value for date range .nc-files selection
  dateRange_prep_nc <- reactiveVal()

  # Reactive values for biggest possible spatial range
  spatialRange <- reactiveValues()
  
  # Similar to spatialRange but for NCSS URL subset.
  spatialRange_ncss <- reactiveValues()

  # Reactive value for timestep
  timestep <- reactiveVal()
  timestep_c <- reactiveVal()

  #Reactive value for maximum level
  max_level <- reactiveVal()

  # Reactive value for dimensions
  dimensions <- reactiveVal()

  # Reactive value for a path to the aux file.
  auxFilePath <- reactiveVal()
  globalAuxFilePath <- reactiveVal()

  # Reactive value for using level or not.
  usingLevel <- reactiveVal(FALSE)

  # Reactive value for output file path (nc file)
  outputFilepath <- reactiveVal()

  # Reactive value for output file nc object
  # An alternative to outputFilepath(), particularly for URL paths
  # to increase efficiency by avoiding repeated calls ncdf4::nc_open() on the URL
  outputFilenc <- reactiveVal(NULL)
  
  # Reactive value for the nc file to be used in analyze. (update action if file stays the same on new upload)
  nc_path_analyze <- reactiveVal()
  nc_path_analyze_action <- reactiveVal(0)

  # Similar to outputFilenc(), reactive value for the nc object to be used in analyze
  nc_object_analyze <- reactiveVal(NULL)
  
  # Reactive value for which variable is used
  var_used <- reactiveVal()

  # Reactive value for current Operator Option
  currentOperatorOption <- reactiveVal()
  currentOperatorValue <- reactiveVal()

  chosen_latPoints <- reactiveVal(c())
  chosen_lonPoints <- reactiveVal(c())

  # Reactive value for chosen operators + a simulated reactive value.
  operatorDataFrame <<- data.frame()
  operatorDataFrameAction <- reactiveVal(0)

  # Repeat message on file loss (remote case only)
  repeatWarning <- reactiveVal(TRUE)

  # Second nc file for operators
  second_infile <- reactiveVal()
  
  # Operator Input
  operatorInput_value <- reactiveVal("")
  
  # global variable for plot type 1d
  plot_type_1d <<- ""
  
  # global variable for plot type 2d
  plot_type_2d <<- ""
  
  # compare data: date range
  start_date_reac <- reactiveVal()
  end_date_reac <- reactiveVal()
  
  # Compare data: save the clicked plots
  checkboxCompareData <- reactiveVal(0)   # Analyze step
  checkboxCompareData_dropdown <- reactiveVal(0)   # Save clicked plot in dropdown in visualize step
  two_files_compare_data_vis <- reactiveVal(0) # Save the number of files to plot (O: one file or 1: two files)

  # Reactive value for the nc file to be used in analyze. (update action if file stays the same on new upload)
  nc_path_visualize <- reactiveVal()
  nc_path_visualize_2 <- reactiveVal("")
  actionVisualize <- reactiveVal(0)
  
  # Similar to outputFilenc(), reactive value for the nc object to be used in visualize
  nc_object_visualize <- reactiveVal(NULL)
  
  # Reactive value for the csv / RData data to be used in visualize (compare data)
  station_data_compare <- reactiveVal(0)
  
  # save cmsaf.stats mode
  cmsaf_stats_enable <- reactiveVal(0)

  # Image path for monitor climate
  image_path_visualize <- reactiveVal()
  actionVisualizeMonitorClimate <- reactiveVal(0)

  # Shape file path
  shapeFile_path <- reactiveVal()
  shapeFile_path_action <- reactiveVal(0)

  # Storing the polygons.
  region_data <- reactiveVal()

  # Instat file path
  instat_path <- reactiveVal()
  instat_path_action <- reactiveVal(0)
  
  # Reactive Value for all visualize variables
  visualizeVariables <- reactiveVal()
  visualizeDataTimestep <- reactiveVal()
  visualizeDataMin <- reactiveVal()
  visualizeDataMax <- reactiveVal()
  reversedDimensions <- reactiveValues(transpose = FALSE, latReverse = FALSE, lonReverse = FALSE)

  # Variable to be visualized chosen in modal
  variable_visualize_modal <- reactiveVal()
  action_visualize_post_modal <- reactiveVal(0)
  
  second_variable_analyze <- reactiveVal(0)
  infile2_analyze_value <- reactiveVal("")
  
  # save file names for plotting in compare data step
  analyze_file1_plot <- reactiveVal("")
  analyze_file2_plot <- reactiveVal("")
  
  # prepare options
  option_prepare_ui <- reactiveVal(0)

  # Reactive values for coordinate bounds in visualize
  lon_bounds <- reactiveVal()
  lat_bounds <- reactiveVal()
  ihsf       <- reactiveVal()

  # Longitute, latitute location vectors (of own locations added in options)
  lon_loc_vec  <- reactiveVal()
  lat_loc_vec  <- reactiveVal()
  name_loc_vec <- reactiveVal()

  # Png file location
  png_path <- reactiveVal()

  # Reactive values for imagewidth and imageheight
  imageheight <- reactiveVal(round(image_def * (2 / 3)))
  imagewidth  <- reactiveVal(image_def)
  lat_lon_trigger <- reactiveVal(0)

  # Reactive value to determine whether this was the first plot
  readyToPlot <- reactiveVal(FALSE)

  # Set these values to one as soon as valid.
  userDirValid <- reactiveVal(0)
  resolutionValid <- reactiveVal(0)

  # isRunningLocally can be found in global.R
  # Find/Create user directory.
  if (isRunningLocally) {
    # Case of local host!

    # Read lines of file.
    for (line in config_lines) {
      if (startsWith(line, "USRWDIR=")) {
        if (nchar(line) > 8) {
          userDir <<- substring(line, 9)
          userDir <<- file.path(userDir, "output")
          outputDir <<- userDir
          # Create the output directory.
          if (!dir.exists(userDir)) {
            cat("WARNING!","\n")
            cat(paste(userDir," does not exist and will be created!", sep = ""),"\n")
            cat("You might check the user directory in ~/CMSAF-Toolbox/config.conf","\n")
            dir.create(userDir)
          }
          setwd(userDir)
        }
      }
    }

    # Set flags and counts for girdInfo and userDir
    gridSupportFile <- file.path(config_directory, "myGrid.txt")
    noGridInfoFlag <<- !file.exists(gridSupportFile)
    noUserDirFlag <<- (nchar(userDir) == 0 || !dir.exists(userDir))

    checkSum <<- 0
    if (noUserDirFlag || noGridInfoFlag) {
      # Check sum = 1 unless both files are missing
      checkSum <<- 1
      if (noUserDirFlag && noGridInfoFlag) {
        checkSum <<- 2

        showModal(modalDialog(
          h4("Please select a directory where created output will be saved."),
          br(),
          actionButton("userDirButton", "Choose a user directory."),
          verbatimTextOutput("selectedUserDirectory"),
          hr(),
          h4("Please specify a grid resolution."),
          h5("The chosen value must be between 0.01 and 89.99.
              Depending on your browser a comma or a point will be accepted as decimal seperator."),
          numericInput("gridResolution", "Resolution", value = 0.05, step = 0.01, min = 0.01, max = 89.99),
          title = "We need your help.",
          size = "l",
          footer = shinyjs::disabled(actionButton("Submit", "Submit"))
        ))
      } else if (noUserDirFlag) {
        showModal(modalDialog(
          h4("Please select a directory where we can save your created output."),
          br(),
          actionButton("userDirButton", "Choose a user directory."),
          verbatimTextOutput("selectedUserDirectory"),
          title = "We need your help.",
          size = "l",
          footer = shinyjs::disabled(actionButton("Submit", "Submit"))
        ))
      } else {
        showModal(modalDialog(
          h4("Please specify a grid resolution."),
          h5("The chosen value must be between 0.01 and 89.99.
              Depending on your browser a comma or a point will be accepted as decimal seperator."),
          numericInput("gridResolution", "Resolution", value = 0.05, step = 0.01, min = 0.01, max = 89.99),
          title = "We need your help.",
          size = "l",
          footer = shinyjs::disabled(actionButton("Submit", "Submit"))
        ))
      }
    }
  } else {
    # Case of remote host!
	dataDir <- file.path("output")
    dataDir <- file.path(dirname(dataDir), "output")

    # Remember the user directory and tear it down in destructor.
    if (!dir.exists("output")) {
      warning("Creating user directory at '", getwd(), "/output'.")
      dir.create("output")
    }
    userDir   <<- file.path("output", sessionName)
    outputDir <<- userDir

    dirFlag <- FALSE
    # If by any chance this directory has existed give warning message.
    # Note: This should now never happen through use of session$token
    # but sensible to keep as a check.
    if (dir.exists(userDir)) {
      dirFlag <- TRUE
      warning(paste0("User directory: ", userDir, " already exists. APP WILL STOP!"))
    } else {
      dir.create(userDir)
    }
  }

  # Observing when user submits initial values for config and/or myGrid.txt file.
  observeEvent(input$Submit, {
    if (noUserDirFlag) {
      # Overwrite config file (config filepath is found in global.R)
      if (file.exists(config_filepath)) {
        file.remove(config_filepath)
      }
      file.create(config_filepath)

      # Save  for next session.
      writeLines(paste0("USRWDIR=", userDir), config_filepath)

      userDir   <<- file.path(userDir, "output")
      outputDir <<- userDir
      action_userDir_change(action_userDir_change() + 1)

      if (!dir.exists(userDir)) {
        dir.create(userDir)
      }
    }

    if (noGridInfoFlag) {
      file.create(gridSupportFile)

      gridXsize <- 360 / input$gridResolution + 1
      gridYsize <- 180 / input$gridResolution + 1

      gridLines <- c("gridtype = lonlat",
                     paste0("xsize = ", gridXsize),
                     paste0("ysize = ", gridYsize),
                     "xfirst = -180",
                     paste0("xinc = ", input$gridResolution),
                     "yfirst = -90",
                     paste0("yinc = ", input$gridResolution))

      writeLines(gridLines, gridSupportFile)
    }

    removeModal()
  })

  # Observe when user gives output directory.
  observeEvent(input$userDirButton, {
    userDirValid(0)
    shinyjs::disable("userDirButton")
    try(userDir <<- choose_directory())
    if (dir.exists(userDir)) {
      output$selectedUserDirectory <- renderText({
        userDir
      })
      userDirValid(1)
      shinyjs::show("selectedUserDirectory")
      setwd(userDir)
	    writeLines(paste0("USRWDIR=", userDir), config_filepath)
    } else {
      shinyjs::hide("selectedUserDirectory")
    }
    shinyjs::enable("userDirButton")
  })

  # Observe when user gives grid resolution.
  observeEvent(input$gridResolution, {
    resolutionValid(0)
    req(input$gridResolution)
    if (input$gridResolution >= 0.01 && input$gridResolution <= 89.99) {
      resolutionValid(1)
    }
  })

  # Allow submitting the initial modal page, as soon as check sum fullfilled, i.e. all required inputs are valid.
  observe({
    req(isRunningLocally)
    if (resolutionValid() + userDirValid() == checkSum) {
      shinyjs::enable("Submit")
    } else {
      shinyjs::disable("Submit")
    }
  })

  observeEvent(input$modify_userDir, {
    showModal(modalDialog(
      h4("Your current user directory is located at:"),
      tags$strong(dirname(userDir)),
      h5("A changed user directory will be visible with the next start of the CM SAF R Toolbox."),
      h5("You can check and change the user directory in ~/CMSAF-Toolbox/config.conf."),
      br(),
      actionButton("userDirButton", "Change user directory."),
      title = "User directory information.",
      size = "l"
    ))
  })

  observe({
    # Trigger every time this changes
    c(action_userDir_change())
    output$prepareString <- renderUI({
      # Can be found in global.R
      if (isRunningLocally) {
        # Local host prepare string dependent on userDir
        tags$div(h2("Prepare"),
                 tags$p("Please select a TAR file", tags$strong("(.tar)"), ", a NetCDF file", tags$strong("(.nc)"), " or a NetCDF URL to start the preparation"),
                 tags$p("of your data. This is the first step after you downloaded your ordered tar-file(s) or NetCDF files or obtained a direct URL."),
                 tags$p("For NetCDF files, you only need to select the first file and the others are selected automatically."),
                 br(),
                 tags$p("This application will help you to extract and merge the data."),
                 tags$p("In addition, you can select a time range and region from your data."),
                 br(),
                 tags$p("If you choose the option to 'just merge' the data files, make sure that grid"),
                 tags$p("and variables are matching. Files are automatically chosen by the pattern of"),
                 tags$p("the first four characters of the file names."),
                 br(),
                 tags$p("Finally, a NetCDF file will be created for you. You can find it in the output directory"),
                 tags$p("located at ", tags$strong(dirname(userDir))),
                 br(),
                 tags$p("The app guides through all steps."))
      } else {
        tags$div(h2("Prepare"),
                 tags$p("Please select a TAR file", tags$strong("(.tar)"), "or a NetCDF file", tags$strong("(.nc)"), " to start the preparation."),
                 tags$p("of your data. This is the first step after you downloaded your ordered tar-file(s)."),
                 tags$p("For NetCDF files, you only need to select the first file and the others are selected automatically."),
                 br(),
                 tags$p("This application will help you to extract and merge the data."),
                 tags$p("In addition, you can select a time range and region from your data."),
                 br(),
                 tags$p("If you choose the option to 'just merge' the data files, make sure that grid"),
                 tags$p("and variables are matching. Files are automatically chosen by the pattern of"),
                 tags$p("the first four characters of the file names."),
                 br(),
                 tags$p("Finally, a NetCDF file will be created for you."),
                 tags$p(tags$strong("Make sure to download your session files before closing this application.")),
                 br(),
                 tags$p("The app guides through all steps."))
      }
    })
  })

  # Going to home screen.
  observeEvent(input$homeimg, {
    shinyjs::hide("panel_content")
    shinyjs::show("panel_home", anim = TRUE, animType = "fade")
  })

  observeEvent(c(input$prepare, input$analyze, input$visualize), {
    shinyjs::hide("panel_home")
    shinyjs::show("panel_content", anim = TRUE, animType = "fade")
  }, ignoreInit = TRUE)

  #### Observing Uploading Events ####
  #### Updating paths ####
  # Modal for wrong file format called with type argument (.tar, .nc, .shp, .RData).
  wrong_file_modal <- function(type) {
    showModal(modalDialog(
      h4(paste("Wrong file format. Please choose",
               type,
               "file to continue.")),
      title = "Warning!",
      size = "m"
    ))
  }

  # Updating the path to the tar file. (local)
  observeEvent(input$tarFileLocal, {
    shinyjs::disable("tarFileLocal")
    res <- try(tar_path(file.choose(new = TRUE)))
    if (class(res) != "try-error") {
      #for (path in tar_path()) {
      if (!endsWith(tar_path(), ".tar")) {
        isolate(tar_path(""))
        wrong_file_modal(".tar")
      } else {
        tar_path_action(tar_path_action() + 1)
      }
      #}
    }
    shinyjs::enable("tarFileLocal")
  }, ignoreInit = TRUE)
  
  # prepare choose .nc-files button
  observeEvent(input$ncFileLocal, {
    shinyjs::disable("ncFileLocal")
    res <- try(nc_path(file.choose(new = TRUE)))
    if (class(res) != "try-error") {
      if (!endsWith(nc_path(), ".nc")) {
        isolate(nc_path(""))
        wrong_file_modal(".nc")
      } else {
        nc_path_action(nc_path_action() + 1)
      }
    }
    shinyjs::enable("ncFileLocal")
  }, ignoreInit = TRUE)

  # Prepare enter .nc file from URL button. (local and remote)
  observeEvent(input$ncURL, {
    shinyjs::hide(id = "panel_prepareGo")
    shinyjs::show(id = "panel_prepare_nc_url", anim = TRUE, animType = "fade")
  }, ignoreInit = TRUE)
  
  # Prepare check .nc URL button
  observeEvent(input$nc_url_text, {
    shinyjs::toggleState("nc_url_connect", input$nc_url_text != "")
    output$nc_url_valid_message <- renderText({""})
    shinyjs::hide(id = "nc_url_file_info")
    shinyjs::hide(id = "nc_url_download")
    shinyjs::hide(id = "nc_url_subset")
    shinyjs::hide(id = "or_prepare3")
    shinyjs::hide(id = "nc_url_analyze")
    shinyjs::hide(id = "or_prepare4")
    shinyjs::hide(id = "nc_url_visualize")
    shinyjs::hide(id = "nc_url_download_analyze_or_visualise")
  }, ignoreInit = TRUE)
  
  # Set .nc URL validation and connection text
  observeEvent(input$nc_url_connect, {
    shinyjs::disable("panel_prepare_nc_url")
    shinyjs::show("spinner_prepare_nc_url_connect", anim = TRUE, animType = "fade")
    user_url <- input$nc_url_text
    if (endsWith(user_url, "dataset.html") || endsWith(user_url, "dataset.xml")) {
      ncss_url(base_ncss_url(user_url))
      ncss_url_data_desc(ncss_data_description(ncss_url()))
      if (!is.null(ncss_url_data_desc())) {
        shinyjs::show(id = "nc_url_subset")
        output$nc_url_valid_message <- renderText({
          "<span style='color:green'>Valid NetCDF (.nc) URL for subsetting selection.</span>"
        })
      } else {
        output$nc_url_valid_message <- renderText({
          "<span style='color:red'>URL does not appear to lead to a NetCDF (.nc) file or cannot access URL. Please check the URL or your connection and try again.</span>"
        })
        shinyjs::hide(id = "nc_url_subset")
      }
    } else {
      nc <- tryCatch(ncdf4::nc_open(user_url),
                     error = function(e) return(NULL))
      if (!is.null(nc)) valid_url <- TRUE
      else valid_url <- valid_nc_url(user_url)
      output$nc_url_valid_message <- renderText({
        if (valid_url == -1) {
          mes <- "<span style='color:red'>Cannot access URL. Check the URL is correct"
          if (isRunningLocally) {
            mes <- paste(mes, "and your internet connection")
          }
          return(paste0(mes, " and try again.</span>"))
        } else if (valid_url) {
          return("<span style='color:green'>Valid NetCDF (.nc) URL</span>")
        } else {
          return("<span style='color:red'>URL does not appear to lead to a NetCDF (.nc) file. Please check the URL and try again.</span>")
        }
      })
      if (isTRUE(valid_url)) {
        shinyjs::show(id = "nc_url_download")
        if (!is.null(nc)) {
          output$ncurlShortInfo <- renderPrint({
            cmsafops::ncinfo(nc = nc)
          })
          outputFilepath(user_url)
          outputFilenc(nc)
          shinyjs::show(id = "nc_url_file_info")
          shinyjs::show(id = "or_prepare3")
          shinyjs::show(id = "nc_url_analyze")
          shinyjs::show(id = "or_prepare4")
          shinyjs::show(id = "nc_url_visualize")
        } else {
          outputFilenc(NULL)
          shinyjs::hide(id = "nc_url_file_info")
          shinyjs::hide(id = "or_prepare3")
          shinyjs::hide(id = "nc_url_analyze")
          shinyjs::hide(id = "or_prepare4")
          shinyjs::hide(id = "nc_url_visualize")
        }
      } else {
        shinyjs::hide(id = "nc_url_download")
      }
    }
    shinyjs::hide("spinner_prepare_nc_url_connect")
    shinyjs::enable("panel_prepare_nc_url")
  }, ignoreInit = TRUE)
  
  # Download .nc URL
  observeEvent(input$nc_url_download, {
    outputFilepath(NULL)
    outputFilenc(NULL)
    shinyjs::disable("panel_prepare_nc_url")
    shinyjs::show("spinner_prepare_nc_url_download", anim = TRUE, animType = "fade")
    # Try to get the base name from the URL
    b <- try(cmsafops::get_basename(input$nc_url_text))
    # However, some URLs are too long e.g. from THREDDS servers, and don't return a
    # base name. Hence, a default name "url_download" is used instead.
    # This could be replaced by something else derived from the URL
    # e.g. first and last few characters?
    if (class(b) == "try-error") b <- "url_download"
    # The timestamp is appended to the file name to ensure the file is unique.
    url_file <- file.path(userDir, paste0(format(Sys.time(), "%Y%m%d_%H%M%S_"), b))
    # The base name may not finish with ".nc" so this needs to be added.
    if (!endsWith(url_file, ".nc")) url_file <- paste0(url_file, ".nc")
    res <- try(utils::download.file(input$nc_url_text, url_file, method = "auto", mode = "wb"))
    
    shinyjs::hide("spinner_prepare_nc_url_download")
    shinyjs::enable("panel_prepare_nc_url")
    if (class(res) != "try-error" && res == 0) {
      shinyjs::hide(id = "nc_url_download")
      outputFilepath(url_file)
      output$ncurlShortInfo <- renderPrint({
        cmsafops::ncinfo(url_file)
      })
      shinyjs::show(id = "nc_url_file_info")
      shinyjs::show(id = "nc_url_download_analyze_or_visualise")
    } else {
      showModal(modalDialog(
        h4("Something went wrong while downloading the file. Please try again or choose another URL."),
        title = "Error.",
        size = "l"
      ))
    }
  },
  ignoreInit = TRUE
  )
  
  # Set up panel_prepare_ncss_url_subset when nc_url_subset clicked
  observeEvent(input$nc_url_subset, {
    shinyjs::hide("panel_prepare_nc_url")
    shinyjs::show("panel_prepare_ncss_url_subset")
    
    grid_west <- as.numeric(unlist(ncss_url_data_desc()$gridDataset$LatLonBox$west))
    grid_east <- as.numeric(unlist(ncss_url_data_desc()$gridDataset$LatLonBox$east))
    grid_north <- as.numeric(unlist(ncss_url_data_desc()$gridDataset$LatLonBox$north))
    grid_south <- as.numeric(unlist(ncss_url_data_desc()$gridDataset$LatLonBox$south))
    
    # Set spatial range for dynamic plot
    spatialRange_ncss$lat_range <- c(grid_south, grid_north)
    spatialRange_ncss$lon_range  <- c(grid_west, grid_east)
    
    #TODO Determine this from data description
    lon_step <- 0.05
    lat_step <- 0.05
    
    time_min <- as.Date(unlist(ncss_url_data_desc()$gridDataset$TimeSpan$begin))
    time_max <- as.Date(unlist(ncss_url_data_desc()$gridDataset$TimeSpan$end))
    year_min <- as.numeric(format(time_min, "%Y"))
    year_max <- as.numeric(format(time_max, "%Y"))
    
    vars <- c()
    grid_set <- ncss_url_data_desc()$gridDataset$gridSet
    for (i in seq_along(grid_set)) {
      if (names(grid_set)[i] == "grid") {
        vars <- c(vars, attributes(grid_set[[i]])$name)
      }
    }
    vars <- vars[!vars %in% "crs"]
    output$ncss_url_print <- renderText({paste(tags$b(ncss_url()))})
    output$ncss_var_list_ui <- renderUI({
      selectInput(inputId = "ncss_var_list",
                  label = "Select a variable",
                  vars)
    })
    output$ncss_select_region_ui <- renderUI({
      tags$div(id = "ncss_region",
               fluidRow(
                 column(width = 5,
                        numericInput("ncss_lon_min",
                                     label = "Longitude min",
                                     min = grid_west,
                                     max = grid_east,
                                     value = grid_west)
                 ),
                 column(width = 5,
                        numericInput("ncss_lon_max",
                                     label = "Longitude max",
                                     min = grid_west,
                                     max = grid_east,
                                     value = grid_east
                        ))),
               fluidRow(
                 column(width = 5,
                        numericInput("ncss_lat_min",
                                     label = "Latitude min",
                                     min = grid_south,
                                     max = grid_north,
                                     value = grid_south)
                        ),
                 column(width = 5,
                        numericInput("ncss_lat_max",
                                     label = "Latitude max",
                                     min = grid_south,
                                     max = grid_north,
                                     value = grid_north)
                        )
                 
               )
      )
    })
    output$ncss_date_range_ui <- renderUI({
      dateRangeInput(inputId = "ncss_date_range",
                  label = "Please select a date range.",
                  start = time_min,
                  end = time_max,
                  min = time_min,
                  max = time_max)
    })
    output$ncss_year_range_ui <- renderUI({
      fluidRow(
        column(width = 5,
               numericInput("ncss_year_min",
                            label = "Year min",
                            min = year_min,
                            max = year_max,
                            value = year_min)
        ),
        column(width = 5,
               numericInput("ncss_year_max",
                            label = "Year max",
                            min = year_min,
                            max = year_max,
                            value = year_max
               )))
      })
  },
  ignoreInit = TRUE
  )
  
  # Creating a preview plot for the NCSS URL subset.
  output$preview_ncss_subset <- renderPlot({
    req(input$ncss_lon_min)
    req(input$ncss_lon_max)
    req(input$ncss_lat_min)
    req(input$ncss_lat_max)
    
    cmsafvis::render_preview_plot(spatial_lon_range = isolate(spatialRange_ncss$lon_range),
                                  spatial_lat_range = isolate(spatialRange_ncss$lat_range),
                                  lonRange = c(input$ncss_lon_min, input$ncss_lon_max),
                                  latRange = c(input$ncss_lat_min, input$ncss_lat_max))
  })
  
  # Radio buttons for time selection type for subsetting
  observeEvent(input$ncss_time_type, {
    if (input$ncss_time_type == "date_range") {
      shinyjs::show("ncss_date_range_ui")
      shinyjs::hide("ncss_year_range_ui")
      shinyjs::hide("ncss_month_range")
    } else {
      shinyjs::hide("ncss_date_range_ui")
      shinyjs::show("ncss_year_range_ui")
      shinyjs::show("ncss_month_range")
    }
  })
  
  # Downloading a NCSS subset
  observeEvent(input$ncss_subset_download, {
    if (input$ncss_time_type == "date_range") {
      subset_url <- construct_ncss_url(base_url = ncss_url(), var = input$ncss_var_list, 
                                       north = input$ncss_lat_max, west = input$ncss_lon_min, 
                                       east = input$ncss_lon_max, south = input$ncss_lat_min, 
                                       time_start = input$ncss_date_range[1], time_end = input$ncss_date_range[2])
    } else {
      subset_url <- construct_ncss_url_month_extract(base_url = ncss_url(), var = input$ncss_var_list,
                                                     north = input$ncss_lat_max, west = input$ncss_lon_min,
                                                     east = input$ncss_lon_max, south = input$ncss_lat_min,
                                                     month_start = input$ncss_month_from, month_end = input$ncss_month_to, 
                                                     year_start = input$ncss_year_min, year_end = input$ncss_year_max)
    }
    
    # Try to get the base name from the URL
    b <- try(cmsafops::get_basename(ncss_url()))
    if (class(b) == "try-error") b <- "url_download"
    if (endsWith(b, ".nc")) b <- substr(b, 1, nchar(b) - 3)
    b <- paste0(format(Sys.time(), "%Y%m%d_%H%M%S_"), b)
    shinyjs::disable("panel_prepare_ncss_url_subset")
    shinyjs::show("spinner_prepare_ncss_download", anim = TRUE, animType = "fade")
    url_files <- vector("character", length(subset_url))
    for (i in seq_along(subset_url)) {
      # The timestamp is appended to the file name to ensure the file is unique.
      url_files[i] <- file.path(userDir, paste0(b, "_", i))
      # The base name may not finish with ".nc" so this needs to be added.
      if (!endsWith(url_files[i], ".nc")) url_files[i] <- paste0(url_files[i], ".nc")
      
      res <- try(utils::download.file(subset_url[i], url_files[i], method = "auto", mode = "wb"))
      if (class(res) == "try-error" || res != 0) {
        showModal(modalDialog(
          h4("Something went wrong while downloading the file. Please try again or choose another URL."),
          title = "Error.",
          size = "l"
        ))
        break
      }
    }
    if (length(url_files) > 1) {
      url_file_final <- file.path(userDir, paste0(b, "_", "merge.nc"))
      res <- try({
        cmsafops::box_mergetime(var = input$ncss_var_list, path = userDir, pattern = b,
                                outfile = url_file_final, overwrite = TRUE)
      })
      if (!is.null(res)) {
        showModal(modalDialog(
          h4("Something went wrong merging downloaded files. Please try again or choose another URL."),
          title = "Error.",
          size = "l"
        ))
        url_file_final <- NULL
      }
    } else url_file_final <- url_files[1]
    
    shinyjs::hide("spinner_prepare_ncss_download")
    shinyjs::enable("panel_prepare_ncss_url_subset")
    if ((length(url_files) > 1 && is.null(res)) || (class(res) != "try-error" && res == 0)) {
      shinyjs::hide(id = "nc_url_download")
      outputFilepath(url_file_final)
      output$ncssShortInfo <- renderPrint({
        cmsafops::ncinfo(url_file_final)
      })
      shinyjs::hide(id = "panel_prepare_ncss_url_subset")
      shinyjs::show(id = "panel_prepare_ncss_download_info")
    } else {
      showModal(modalDialog(
        h4("Something went wrong while downloading the file. Please try again or choose another URL."),
        title = "Error.",
        size = "l"
      ))
    }
  },
  ignoreInit = TRUE
  )
  
  # Prepare .nc URL for analyze
  observeEvent(input$nc_url_analyze, {
    nc_path_analyze(outputFilepath())
    nc_object_analyze(outputFilenc())
    if (!endsWith(nc_path_analyze(), ".nc") && is.null(nc_object_analyze())) {
      isolate(nc_path_analyze(""))
      wrong_file_modal(".nc")
    } else {
      shinyjs::hide("panel_prepare_nc_url")
      nc_path_analyze_action(nc_path_analyze_action() + 1)
    }
  },
  ignoreInit = TRUE
  )
  
  # Prepare .nc URL for visualize
  observeEvent(input$nc_url_visualize, {
    nc_path_visualize(outputFilepath())
    nc_object_visualize(outputFilenc())
    if (!endsWith(nc_path_visualize(), ".nc") && is.null(nc_object_visualize())) {
      isolate(nc_path_visualize(""))
      wrong_file_modal(".nc")
    } else {
      shinyjs::hide("panel_prepare_nc_url")
      actionVisualize(actionVisualize() + 1)
    }
  },
  ignoreInit = TRUE
  )
  
  # Prepare downloaded .nc URL for analyze
  observeEvent(input$nc_url_download_analyze, {
    nc_path_analyze(outputFilepath())
    isolate(nc_object_analyze(NULL))
    if (!endsWith(nc_path_analyze(), ".nc")) {
      isolate(nc_path_analyze(""))
      wrong_file_modal(".nc")
    } else {
      shinyjs::hide("panel_prepare_nc_url")
      nc_path_analyze_action(nc_path_analyze_action() + 1)
    }
  },
  ignoreInit = TRUE
  )
  
  # Prepare downloaded .nc URL for visualize
  observeEvent(input$nc_url_download_visualize, {
    nc_path_visualize(outputFilepath())
    nc_object_visualize(NULL)
    if (!endsWith(nc_path_visualize(), ".nc") && is.null(nc_object_visualize())) {
      isolate(nc_path_visualize(""))
      wrong_file_modal(".nc")
    } else {
      shinyjs::hide("panel_prepare_nc_url")
      actionVisualize(actionVisualize() + 1)
    }
  },
  ignoreInit = TRUE
  )
  
  # Prepare downloaded .nc URL for analyze
  observeEvent(input$ncss_download_analyze, {
    nc_path_analyze(outputFilepath())
    isolate(nc_object_analyze(NULL))
    if (!endsWith(nc_path_analyze(), ".nc")) {
      isolate(nc_path_analyze(""))
      wrong_file_modal(".nc")
    } else {
      shinyjs::hide("panel_prepare_ncss_download_info")
      nc_path_analyze_action(nc_path_analyze_action() + 1)
    }
  },
  ignoreInit = TRUE
  )
  
  # Prepare downloaded .nc URL for visualize
  observeEvent(input$ncss_download_visualize, {
    nc_path_visualize(outputFilepath())
    nc_object_visualize(NULL)
    if (!endsWith(nc_path_visualize(), ".nc") && is.null(nc_object_visualize())) {
      isolate(nc_path_visualize(""))
      wrong_file_modal(".nc")
    } else {
      shinyjs::hide("panel_prepare_ncss_download_info")
      actionVisualize(actionVisualize() + 1)
    }
  },
  ignoreInit = TRUE
  )
  
  # Prepare downloaded .nc URL for visualize
  observeEvent(input$ncss_info_back, {
    shinyjs::show(id = "panel_prepare_ncss_url_subset")
    shinyjs::hide(id = "panel_prepare_ncss_download_info")
  },
  ignoreInit = TRUE
  )
  
  # Handling remote tar selection.
  shinyFiles::shinyFileChoose(input, 'tarFileRemote', session = session, roots = remoteVolume, filetypes=c('tar'))
    
  observeEvent(input$tarFileRemote, {
    pth <- shinyFiles::parseFilePaths(remoteVolume,input$tarFileRemote)
    req(nrow(pth) > 0)
    req(file.exists(pth$datapath))
    req(endsWith(pth$datapath, ".tar"))
    tar_path( pth$datapath )
    tar_path_action(tar_path_action() + 1)
  })
  
  # Handling remote nc selection.
  shinyFiles::shinyFileChoose(input, 'ncFileRemote', session = session, roots = remoteVolume, filetypes=c('nc'))
  
  observeEvent(input$ncFileRemote, {
    pth <- shinyFiles::parseFilePaths(remoteVolume,input$ncFileRemote)
    req(nrow(pth) > 0)
    req(file.exists(pth$datapath))
    req(endsWith(pth$datapath, ".nc"))
    nc_path( pth$datapath )
    nc_path_action(nc_path_action() + 1)
  })

  # Updating the path to the nc file analyze. (local)
  observeEvent(input$ncFileLocal_analyze, {
    shinyjs::disable("ncFileLocal_analyze")
    shinyjs::disable("useOutputFile_analyze")
    res <- try(nc_path_analyze(file.choose(new = TRUE)))
    isolate(nc_object_analyze(NULL))
    if (class(res) != "try-error") {
      if (!endsWith(nc_path_analyze(), ".nc")) {
        isolate(nc_path_analyze(""))
        wrong_file_modal(".nc")
      } else {
        nc_path_analyze_action(nc_path_analyze_action() + 1)
      }
    }
    shinyjs::enable("ncFileLocal_analyze")
    shinyjs::enable("useOutputFile_analyze")
  }, ignoreInit = TRUE)

  # Use shiny files to handle remote uploading from user directory.
  volumes_output = c("Output" = outputDir, remoteVolume)

  shinyFiles::shinyFileChoose(input, 'ncFileRemote_analyze', session = session, roots = volumes_output, filetypes=c('nc'))

  observeEvent(input$ncFileRemote_analyze, {
    pth <- shinyFiles::parseFilePaths(volumes_output,input$ncFileRemote_analyze)
    req(nrow(pth) > 0)
    req(file.exists(pth$datapath))
    isolate(nc_object_analyze(NULL))
    if (!endsWith(pth$datapath, ".nc")) {
      isolate(nc_path_analyze(""))
      wrong_file_modal(".nc")
    } else {
      nc_path_analyze( pth$datapath )
      nc_path_analyze_action(nc_path_analyze_action() + 1)
    }
  })

  # If user chooses to take generated nc file update nc_path_analyze. (output file)
  observeEvent(input$useOutputFile_analyze, {
    nc_path_analyze(outputFilepath())
    isolate(nc_object_analyze(NULL))
    if (!endsWith(nc_path_analyze(), ".nc")) {
      isolate(nc_path_analyze(""))
      wrong_file_modal(".nc")
    } else {
      nc_path_analyze_action(nc_path_analyze_action() + 1)
    }
  }, ignoreInit = TRUE)

  # Updating the path to the nc file visualize. (local)
  observeEvent(input$ncFileLocal_visualize, {
    shinyjs::disable("ncFileLocal_visualize")
    shinyjs::disable("useOutputFile_visualize")
    res <- try(nc_path_visualize(file.choose(new = TRUE)))
    isolate(nc_object_visualize(NULL))
    if (class(res) != "try-error") {
      if (!endsWith(nc_path_visualize(), ".nc")) {
        isolate(nc_path_visualize(""))
        wrong_file_modal(".nc")
      } else {
        actionVisualize(actionVisualize() + 1)
      }
    }
    shinyjs::enable("ncFileLocal_visualize")
    shinyjs::enable("useOutputFile_visualize")
  }, ignoreInit = TRUE)

  # Observing changes in selected nc file visualize. (remote)
  shinyFiles::shinyFileChoose(input, 'ncFileRemote_visualize', session = session, roots = volumes_output, filetypes=c('nc'))

  observeEvent(input$ncFileRemote_visualize, {
    pth <- shinyFiles::parseFilePaths(volumes_output,input$ncFileRemote_visualize)
    req(nrow(pth) > 0)
    req(file.exists(pth$datapath))
    isolate(nc_object_visualize(NULL))
    if (!endsWith(pth$datapath, ".nc")) {
      isolate(nc_path_visualize(""))
      wrong_file_modal(".nc")
    } else {
      nc_path_visualize( pth$datapath )
      actionVisualize(actionVisualize() + 1)
    }
  })

  # If user chooses to take generated nc file update nc_path_visualize. (output file)
  observeEvent(input$useOutputFile_visualize, {
    nc_path_visualize(outputFilepath())
    if (!endsWith(nc_path_visualize(), ".nc")) {
      isolate(nc_path_visualize(""))
      wrong_file_modal(".nc")
    } else {
      actionVisualize(actionVisualize() + 1)
    }
  }, ignoreInit = TRUE)

  # Updating path to shape file. (local)
  observeEvent(input$shapefileLocal, {
    shinyjs::disable("shapefileLocal")
    res <- try(shapeFile_path(file.choose(new = TRUE)))
    if (class(res) != "try-error") {
      if (!endsWith(shapeFile_path(), ".shp")) {
        isolate(shapeFile_path(""))
        wrong_file_modal(".shp")
      } else {
        shapeFile_path_action(shapeFile_path_action() + 1)
      }
    }
    shinyjs::enable("shapefileLocal")
  }, ignoreInit = TRUE)

  # Observing changes in selected shape file. (remote)
  shinyFiles::shinyFileChoose(input, 'shapefileRemote', session = session, roots = remoteVolume, filetypes=c('shp'))

  observeEvent(input$shapefileRemote, {
    pth <- shinyFiles::parseFilePaths(remoteVolume,input$shapefileRemote)
    req(nrow(pth) > 0)
    req(file.exists(pth$datapath))
    if (!endsWith(pth$datapath, ".shp")) {
      isolate(shapeFile_path(""))
      wrong_file_modal(".shp")
    } else {
      shapeFile_path( pth$datapath )
      shapeFile_path_action(shapeFile_path_action() + 1)
    }
  })

  # Deleting instat file path when removing plot r-instat check box selection
  observeEvent(input$plot_rinstat, {
    if (!input$plot_rinstat) {
      instat_path("")
    }
  })

  # Updating the path to the instat file. (local)
  observeEvent(input$instat_file_local, {
    shinyjs::disable("instat_file_local")
    res <- try(instat_path(file.choose(new = TRUE)))
    if (class(res) != "try-error") {
      if (!endsWith(instat_path(), ".RData") && !endsWith(instat_path(), ".csv")) {
        isolate(instat_path(""))
        wrong_file_modal(".RData")
      } else {
        instat_path_action(instat_path_action() + 1)
      }
    }
    shinyjs::enable("instat_file_local")
  }, ignoreInit = TRUE)

  # Observing changes in selected instat file. (remote)
  shinyFiles::shinyFileChoose(input, 'instat_file_remote', session = session, roots = remoteVolume, filetypes=c('RData', 'csv'))

  observeEvent(input$instat_file_remote, {
    pth <- shinyFiles::parseFilePaths(remoteVolume,input$instat_file_remote)
    req(nrow(pth) > 0)
    req(file.exists(pth$datapath))
    if (!endsWith(pth$datapath, ".RData") && !endsWith(pth$datapath, ".csv")) {
      isolate(instat_path(""))
      wrong_file_modal(".RData")
    } else {
      instat_path( pth$datapath )
      instat_path_action(instat_path_action() + 1)
    }
  })

  resetToPreparePanel <- function() {
    # Clear mem
    rm(list = ls())
    gc()

    # First toggle states of main output panel.
    shinyjs::hide("panel_analyzeGo")
    shinyjs::hide("panel_visualizeGo")
    shinyjs::hide("panel_prepareInput1")
    shinyjs::hide("panel_prepare_nc_url")
    shinyjs::hide("panel_prepare_ncss_url_subset")
    shinyjs::hide("panel_prepare_ncss_download_info")
    shinyjs::hide("panel_prepareInput1Nc")
    shinyjs::hide("panel_prepareInput2")
    shinyjs::reset("panel_prepareInput1")
    shinyjs::reset("panel_prepare_nc_url")
    shinyjs::reset("panel_prepare_ncss_url_subset")
    shinyjs::reset("panel_prepare_ncss_download_info")
    shinyjs::reset("panel_prepareInput1Nc")
    shinyjs::reset("panel_prepareInput2")
    shinyjs::hide("spinner_prepare1")
    shinyjs::hide("spinner_prepare2")
    shinyjs::hide("spinner_prepare3")
    shinyjs::hide("spinner_prepare4")
    shinyjs::hide("spinner_analyze")
    shinyjs::hide("spinner_visualize")
    shinyjs::hide("panel_analyze")
    shinyjs::reset("panel_analyze")

    untarVals(list())

    # Resetting data frame
    operatorDataFrame <<- data.frame()
    operatorDataFrameAction(operatorDataFrameAction() + 1)
    shinyjs::show("panel_prepareGo", anim = TRUE, animType = "fade")
  }

  resetToAnalyzePanel <- function() {
    # Clear mem
    rm(list = ls())
    gc()

    # First toggle states of main output panel.
    shinyjs::hide("panel_prepareGo")
    shinyjs::hide("panel_visualizeGo")
    shinyjs::hide("panel_prepareInput1")
    shinyjs::hide("panel_prepare_nc_url")
    shinyjs::hide("panel_prepare_ncss_url_subset")
    shinyjs::hide("panel_prepare_ncss_download_info")
    shinyjs::hide("panel_prepareInput1Nc")
    shinyjs::hide("panel_prepareInput2")
    shinyjs::reset("panel_prepareInput1")
    shinyjs::reset("panel_prepare_nc_url")
    shinyjs::reset("panel_prepare_ncss_url_subset")
    shinyjs::reset("panel_prepare_ncss_download_info")
    shinyjs::reset("panel_prepareInput1Nc")
    shinyjs::reset("panel_prepareInput2")
    shinyjs::hide("spinner_visualize")
    shinyjs::hide("panel_analyze")
    shinyjs::reset("panel_analyze")
    shinyjs::hide("ncFile_analyze_second_file")
    shinyjs::reset("ncFile_analyze_second_file")
    
    # Resetting path of second file (compare data)
    nc_path_visualize_2("")
    infile2_analyze_value("")
    switchButtonCompare <<- FALSE   # switch button operator dropdown (compare data)
    
    # Resetting data frame
    operatorDataFrame <<- data.frame()
    operatorDataFrameAction(operatorDataFrameAction() + 1)
    shinyjs::show("panel_analyzeGo", anim = TRUE, animType = "fade")
  }

  resetToVisualizePanel <- function() {
    # Clear mem
    rm(list = ls())
    gc()

    # First toggle states of main output panel.
    shinyjs::hide("panel_prepareGo")
    shinyjs::hide("panel_analyzeGo")
    shinyjs::hide("panel_prepareInput1")
    shinyjs::hide("panel_prepare_nc_url")
    shinyjs::hide("panel_prepare_ncss_url_subset")
    shinyjs::hide("panel_prepare_ncss_download_info")
    shinyjs::hide("panel_prepareInput1Nc")
    shinyjs::hide("panel_prepareInput2")
    shinyjs::reset("panel_prepareInput1")
    shinyjs::reset("panel_prepare_nc_url")
    shinyjs::reset("panel_prepare_ncss_url_subset")
    shinyjs::reset("panel_prepare_ncss_download_info")
    shinyjs::reset("panel_prepareInput1Nc")
    shinyjs::reset("panel_prepareInput2")
    shinyjs::hide("panel_analyze")
    shinyjs::reset("panel_analyze")
    shinyjs::hide("spinner_visualize")
    shinyjs::hide("spinner_visualize_compare_data")
    shinyjs::hide("date_range_compare_data")
    shinyjs::hide("ncFile_analyze_second_file")
    shinyjs::hide("visualizePage")
    shinyjs::reset("visualizePage")
    shinyjs::reset("backToSetup")
    shinyjs::reset("myImage_monitorClimate")
    shinyjs::reset("monitorClimate_PNG")
    shinyjs::reset("monitorClimate_MP4")
    shinyjs::hide("dropdown_station_number")
    shinyjs::hide("title_text2")
    shinyjs::hide("subtitle_text2")
    
    readyToPlot(FALSE)
    
    applyOperatorActiv <<- FALSE   # because something went wrong, when apply compare data
    
    # delete temp folder (compare data)
    compare_temp_dir <- file.path(tempdir(), "compare_temp")
    # remove if it exists
    if (dir.exists(compare_temp_dir)) {
      unlink(compare_temp_dir, recursive = TRUE)
    }
    
    # Resetting path of second file (compare data)
    nc_path_visualize_2("")
    switchButtonCompare <<- FALSE   # switch button operator dropdown (compare data)
    shinyjs::hide("operatorInput_dropdown")
    shinyjs::reset("operatorInput_dropdown")
    
    cmsaf_stats_enable(0)
    
    # Resetting reactive variables
    operatorInput_value("")
    two_files_compare_data_vis(0)
    checkboxCompareData_dropdown(0)
    checkboxCompareData(0)
    
    analyze_file1_plot("")
    analyze_file2_plot("")
    
    # reset global variables
    plot_type_1d <<- ""
    plot_type_2d <<- ""

    # Resetting data frame
    operatorDataFrame <<- data.frame()
    operatorDataFrameAction(operatorDataFrameAction() + 1)
    shinyjs::show("panel_visualizeGo")
    shinyjs::show("setupPage", anim = TRUE, animType = "fade")

  }

  # THIS HAD FLAG napp() == 1.
  observeEvent(input$prepare, {
    resetToPreparePanel()
  })

  # THIS HAD FLAG napp() == 2.
  observeEvent(input$analyze, {
    resetToAnalyzePanel()
  })

  # THIS HAD FLAG napp() == 3.
  observeEvent(input$visualize, {
    resetToVisualizePanel()
  })

  #### Handling the scripts ####
  #### PREPARATION ####
  observeEvent({
    tar_path()
    tar_path_action()
  }, {
    # Requirements
    req(tar_path())
    req(tar_path_action())

    # If wrong format alert and stop.
    #for(path in tar_path()) {
    if (!endsWith(tar_path(), ".tar")) {
      isolate(tar_path(""))
      showModal(modalDialog(
        h4("Wrong file format. Please choose .tar file to continue."),
        title = "Warning!",
        size = "m"
      ))
    } else {
      # Show Spinner
      shinyjs::hide(id = "panel_prepareGo")
      shinyjs::show("spinner_prepare1", anim = TRUE, animType = "fade")

      # Extracting date range and lat/lon range from functions
      extractedDates <- extractDateRange(tar_path(), tar_flag = 1)
      timestep(extractedDates$timestep)

      # Rendering date range.
      output$dateRange_ui <- renderUI({
        dateRangeInput(inputId = "dateRange_prepare",
                       label = "Please select a date range to prepare.",
                       start = extractedDates$date_from,
                       end = extractedDates$date_to,
                       min = extractedDates$date_from,
                       max = extractedDates$date_to,
                       startview = "year"
        )
      })
      shinyjs::hide("spinner_prepare1")
      shinyjs::show(id = "panel_prepareInput1", anim = TRUE, animType = "fade")
    }
  })
  
  # Handling .nc-files prepare
  observeEvent({
    nc_path()
    nc_path_action()
  }, {
    # Requirements
    req(nc_path())
    req(nc_path_action())
    
    # If wrong format alert and stop.
    if (!endsWith(nc_path(), ".nc")) {
      isolate(nc_path(""))
      showModal(modalDialog(
        h4("Wrong file format. Please choose .nc file to continue."),
        title = "Warning!",
        size = "m"
      ))
    } else {
      # Show Spinner
      shinyjs::hide(id = "panel_prepareGo")
      shinyjs::show("spinner_prepare1", anim = TRUE, animType = "fade")
      
      # check filetype 
      # c("GOME", "_gri", "z_ca", "era", "h141", "HDF5", "NETCDF4", "ice")
      # filetype.list <- list(ac_saf)
      # check.boolean <- check.ncfiletype()
      # 
      # if(check.boolean){
      #   showModal(modalDialog(
      #     h4("Wrong file format. Please choose .nc file to continue."),
      #     title = "Warning!",
      #     size = "m"
      #   ))
      # }
      
      filname <- cmsafops::get_basename(nc_path())
      filetype <- substr(filname, 1, 4)
      pattern <- substr(filname, 1, 6)
      if(filetype == "GOME"){
        cmsafops::acsaf_box_mergetime(dirname(nc_path()), pattern,file.path(tempdir(),"ac_saf_mergetime.nc"))
        nc_path(file.path(tempdir(),"ac_saf_mergetime.nc"))
      }
      
      # choose variable 
      userOptions <- getUserOptions(nc_path(), claas_flag = 0)
      output$variable_ui_nc <- renderUI({
        vars <- subset(userOptions$variables, !(userOptions$variables %in% c("lat", "lon", "latitude", "longitude","time_bnds", "nb2", "time", "crs")))
        selectInput("variableInput360",
                    "Please choose a variable.",
                    choices = vars)
      })
     
      # Extracting date range and lat/lon range from functions
      extractedDates <- extractDateRangeNc(nc_path(), nc_flag = 1)
      timestep(extractedDates$timestep)

      # Rendering date range.
      output$dateRange_ui_nc <- renderUI({
        dateRangeInput(inputId = "dateRange_prepare_nc",
                       label = "Please select a date range to prepare.",
                       start = extractedDates$date_from,
                       end = extractedDates$date_to,
                       min = extractedDates$date_from,
                       max = extractedDates$date_to,
                       startview = "year"
        )
      })
      shinyjs::hide("spinner_prepare1")
      shinyjs::show(id = "panel_prepareInput1Nc", anim = TRUE, animType = "fade")
    }
  })
  
  # Observing time aggregation checkbox
  observeEvent(input$checkboxInput_aggregate, {
    if(input$checkboxInput_aggregate == TRUE){
        shinyjs::show(id = "operatorGroupsPrepare")
    } else {
      shinyjs::hide(id = "operatorGroupsPrepare")
    }
  })

  observeEvent(input$dateRange_prepare, {
    req(input$dateRange_prepare[1])
    req(input$dateRange_prepare[2])
    shinyjs::enable("untarAndUnzip")
  })
  
  # Observing dateRange_prepare_nc
  observeEvent(input$dateRange_prepare_nc, {
    req(input$dateRange_prepare_nc[1])
    req(input$dateRange_prepare_nc[2])
    shinyjs::enable("applyDateRange")
  })
  
  observeEvent(input$justmerge, {
    req(input$justmerge)
    shinyjs::enable("applyDateRange")
  })

  # Observing upload of aux file.
  observeEvent(input$aux_upload, {
    res <- try(globalAuxFilePath(file.choose(new = TRUE)))
    if (class(res) != "try-error") {
      shiny::removeModal()
    } else {
      showModal(modalDialog(
        h4("Something went wrong while uploading the auxiliary file. Please try again or choose another .tar file."),
        title = "Error.",
        size = "l"
      ))
    }
  })

  # Observing
  observeEvent(input$aux_download, {
    auxfile <- file.path(userDir, "claas3_level2_aux_data.nc")
    res <- tryCatch(utils::download.file("https://public.cmsaf.dwd.de/data/perm/auxilliary_data/claas3_level2_aux_data.nc", auxfile, "auto", mode = "wb"))

    # Download file returns 0 on success.
    if (class(res) != "try-error" && res == 0) {
      globalAuxFilePath(file.path(auxfile))
      shiny::removeModal()
    } else {
      showModal(modalDialog(
        h4("Something went wrong while downloading the auxiliary file. Please try again or choose another .tar file."),
        title = "Error.",
        size = "l"
      ))
    }
  })

  # Observing canceling of aux file choice. Return to prepare
  observeEvent(input$aux_cancel, {
    shiny::removeModal()
    shinyjs::hide("spinner_prepare2")
    resetToPreparePanel()
  })

  # get list of NetCDF files
  getNcList <- function(path_to_nc, nc_flag)
  {
    ordname <- cmsafops::get_basename(path_to_nc)
    ordpath <- dirname(path_to_nc)
    
    if (identical(path_to_nc, character(0))) {
      stop(paste0("No infile!", var))
    }
    
    pattern <- substr(ordname, 1, 4)
    fileslist <- list.files(path = ordpath, pattern = pattern, full.names = TRUE)
    #fileslist <- list.files(ordpath, full.names = TRUE)
    pattern <- "[^\\/]+(\\.nc)$" # regular exp. to extract filenames
    
    result.fileslist <- NULL
    for(i in 1:length(fileslist)){
      regex <- regmatches(fileslist[i], regexpr(pattern, fileslist[i]))
      if(!is.null(regex))
        result.fileslist <- append(result.fileslist, regex)
      regex <- NULL
    }
    result.fileslist <- sort(result.fileslist)
    return(result.fileslist)
  }

  #### Function to calculate date range of .nc-files and give variable names. ####
  ncFilelist_dateRange <- function(path_to_nc, startDate, endDate, timestep, nc_flag = 1) {
    # Get important values.
    ncfilelist_all <- getNcList(path_to_nc = path_to_nc, nc_flag = nc_flag)
    # WARNING: DATES ARE IN SAME FORMAT (INDEPENDENT OF TIMESTEP ==/!= 'm')
    # IN FACT: WE ARE OMITTING TIMESTEP VALUE CAUSE WE DON'T APPEAR TO NEED IT.
    dates <- extractAllDatesNc(path_to_nc, nc_flag = nc_flag)
    dates <- dates$allDates
    
    # So filelist just equals tarlist here?
    filelist <- NULL
    
    dums <- NA
    dume <- NA
    
    if (startDate %in% dates) {
      dums <- which(dates == startDate)
    } else {
      if (startDate < dates[1] & endDate >= dates[1])
        (dums <- 1)
    }
    
    if (endDate %in% dates) {
      dume <- which(dates == endDate)
    } else {
      if (endDate > dates[length(dates)])
        (dume <- length(dates))
    }
    
    dums <- dums[1]
    dume <- dume[length(dume)]
    
    if (!is.na(dums)) {
      start <- dums
      end <- dume
      
      if (length(start) > 1) {
        start <- start[1]
        dums <- start
      }
      if (length(end) > 1) {
        end <- end[length(end)]
        dume <- end
      }
      
      if (dums > dume) {
        start <- dume
        end <- dums
      }
      tarlist <- ncfilelist_all
      tarlist <- sort(tarlist)
      tarlist <- tarlist[which(tarlist %in% ncfilelist_all[start:end])]
      
      filelist <- append(filelist, tarlist)
    }
    
    infile <- filelist[1]
    ordpath_nc <- dirname(path_to_nc)
    
    nc_temp_dir <- file.path(tempdir(), "nc_temp")
    # remove if it exists
    if (dir.exists(nc_temp_dir)) {
      unlink(nc_temp_dir, recursive = TRUE)
    }
    
    # create new nc_temp
    if (!dir.exists(nc_temp_dir)) {
      dir.create(nc_temp_dir)
    }
    
    ordpath <- ordpath_nc
    cmsafops::check.coordinate.system(paste0(ordpath,"/",filelist[1]), nc_temp_dir, input$variableInput360, filelist)
    
    # remove temp-file of ac_saf_mergetime
    if(file.exists(file.path(tempdir(),"ac_saf_mergetime.nc"))){
      file.remove(file.path(tempdir(),"ac_saf_mergetime.nc"))
    }
    
    pattern <- substr(filelist[1], 1, 5)
    
    flistdim <- length(filelist)
    
    if(flistdim > 1)
    {
      cmsafops::box_mergetime(input$variableInput360,
                              path = nc_temp_dir,
                              pattern = pattern,
                              outfile = paste0(nc_temp_dir,"/","merge_",filelist[1]),
                              lon1 = -180,
                              lon2 = 180,
                              lat1 = -90,
                              lat2 = 90,
                              nc34 = 4,
                              overwrite = TRUE)
      if(startDate != endDate){
        cmsafops::selperiod(input$variableInput360,
                            start = startDate,
                            end = endDate,
                            infile = paste0(nc_temp_dir,"/","merge_",filelist[1]),
                            outfile = paste0(nc_temp_dir,"/","final_",filelist[1]),
                            overwrite = TRUE)
        file.remove(paste0(nc_temp_dir,"/","merge_",filelist[1]))
      }else{
        file.rename(paste0(nc_temp_dir,"/","merge_",filelist[1]), paste0(nc_temp_dir,"/","final_",filelist[1]))
      }
    }
    else{
      cmsafops::selperiod(input$variableInput360,
                          start = startDate,
                          end = endDate,
                          infile = paste0(nc_temp_dir,"/", filelist[1]),
                          outfile = paste0(nc_temp_dir,"/","final_",filelist[1]),
                          overwrite = TRUE)
    }
    
    nc_path(paste0(nc_temp_dir,"/",paste0("final_",filelist[1])))
    
    infile <- paste0("final_",filelist[1])
    
    # remove temp-files
    for(i in 1:length(filelist))
    {
      file.remove(paste0(nc_temp_dir,"/",filelist[i]))
    }
    filelist <- c(paste0("final_",filelist[1]))
    
    return(
      list(infile =  file.path(nc_temp_dir, infile),
           claas_flag = 0,
           filelist = filelist)
    )
  }
  
  #### Function to untar and unzip files, and give variable names. ####
  untarFiles <- function(path_to_tar, startDate, endDate, timestep, tar_flag = 1) {
    # Get important values.

    tarlist_all <- getTarList(path_to_tar, tar_flag = tar_flag, includeClaasAux = TRUE)
  
    # WARNING: DATES ARE IN SAME FORMAT (INDEPENDENT OF TIMESTEP ==/!= 'm')
    # IN FACT: WE ARE OMITTING TIMESTEP VALUE CAUSE WE DON'T APPEAR TO NEED IT.
    dates <- extractAllDates(path_to_tar, tar_flag = tar_flag)
    dates <- dates$allDates
    
    # Get claas_flag and strop from tarlist if needed.
    claas_flag <- getClaasAuxFlag(tarlist_all)
    if (claas_flag) {
      tarlist_all <- tarlist_all[tarlist_all != claas_aux]
    }

    if (tar_flag == 0) {
      tar_chunk_size <- 100
    }else{
      tar_chunk_size <- 1000
    }

    # So filelist just equals tarlist here?
    filelist <- NULL

    ordname <- cmsafops::get_basename(path_to_tar)
    ordpath <- dirname(path_to_tar)

    flist <- list.files(ordpath, substr(ordname, 1, 8), full.names = TRUE)


    for (file in flist) {
      if (tar_flag == 1) {
        tarlist <- utils::untar(file, list = TRUE, tar = "internal")
      } else {
        tarlist <- utils::untar(file, list = TRUE)
      }
      
      if (claas_aux %in% tarlist) {
        tarlist <- subset(tarlist, !(tarlist %in% c(claas_aux)))
        claas_flag <- 1
      }
      tarlist <- sort(tarlist)
      
      dums <- NA
      dume <- NA

      if (startDate %in% dates) {
        dums <- which(dates == startDate)
      } else {
        if (startDate < dates[1] & endDate >= dates[1])
          (dums <- 1)
      }

      if (endDate %in% dates) {
        dume <- which(dates == endDate)
      } else {
        if (endDate > dates[length(dates)])
          (dume <- length(dates))
      }

      dums <- dums[1]
      dume <- dume[length(dume)]

      if (!is.na(dums)) {
        start <- dums
        end <- dume

        if (length(start) > 1) {
          start <- start[1]
          dums <- start
        }
        if (length(end) > 1) {
          end <- end[length(end)]
          dume <- end
        }

        if (dums > dume) {
          start <- dume
          end <- dums
        }

        tarlist <- tarlist[which(tarlist %in% tarlist_all[start:end])]
        if (length(tarlist) == 0) next

        filelist <- append(filelist, tarlist)

        if (length(tarlist) > tar_chunk_size) {
          dum <- seq(0, length(tarlist), tar_chunk_size)

          for (j in 1:(length(dum) - 1)) {
            tarlist_alt <- tarlist[(dum[j] + 1):dum[j + 1]]
            if (tar_flag == 1) {
              utils::untar(
                file,
                files = tarlist_alt,
                exdir = ordpath,
                tar = "internal"
              )
            } else {
              utils::untar(
                file,
                files = tarlist_alt,
                exdir = ordpath
              )
            }
          }
          tarlist_alt <- tarlist[(dum[length(dum)] + 1):length(tarlist)]
          if (tar_flag == 1) {
            utils::untar(
              file,
              files = tarlist_alt,
              exdir = ordpath,
              tar = "internal"
            )
          } else {
            utils::untar(
              file,
              files = tarlist_alt,
              exdir = ordpath
            )
          }
        } else {

          if (tar_flag == 1) {
            utils::untar(
              file,
              files = tarlist,
              exdir = ordpath,
              tar = "internal"
            )
          } else {
            utils::untar(
              file,
              files = tarlist,
              exdir = ordpath
            )
          }
        }
      }
    } # end if !is.na(dums)

    # Untar auxiliary data if included
    if (claas_flag == TRUE) {
      if (tar_flag == 1) {
        utils::untar(
          path_to_tar,
          files = claas_aux,
          exdir = ordpath,
          tar = "internal"
        )
      } else {
        utils::untar(path_to_tar,
                     files = claas_aux,
                     exdir = ordpath)
      }
    }

    # Unzip data in case of NetCDF3
    gzcheck <- length(unlist(strsplit(tarlist[1], ".nc")))

    if (gzcheck == 2) {
      for (i in seq_along(filelist)) {
        zipfile <- file.path(ordpath, filelist[i])
        R.utils::gunzip(zipfile, overwrite = TRUE)
      }

      # Get information of first file

      infile <- unlist(strsplit(filelist[1], ".gz"))
    } else {
      infile <- filelist[1]
    }
    return(
      list(infile =  file.path(ordpath, infile),
           claas_flag = claas_flag,
           filelist = filelist)
    )
  }

  # Create modal for

  getUserOptions <- function(infile, claas_flag) {
    id <- ncdf4::nc_open(infile)
    vn <- names(id$var)
    dn <- names(id$dim)
    lon_var <- "lon"
    lat_var <- "lat"

    '%ni%' <- Negate('%in%')

    if ("lon" %ni% dn) {
      if ("longitude" %in% dn) {
        lon_var <- "longitude"
      }
    }

    if ("lat" %ni% dn) {
      if ("latitude" %in% dn) {
        lat_var <- "latitude"
      }
    }

    if (lon_var %in% c(dn, vn)) {
      lon_range <- range(ncdf4::ncvar_get(id, lon_var), na.rm = TRUE)
    }
    if (lat_var %in% c(dn, vn)) {
      lat_range <- range(ncdf4::ncvar_get(id, lat_var), na.rm = TRUE)
    }
    ncdf4::nc_close(id)

    var_default <-
      subset(vn, !(
        vn %in% c(
          "lat",
          "lon",
          "time_bnds",
          "nb2",
          "time",
          "SATID",
          "latitude",
          "longitude",
          "crs"
        )
      ))

    # Get max level.
    max_level <- NA
    for (variable in vn) {
      if (startsWith(variable, "HLW") || startsWith(variable, "HSH")) {
        id <- ncdf4::nc_open(infile)
        max_level <- length(ncdf4::ncvar_get(id, "lev"))
        ncdf4::nc_close(id)
      }
    }

    # Stop if data are in sinusoidal projection
    if ("sinusoidal" %in% vn) {
      showModal(modalDialog(
        h4("Sorry, the CM SAF R Toolbox can not handle data in sinusoidal projection.
            Please use the 'change projection' option during the order process.
            Your NetCDF data have to be on a regular lon-lat grid."),
        title = "Sorry!",
        size = "l"
      ))

      req(FALSE)
      resetToPreparePanel()
    }

    return(list(
      variables = vn,
      dimensions = dn,
      lat_range = lat_range,
      lon_range = lon_range,
      max_level = max_level
    ))
  }

  # When untar button is pressed.
  observeEvent(input$untarAndUnzip, {
    # Require positve click value.
    req(input$untarAndUnzip > 0)

    # Get first of month if timestep == m
    if (timestep() == "m") {
      dateRange_prep(firstOfMonth(input$dateRange_prepare))
    } else {
      dateRange_prep(input$dateRange_prepare)
    }

    # Show spinner
    shinyjs::hide("panel_prepareInput1")
    shinyjs::reset("panel_prepareInput1")
    shinyjs::show("spinner_prepare2", anim = TRUE, animType = "fade")

    untarVals(untarFiles(tar_path(), dateRange_prep()[1], dateRange_prep()[2], timestep(), tar_flag = 1))
  }, ignoreInit = TRUE)
  
  # # When apply date range (nc prepare) button is pressed.
  # observeEvent(input$applyDateRange, {
    # # Require positve click value.
    # req(input$applyDateRange > 0)

    # # Get first of month if timestep == m
    # if (timestep() == "m") {
      # dateRange_prep(firstOfMonth(input$dateRange_prepare_nc))
    # } else {
      # dateRange_prep(input$dateRange_prepare_nc)
    # }
    
    # # Show spinner
    # shinyjs::hide("panel_prepareInput1Nc")
    # shinyjs::reset("panel_prepareInput1Nc")
    # shinyjs::show("spinner_prepare4", anim = TRUE, animType = "fade")
    
    # # From this point on nc and tar files are processed immediately
    # untarVals(ncFilelist_dateRange(nc_path(), dateRange_prep()[1], dateRange_prep()[2], timestep(), nc_flag = 1))
  # }, ignoreInit = TRUE)
  
  
  # Function to create the output
    creatingOutputfile2 <- function(path_to_tar, var) {

    file1   <- cmsafops::get_basename(path_to_tar)
    ordDir  <- dirname(path_to_tar)
	  outfile <- file.path(outputDir, paste0(var, "_mergetime.nc"))

    # box_mergetime
      pattern <- substr(file1, 1, 4)

      cmsafops::box_mergetime(var,
                           path = ordDir,
                           pattern = pattern,
                           outfile = outfile,
                           overwrite = TRUE)
      return(outfile)
  }
  
  
  # When apply date range (nc prepare) button is pressed.
  observeEvent(input$applyDateRange, {
    # Require positve click value.
    req(input$applyDateRange > 0)

	# If just merge checkbox = TRUE
	if (input$justmerge) {
		# Show / hide spinner
		shinyjs::hide("panel_prepareInput1Nc")
		shinyjs::show("spinner_prepare3", anim = TRUE, animType = "fade")

		res <- try(outputFilepath(creatingOutputfile2(nc_path(),
                                                   input$variableInput360)))
    
		if (class(res) == "try-error") {
			showModal(modalDialog(
				h4("An error occured while creating an output file."),
				tags$p(paste0("Message: ", res)),
				title = "Error!",
				size = "m"
			))
		}

		# Variable 'isRunningLocally' can be found in global.R
		if (repeatWarning() && !isRunningLocally) {
			showModal(modalDialog(
				tags$p("A .nc file has been created for you. ",
					"Its contents are temporarily stored in the session folder.",
					"Please downlaod the session folder if you want to save it.",
					"All files will be removed after closing this app!"),
				checkboxInput("noRepeat", "Do not show this message again."),
			title = "Warning to prevent data loss!",
			size = "l"
		))
		}
	
		shinyjs::hide("spinner_prepare3")
		resetToAnalyzePanel()
	} else {

		# Get first of month if timestep == m
		if (timestep() == "m") {
			dateRange_prep(firstOfMonth(input$dateRange_prepare_nc))
		} else {
			dateRange_prep(input$dateRange_prepare_nc)
		}
    
		# Show spinner
		shinyjs::hide("panel_prepareInput1Nc")
		shinyjs::reset("panel_prepareInput1Nc")
		shinyjs::show("spinner_prepare4", anim = TRUE, animType = "fade")
    
		# From this point on nc and tar files are processed immediately
		untarVals(ncFilelist_dateRange(nc_path(), dateRange_prep()[1], dateRange_prep()[2], timestep(), nc_flag = 1))
	
	  }
    }, ignoreInit = TRUE)
  

  # Set all input values for next stage.
  observe({
    # First do aux check
    req(untarVals()$infile)
    req(!is.null(untarVals()$claas_flag))

    shinyjs::hide("panel_prepareInput1Nc")
    shinyjs::reset("panel_prepareInput1Nc")
    
    ordPath <- dirname(untarVals()$infile)

    infile <- untarVals()$infile
    claas_flag <- untarVals()$claas_flag
    id <- ncdf4::nc_open(infile)
    file_info <- cmsafops:::check_dims(id)
    ncdf4::nc_close(id)

    if (!file_info$has_lon_lat) {
      if (claas_flag) {
        auxFilePath(file.path(ordPath, claas_aux))
        cmsafops::add_grid_info(infile, auxFilePath(), outfile = NULL, overwrite = TRUE)
      } else {
        grid_info <- cmsaf:::get_grid(infile)
        if (grid_info == 5 && (is.null(globalAuxFilePath()) || !file.exists(globalAuxFilePath()))) {
          showModal(modalDialog(
            h4("Your data seems to require an auxiliar file. You can either upload a local auxiliar file or download it from the public CM SAF website."),
            br(),
            fluidRow(column(6, actionButton(inputId = "aux_upload",
                                            label = "Upload aux file.",
                                            class = "btn btn-success btn-lg btn-block")),
                     column(6, actionButton(inputId = "aux_download",
                                            label = "Download aux file.",
                                            class = "btn btn-success btn-lg btn-block"))),
            title = "Auxiliary data needed.",
            footer = actionButton(inputId = "aux_cancel",
                                  label = "Cancel"),
            size = "l"
          ))

          # Leave silently and come back when globalAuxFilePath is updated.
          req(FALSE)
          cmsafops::add_grid_info(infile, globalAuxFilePath(), outfile = NULL, overwrite = TRUE)
        } else if (grid_info == 2 || grid_info == 7) {
          showModal(modalDialog(
            h4("Sorry, the CM SAF R Toolbox can not handle data in sinusoidal projection.
               Please use the 'change projection' option during the order process.
               Your NetCDF data have to be on a regular lon-lat grid."),
            title = "Error!",
            size = "l"))

          resetToPreparePanel()
          req(FALSE)
        }
      }

    }
    
    if (!is.null(globalAuxFilePath())) {
      if (file.exists(globalAuxFilePath())) {
        cmsafops::add_grid_info(infile, globalAuxFilePath(), outfile = NULL, overwrite = TRUE)
      }
    }
    
    userOptions <- getUserOptions(infile, claas_flag)

    # Set max_level
    if (is.numeric(userOptions$max_level)) {
      max_level(userOptions$max_level)
      shinyjs::show("level_ui")
    } else {
      max_level(0)
      shinyjs::hide("level_ui")
    }

    # Remembering the largest possible range.
    spatialRange$lat_range <- userOptions$lat_range
    spatialRange$lon_range  <- userOptions$lon_range

    # Remembering dimensions
    dimensions(userOptions$dimensions)

    # Distinction between .tar-mode and .nc-mode
    if(nc_path() != "") {
      output$variable_ui <- renderUI({
        vars <- subset(userOptions$variables, !(userOptions$variables %in% c("lat", "lon", "latitude", "longitude", "time_bnds", "nb2", "time", "crs")))
        selectInput("variableInput",
                    "You have selected the following variable",
                    choices = vars)
      })
    }
    else{
      output$variable_ui <- renderUI({
        vars <- subset(userOptions$variables, !(userOptions$variables %in% c("lat", "lon", "latitude", "longitude", "time_bnds", "nb2", "time", "crs")))
        selectInput("variableInput",
                    "We found the following variables",
                    choices = vars)
      })
    }
    
    # Rendering lon range.
    output$lonRange_ui <- renderUI({
      sliderInput(inputId = "lonRange",
                  label = "Please select a longitude range.",
                  min = trunc(20 * userOptions$lon_range[1]) / 20,
                  max = trunc(20 * userOptions$lon_range[2]) / 20,
                  value = c(trunc(20 * userOptions$lon_range[1]) / 20, trunc(20 * userOptions$lon_range[2]) / 20),
                  step = 0.05
      )
    })

    # Rendering lat range.
    output$latRange_ui <- renderUI({
      sliderInput(inputId = "latRange",
                  label = "Please select a latitude range.",
                  min = trunc(20 * userOptions$lat_range[1]) / 20,
                  max = trunc(20 * userOptions$lat_range[2]) / 20,
                  value = c(trunc(20 * userOptions$lat_range[1]) / 20, trunc(20 * userOptions$lat_range[2]) / 20),
                  step = 0.05
      )
    })

    # Reset auxFilePath and untarVals
    untarVals()
    auxFilePath()

    # Show second part of prepare and hide spinner
    shinyjs::hide("spinner_prepare2")
    shinyjs::hide("spinner_prepare4")
    shinyjs::show(id = "panel_prepareInput2", anim = TRUE, animType = "fade")
    if(nc_path() != ""){
      shinyjs::hide("deleteExtracted")
    }
    else{
      shinyjs::show("deleteExtracted")
    }
  })

  # Creating a preview plot.
  output$previewSpatialCoveragePlot <- renderPlot({
    req(input$lonRange)
    req(input$latRange)

    cmsafvis::render_preview_plot(spatial_lon_range = isolate(spatialRange$lon_range),
                                  spatial_lat_range = isolate(spatialRange$lat_range),
                                  lonRange = input$lonRange,
                                  latRange = input$latRange)
  })

  observe({
    req(input$variableInput)
    req(max_level())

    if (startsWith(input$variableInput, "HLW") | startsWith(input$variableInput, "HSH")) {
      output$level_ui <- renderUI({
        numericInput("level",
                     paste0("Select level (1 - ", max_level(), ")"),
                     min = 1,
                     max = max_level(),
                     value = 1,
                     step = 1)
      })
      shinyjs::show("level_ui")
      usingLevel(TRUE)
    } else {
      shinyjs::hide("level")
      usingLevel(FALSE)
    }
  })

  observeEvent(input$level, {
    shinyjs::disable("createOutput")
    req(is.numeric(input$level))
    if (input$level < 1 || input$level > max_level()) {
      shinyjs::disable("createOutput")
    } else {
      shinyjs::enable("createOutput")
    }
  })

  # Function to create the output
  creatingOutputfile <- function(path_to_tar, startDate, endDate, lon_var, lat_var, var, level, dn, outputFormat, claas_flag, deleteExtracted) {

    filelist <- untarVals()$filelist
    ordDir <- dirname(path_to_tar)

    # Regrid AOD or CLAAS data
    if (claas_flag) {
      cat("Data will be regridded to rectangular grid...", "\n")
      # Regrid first file
      infile  <- filelist[1]
      infile  <- file.path(ordDir, infile)
      auxfile <- file.path(ordDir, claas_aux)
      dxy <- 0.05     # Target grid resolution
      goc <- NULL

      id <- ncdf4::nc_open(infile)
        rdata <- ncdf4::ncvar_get(id, var)
        if ("georef_offset_corrected" %in% names(id$var)) {
          goc <- ncdf4::ncvar_get(id, "georef_offset_corrected")
          goc <- goc + 1
        }
      ncdf4::nc_close(id)

      id <- ncdf4::nc_open(auxfile)
        lon_reg <- ncdf4::ncvar_get(id, lon_var)
        if (!is.null(goc) && !is.na(dim(lon_reg)[3])) {
          if (dim(lon_reg)[3] > 1) lon_reg <- lon_reg[,,goc]
        }
        
        lat_reg <- ncdf4::ncvar_get(id, lat_var)
        if (!is.null(goc) && !is.na(dim(lat_reg)[3])) {
          if (dim(lat_reg)[3] > 1) lat_reg <- lat_reg[,,goc]
        }
      ncdf4::nc_close(id)

      lon_org <- seq(-90.0, 90.0, dxy)
      lat_org <- lon_org

      lon <-
        lon_org[which(lon_org > (min(lon_reg, na.rm = TRUE) - dxy) &
                        lon_org < (max(lon_reg, na.rm = TRUE) + dxy))]
      lat <-
        lat_org[which(lat_org > (min(lat_reg, na.rm = TRUE) - dxy) &
                        lat_org < (max(lat_reg, na.rm = TRUE) + dxy))]

      # FNN solution
      lon_reg   <- as.vector(lon_reg)
      lat_reg   <- as.vector(lat_reg)
      lon_reg2   <- lon_reg[!is.na(lon_reg)]
      lat_reg2   <- lat_reg[!is.na(lon_reg)]

      fnn_a <- FNN::get.knnx(lon, lon_reg2, k = 1)
      fnn_b <- FNN::get.knnx(lat, lat_reg2, k = 1)

      filelist_claas <- NULL

      for (i in seq_along(filelist)) {
        infile  <- filelist[i]
        infile  <- file.path(ordDir, infile)

        id <- ncdf4::nc_open(infile)
        rdata <- as.vector(ncdf4::ncvar_get(id, var))
        ncdf4::nc_close(id)

        rdata2 <- rdata[!is.na(lon_reg)]
        arr_new <- array(NA, c(length(lon), length(lat)))
        arr_new[cbind(fnn_a$nn.index, fnn_b$nn.index)] <- rdata2

        # Put new data into file

        t_name <- "time"
        t_standard_name <- "time"
        t_calendar <- "standard"

        lat_name <- "latitude"
        lat_standard_name <- "latitude"
        lat_long_name <- "latitude"
        lat_units <- "degrees_north"
        lat_axis <- "Y"

        lon_name <- "longitude"
        lon_standard_name <- "longitude"
        lon_long_name <- "longitude"
        lon_units <- "degrees_east"
        lon_axis <- "X"

        info <- "Created with the CM SAF R Toolbox."
        var_prec <- "float"

        # Originally called nc34 and set in header as nc34 <- 3
        # After that no change... I'm now passing this as a shiny select option.
        # outputFormat = "NetCDF3"

        if (outputFormat == "NetCDF4") {
          nc_format <- as.logical(1)
          compression <- 4
        } else {
          nc_format <- as.logical(0)
          compression <- NA
        }

        v_missing_value <- -999

        target <- array(NA, c(length(lon), length(lat), 1))
        target[, , 1] <- arr_new
        target[is.na(target)] <- v_missing_value

        id <- ncdf4::nc_open(infile)
        v_units         <- ncdf4::ncatt_get(id, var, "units")$value
        v_standard_name <- ncdf4::ncatt_get(id, var, "standard_name")$value
        v_long_name     <- ncdf4::ncatt_get(id, var, "long_name")$value
        time1           <- ncdf4::ncvar_get(id, "time")
        t_units         <- ncdf4::ncatt_get(id, "time", "units")$value
        ncdf4::nc_close(id)

        outfile <- file.path(userDir, paste0("RG_", filelist[i]))

        x <- ncdf4::ncdim_def(name = "lon",
                              units = lon_units,
                              vals = lon)
        y <- ncdf4::ncdim_def(name = "lat",
                              units = lat_units,
                              vals = lat)
        t <-
          ncdf4::ncdim_def(
            name = "time",
            units = t_units,
            vals = time1,
            unlim = TRUE
          )

        var1 <-
          ncdf4::ncvar_def(
            name = var,
            units = v_units,
            dim = list(x, y, t),
            missval = v_missing_value,
            prec = var_prec,
            compression = compression
          )

        vars <- list(var1)

        ncnew <- ncdf4::nc_create(outfile, vars, force_v4 = nc_format)

        ncdf4::ncvar_put(ncnew, var1, target)

        ncdf4::ncatt_put(ncnew, var, "standard_name", v_standard_name, prec = "text")
        ncdf4::ncatt_put(ncnew, var, "long_name", v_long_name, prec = "text")

        ncdf4::ncatt_put(ncnew, "time", "standard_name", t_standard_name, prec =
                           "text")
        ncdf4::ncatt_put(ncnew, "time", "calendar", t_calendar, prec = "text")

        ncdf4::ncatt_put(ncnew, "lon", "standard_name", lon_standard_name, prec =
                           "text")
        ncdf4::ncatt_put(ncnew, "lon", "long_name", lon_long_name, prec = "text")
        ncdf4::ncatt_put(ncnew, "lon", "axis", lon_axis, prec = "text")

        ncdf4::ncatt_put(ncnew, "lat", "standard_name", lat_standard_name, prec =
                           "text")
        ncdf4::ncatt_put(ncnew, "lat", "long_name", lat_long_name, prec = "text")
        ncdf4::ncatt_put(ncnew, "lat", "axis", lat_axis, prec = "text")

        ncdf4::ncatt_put(ncnew, 0, "Info", info, prec = "text")

        ncdf4::nc_close(ncnew)

        filelist_claas <-
          append(filelist_claas, paste0("RG_", filelist[i]))
      } # end for filelist

      # Remove original files
      file.remove(file.path(ordDir, filelist))
      file.remove(auxfile)
      filelist <- filelist_claas
    } # end if claas flag

    # if time aggregation is enabled
    if(input$checkboxInput_aggregate == TRUE) {
      outfile <- file.path(outputDir, paste0(var, "_", startDate, "-", endDate, "_tmp.nc"))
    } 
    else {
      outfile <- file.path(outputDir, paste0(var, "_", startDate, "-", endDate, ".nc"))
    }
    
    if (!is.null(level)) {
      pattern <- substr(filelist[1], 1, 5)
      
      cmsafops::levbox_mergetime(var,
                              level = level,
                              path = ordDir,
                              pattern = pattern,
                              outfile = outfile,
                              lon1 = lon_var[1],
                              lon2 = lon_var[2],
                              lat1 = lat_var[1],
                              lat2 = lat_var[2],
                              nc34 = outputFormat,
                              overwrite = TRUE)
    } else {
      # box_mergetime
      pattern <- substr(filelist[1], 1, 5)

      cmsafops::box_mergetime(var,
                           path = ordDir,
                           pattern = pattern,
                           outfile = outfile,
                           lon1 = lon_var[1],
                           lon2 = lon_var[2],
                           lat1 = lat_var[1],
                           lat2 = lat_var[2],
                           nc34 = outputFormat,
                           overwrite = TRUE)
    }

    # Clean up
    if (deleteExtracted) {
      gzcheck <- length(unlist(strsplit(filelist[1], ".nc")))
      if (gzcheck == 2) {
        removelist <- unlist(strsplit(filelist, ".gz"))
      } else {
        removelist <- filelist
      }

      file.remove(file.path(ordDir, removelist))
    }

    # Clean up variables
    var_list_default <- c("checkstring", "userDir", "date_from", "date_to", "dates",
                          "dates_all", "delete", "dume", "dummy", "dums", "end", "endDate",
                          "filelist", "flist", "gzcheck", "i", "id", "infile", "infile_name",
                          "n", "orddir", "ordname", "ordpath",
                          "outputDir", "pattern", "slash", "split_path", "start",
                          "startDate", "tar_flag", "tarlist", "tarlist_all", "timestep", "var",
                          "var_default", "vn", "zipfile", "t", "claas_flag", "sn", "outputFormat",
                          "lon_var", "lat_var", "%ni%")
    var_list <- ls()

    var_list <- var_list[var_list %in% var_list_default]
    var_list <- append(var_list, c("var_list_default", "var_list"))

    rm(list = var_list)
    return(outfile)
  }
  
  observeEvent(input$operatorGroupsPrepare, {
    for (option in operatorOptions) {
      if (is.element(input$operatorGroupsPrepare, operatorOptionsDict[[option]])) {
        currentOperatorOption(option)
        break
      } else {
        currentOperatorOption("None")
      }
    }
    
    if(currentOperatorOption() != "None") {
      option_string <- toString(currentOperatorOption())
      option_prepare_ui(paste0(option_string, "_prepare"))
    }
   
    if(currentOperatorOption() == "None"){
      if(option_prepare_ui() != 0)
        shinyjs::hide(option_prepare_ui())
    } else {
      shinyjs::show(option_prepare_ui())
    }
  })

  observeEvent(input$createOutput, {
    # Show spinner
    shinyjs::hide("panel_prepareInput2")
    shinyjs::show("spinner_prepare3", anim = TRUE, animType = "fade")

    # Require positive click value
    req(input$createOutput > 0)
    req(dateRange_prep())

    # Get level or set to NULL.
    if (usingLevel()) {
      level <- input$level
    } else {
      level <- NULL
    }

    # Finally create the output file and remember it's location.
    # Differentiation between .nc-version and .tar-version
    if(nc_path() != ""){
      res <- try(outputFilepath(creatingOutputfile(nc_path(),
                                                   dateRange_prep()[1],
                                                   dateRange_prep()[2],
                                                   input$lonRange,
                                                   input$latRange,
                                                   input$variableInput,
                                                   level,
                                                   dimensions(),
                                                   input$outputFormat,
                                                   FALSE,
                                                   input$deleteExtracted)))
    }
    else{
      res <- try(outputFilepath(creatingOutputfile(tar_path(),
                                                   dateRange_prep()[1],
                                                   dateRange_prep()[2],
                                                   input$lonRange,
                                                   input$latRange,
                                                   input$variableInput,
                                                   level,
                                                   dimensions(),
                                                   input$outputFormat,
                                                   FALSE,
                                                   input$deleteExtracted)))
    }
    
    # time aggregation in prepare step
    if(input$checkboxInput_aggregate == TRUE) {
      agg_func <- get(input$operatorGroupsPrepare, asNamespace("cmsafops"))
      outfile_path <- file.path(outputDir, paste0(input$variableInput, "_", dateRange_prep()[1], "-", dateRange_prep()[2], ".nc"))
      
      for (option in operatorOptions) {
        if (is.element(input$operatorGroupsPrepare, operatorOptionsDict[[option]])) {
          currentOperatorOption(option)
          break
        } else {
          currentOperatorOption("None")
        }
      }
      
      if(currentOperatorOption() == "None") {
        argumentList <- list(var = input$variableInput,
                             infile = outputFilepath(),
                             outfile = outfile_path,
                             nc34 = input$outputFormat,
                             overwrite = TRUE)
      }
      else if (currentOperatorOption() == "timeRange") {
        argumentList <- list(var = input$variableInput,
                             nts = input$timeRange_nts_prepare,
                             infile = outputFilepath(),
                             outfile = outfile_path,
                             nc34 = input$outputFormat,
                             overwrite = TRUE)
      }
      res <- try(do.call(agg_func, argumentList))
      
      currentOperatorOption("None")   # reset option
      
      outputFilepath(file.path(outputDir, paste0(input$variableInput, "_", dateRange_prep()[1], "-", dateRange_prep()[2], ".nc")))
      unlink(file.path(outputDir, paste0(input$variableInput, "_", dateRange_prep()[1], "-", dateRange_prep()[2], "_tmp.nc")))
    }

    if (class(res) == "try-error") {
      showModal(modalDialog(
        h4("An error occured while creating an output file."),
        tags$p(paste0("Message: ", res)),
        title = "Error!",
        size = "m"
      ))
    }

    # Variable 'isRunningLocally' can be found in global.R
    if (repeatWarning() && !isRunningLocally) {
      showModal(modalDialog(
        tags$p("A .nc file has been created for you. ",
               "Its contents are temporarily stored in the session folder.",
               "Please downlaod the session folder if you want to save it.",
               "All files will be removed after closing this app!"),
        checkboxInput("noRepeat", "Do not show this message again."),
        title = "Warning to prevent data loss!",
        size = "l"
      ))
    }

    shinyjs::hide("spinner_prepare3")
    resetToAnalyzePanel()
  }, ignoreInit = TRUE)

  observeEvent(input$noRepeat, {
    repeatWarning(!input$noRepeat)
  })

  # Download the created session directory.
  # session_dir_download_handler is called in two places
  # For output$download (main button) and output$downloader_modal (button in modal)
  session_dir_download_handler <- downloadHandler(
    filename = function() {
      paste0(sessionName, ".tar")
    },
    content = function(con) {
      if (dir.exists(userDir)) {
        tarname <- paste0(sessionName, ".tar")
        utils::tar(tarname, userDir)
        file.copy(tarname, con)
      }
    },
    contentType = "application/x-tar"
  )
  output$download <- session_dir_download_handler

  #### ANALYZING ####
  # If a file has been generated let user decide if they want to continue with
  # this file or select another file.
  observeEvent(outputFilepath(), {
    if (endsWith(outputFilepath(), ".nc") || !is.null(outputFilenc())) {
      output$ncFile_analyze <- renderUI({
        tags$pre("We prepared the following .nc file for you: ",
                 cmsafops::get_basename(outputFilepath(), nc = outputFilenc()))
      })
      output$ncFile_visualize <- renderUI({
        tags$pre("We prepared the following .nc file for you: ",
                 cmsafops::get_basename(outputFilepath(), nc = outputFilenc()))
      })
      shinyjs::show("ncFile_analyze")
      shinyjs::show("useOutputFile_analyze")
      shinyjs::show("or_analyze")
      shinyjs::show("ncFile_visualize")
      shinyjs::show("useOutputFile_visualize")
      shinyjs::show("or_visualize")
    } else {
      shinyjs::hide("ncFile_analyze")
      shinyjs::hide("useOutputFile_analyze")
      shinyjs::hide("or_analyze")
      shinyjs::hide("ncFile_visualize")
      shinyjs::hide("useOutputFile_visualize")
      shinyjs::hide("or_visualize")
    }
  })

  # Starting analyze page.
  observeEvent(nc_path_analyze_action(), {
    # Requirements
    req(nc_path_analyze())

    # If wrong format alert and stop.
    if (!endsWith(nc_path_analyze(), ".nc") && is.null(nc_object_analyze())) {
      isolate(nc_path_analyze(""))
      showModal(modalDialog(
        h4("Wrong file format. Please choose .nc file to continue."),
        title = "Warning!",
        size = "m"
      ))
    } else {
      # Getting variable(s)
      if (!is.null(nc_object_analyze())) id <- nc_object_analyze()
      else id <- ncdf4::nc_open(nc_path_analyze())
      vn <- names(id$var)
      dn <- names(id$dim)
      if (is.null(nc_object_analyze())) ncdf4::nc_close(id)

      if (!("time" %in% dn)) {
        showModal(modalDialog(
          h4("Sorry, the file you chose does not contain a time dimension."),
          title = "Error!",
          size = "l"))

        resetToPreparePanel()
      } else {

      var_default <- subset(vn, !(vn %in% c("lat", "lon", "latitude", "longitude", "time_bnds", "nb2", "time", "crs")))

      # Stop if data are in sinusoidal projection
      if ("sinusoidal" %in% vn) {
        showModal(modalDialog(
          h4("Sorry, the CM SAF R Toolbox can not handle data in sinusoidal projection.
           Please use the 'change projection' option during the order process.
           Your NetCDF data have to be on a regular lon-lat grid."),
          title = "Error!",
          size = "l"))

        resetToPreparePanel()
      } else {

      output$usedVariable <- renderUI({
        selectInput("usedVariable",
                    label = "Please choose a variable",
                    choices = var_default,
                    width = "320px")
      })
      shinyjs::hide("panel_analyzeGo")
      shinyjs::show("panel_analyze")
      }}
    }
  }, ignoreInit = TRUE)

  # Update Variable
  observeEvent(input$variableAnalyze, {
    req(input$variableAnalyze)

    var_used(input$variableAnalyze)
  }, ignoreInit = TRUE)
  
  # Update possible choices for operator.
  observe({
    req(input$operatorGroup)
    req(!applyOperatorActiv)
    
    if(input$operatorGroup == "Compare Data"){
      if((endsWith(infile2_analyze_value(), ".csv")) || endsWith(infile2_analyze_value(), ".RData")) {
        tmp_vec <- c()
        tmp_vec[["Compare Data"]] <- c(
          "Difference plot (absolute)" = "cmsaf.diff.absolute",
          "Difference plot (relative)" = "cmsaf.diff.relative",
          "Scatterplot" = "cmsaf.scatter",
          "Bar chart" = "cmsaf.hist",
          "Side-by-Side plot" = "cmsaf.side.by.side",
          "Comparison of time series" = "cmsaf.time.series",
          "Show statistics" = "cmsaf.stats"
        )

        shinyjs::show("operator")
        output$operator <- renderUI({
          # Operator can be found in global.R
          checkboxGroupInput("operatorInput",
                             label = "Select an operator.",
                             choices = tmp_vec[[input$operatorGroup]],
                             selected = tmp_vec[[input$operatorGroup]][1],
                             width = "320px")
        })
      } else {
        shinyjs::show("operator")
        output$operator <- renderUI({
          # Operator can be found in global.R
          checkboxGroupInput("operatorInput",
                             label = "Select an operator.",
                             choices = operators[[input$operatorGroup]],
                             selected = operators[[input$operatorGroup]][1],
                             width = "320px")
        })
      }
    } else{
      shinyjs::hide("ncFile_analyze_second_file")
      output$operator <- renderUI({
        # Operator can be found in global.R
        selectInput("operatorInput",
                    label = "Select an operator.",
                    choices = operators[[input$operatorGroup]],
                    width = "320px")
      })
    }
  })
  
  observeEvent(input$operatorInput, {
    req(input$operatorGroup)
    req(input$operatorInput)
    
    if(input$operatorGroup == "Compare Data") {
      checkboxCompareData(input$operatorInput)
      checkboxCompareData_dropdown(checkboxCompareData()[1])
    } 
    operatorInput_value(input$operatorInput[1])
  })
  
  observe({
    req(input$operatorGroup)
    req(operatorInput_value())
    
    climate_analysis_ops <- c(
      "absolute_map",
      "anomaly_map",
      "climatology_map",
      "fieldmean_plot",
      "fieldmean_and_anomaly_map",
      "warming_stripes_plot",
      "time_series_plot",
      "trend_plot"
    )

    countries_choosable <- codes[, "iso3c"]
    names(countries_choosable) <- codes[, "country.name.en"]

    if (operatorInput_value() %in% climate_analysis_ops) {
      # If the monitor climate name is chosen, we will visualize right away!
      shinyjs::show("ClimateAnalysisMessage")
      # Update checkboxes to correct value
      updateCheckboxInput(
        session = session,
        inputId = "applyAnother",
        label = "Do you want to apply another operator afterwards?",
        value = FALSE)
      updateCheckboxInput(
        session = session,
        inputId = "instantlyVisualize",
        label = "Do you want to visualize the results right away?",
        value = TRUE)

      # Render countries including EUR, AFR, TOT
      output$select_country <- renderUI({
        selectInput("country",
                  label = "Please select a country",
                  choices = countries_choosable,
                  selected = countries_choosable[which(countries_choosable == "S_A")],
                  width = "320px",
                  multiple = FALSE)
      })
    }

    # Render some UI elements dependent on infile and chosen operator
    if (operatorInput_value() == "selyear") {
      if (!is.null(nc_object_analyze())) nc <- nc_object_analyze()
      else nc <- ncdf4::nc_open(isolate(nc_path_analyze()))
      time_info <- cmsafops:::get_date_time(ncdf4::ncvar_get(nc, "time"), ncdf4::ncatt_get(nc, "time", "units")$value)
      years2 <- time_info$years
      if (is.null(nc_object_analyze())) ncdf4::nc_close(nc)

      output$years_to_select <- renderUI({
        selectInput("years",
                    label = "Select years",
                    choices = sort(unique(years2)),
                    width = "320px",
                    multiple = TRUE)
      })
    }

    if (operatorInput_value() %in% c("selperiod", "extract.period", climate_analysis_ops)) {
      if (!is.null(nc_object_analyze())) nc <- nc_object_analyze()
      else nc <- ncdf4::nc_open(isolate(nc_path_analyze()))
      date_time <- as.Date(cmsafops::get_time(ncdf4::ncatt_get(nc, "time", "units")$value, ncdf4::ncvar_get(nc, "time")))
      if (is.null(nc_object_analyze())) ncdf4::nc_close(nc)

      if (operatorInput_value() %in% c("selperiod", "extract.period")) {
        output$dateRange_to_select <- renderUI({
          dateRangeInput("dateRange_analyze",
                         label = "Select date range",
                         start = min(date_time),
                         end = max(date_time),
                         min = min(date_time),
                         max = max(date_time),
                         width = "320px")
        })
      } else if(operatorInput_value() %in% c("absolute_map", "anomaly_map", "climatology_map", "fieldmean_plot", "fieldmean_and_anomaly_map")){
        # In monitor climate want to initialize in same year.
        output$dateRange_to_select <- renderUI({
          dateRangeInput("dateRange_analyze",
                         label = "Select date range",
                         start = min(date_time[format(date_time, "%Y") == format(max(date_time), "%Y")]),
                         end = max(date_time),
                         min = min(date_time),
                         max = max(date_time),
                         width = "320px")
        })
      }
    }

    if (operatorInput_value() %in% c("anomaly_map", "climatology_map", "fieldmean_plot", "fieldmean_and_anomaly_map", "warming_stripes_plot", "time_series_plot", "trend_plot")) 
    {
      output$climatology_years <- renderUI({

        years <- unique(format(date_time, format = "%Y"))
        if (length(years) == 1) {
          end_year <- years[1]
        } else {
          end_year <- years[length(years) - 1]
        }

        tags$div(
          fluidRow(
            column(width = 5,
                   selectInput("climate_year_start",
                               label = "Climatol. start year",
                               choices = years,
                               selected = years[1])
                               ),
            column(width = 5,
                   selectInput("climate_year_end",
                               label = "Climatol. end year",
                               choices = years,
                               selected = end_year
                               ))
          )
        )
      })
    }

    if (operatorInput_value() == "seltime") {
      if (!is.null(nc_object_analyze())) nc <- nc_object_analyze()
      else nc <- ncdf4::nc_open(isolate(nc_path_analyze()))
      time_info <- cmsafops:::get_date_time(ncdf4::ncvar_get(nc, "time"), ncdf4::ncatt_get(nc, "time", "units")$value)
      times2 <- time_info$times
      if (is.null(nc_object_analyze())) ncdf4::nc_close(nc)

      output$times_to_select <- renderUI({
        selectInput("times",
                    label = "Select times",
                    choices = sort(unique(times2)),
                    width = "320px",
                    multiple = TRUE)
      })
    }

    if (operatorInput_value() %in% c("sellonlatbox", climate_analysis_ops)) {
      # nc <- ncdf4::nc_open(isolate(nc_path_analyze()))
      # lon <- ncdf4::ncvar_get(nc, "lon")
      # lat <- ncdf4::ncvar_get(nc, "lat")
      # ncdf4::nc_close(nc)
      
      file_data <- cmsafops::read_file(isolate(nc_path_analyze()), input$usedVariable, nc = nc_object_analyze())
      lon <- file_data$dimension_data$x
      lat <- file_data$dimension_data$y
      
      output$region_to_select <- renderUI({
        # tags$div(id = "region",
        #          sliderInput("lonRegionSlider",
        #                      label = "Select longitude",
        #                      min = ceiling(min(lon, na.rm = T)*100)/100,
        #                      max = floor(max(lon, na.rm = T)*100)/100,
        #                      value = c(ceiling(min(lon, na.rm = T)*100)/100,
        #                                floor(max(lon, na.rm = T)*100)/100),
        #                      width = "320px"),
        #          sliderInput("latRegionSlider",
        #                      label = "Select latitude",
        #                      min = ceiling(min(lat, na.rm = T)*100)/100,
        #                      max = floor(max(lat, na.rm = T)*100)/100,
        #                      value = c(ceiling(min(lat, na.rm = T)*100)/100,
        #                                floor(max(lat, na.rm = T)*100)/100),
        #                      width = "320px"))
        tags$div(id = "region",
          fluidRow(
            column(width = 5,
                   numericInput("lonRegionMin",
                               label = "Longitude min",
                               min = ceiling(min(lon, na.rm = T)*100)/100,
                               max = floor(max(lon, na.rm = T)*100)/100,
                               value = ceiling(min(lon, na.rm = T)*100)/100)
                               ),
            column(width = 5,
                   numericInput("lonRegionMax",
                                label = "Longitude max",
                                min = ceiling(min(lon, na.rm = T)*100)/100,
                                max = floor(max(lon, na.rm = T)*100)/100,
                                value = floor(max(lon, na.rm = T)*100)/100
                   ))),
            fluidRow(
              column(width = 5,
                     numericInput("latRegionMin",
                                  label = "Latitude min",
                                  min = ceiling(min(lat, na.rm = T)*100)/100,
                                  max = floor(max(lat, na.rm = T)*100)/100,
                                  value = ceiling(min(lat, na.rm = T)*100)/100)
              ),
              column(width = 5,
                     numericInput("latRegionMax",
                                  label = "Latitude max",
                                  min = ceiling(min(lat, na.rm = T)*100)/100,
                                  max = floor(max(lat, na.rm = T)*100)/100,
                                  value = floor(max(lat, na.rm = T)*100)/100
                     ))
            
          )
        )
      })
    }

    if (operatorInput_value() == "selpoint.multi") {
      # nc <- ncdf4::nc_open(isolate(nc_path_analyze()))
      # lon <- ncdf4::ncvar_get(nc, "lon")
      # lat <- ncdf4::ncvar_get(nc, "lat")
      # ncdf4::nc_close(nc)
      
      file_data <- cmsafops::read_file(isolate(nc_path_analyze()), input$usedVariable, nc = nc_object_analyze())
      lon <- file_data$dimension_data$x
      lat <- file_data$dimension_data$y

      updateCheckboxInput(session, "instantlyVisualize", value = FALSE)

      updateSelectInput(session,
                        "format",
                        "Select output format",
                        choices = c("NetCDF4" = 4, "NetCDF3" = 3, "CSV" = 5))

      output$multi_warning <- renderUI({
        tags$div(
          br(),
          p("This function creates multiple output files.
                                    These will be saved in your output directory.
                                    Instant visualization is not possible!", style = "color:red"),
          br())
        })

    } else {
      updateSelectInput(session,
                        "format",
                        "Select output format",
                        choices = c("NetCDF4" = 4, "NetCDF3" = 3))
    }

    if(operatorInput_value() == "cmsaf.adjust.two.files") {
      updateCheckboxInput(session, "instantlyVisualize", value = FALSE)
      
      output$multi_warning_adjust_two_files <- renderUI({
        tags$div(
          br(),
          p("This function creates multiple output files.
                                    These will be saved in your output directory.
                                    Instant visualization is not possible!", style = "color:red"),
          br())
      })
    }
    
    # Disable the correct checkboxes
    disable_apply_another_ops <- climate_analysis_ops
    disable_instant_vis_ops <- c(climate_analysis_ops, "selpoint.multi", "cmsaf.adjust.two.files")

    if (operatorInput_value() %in% disable_apply_another_ops) {
      shinyjs::disable("applyAnother")
      shinyjs::hide("applyAnother")
    } else {
      shinyjs::enable("applyAnother")
    }

    if (operatorInput_value() %in% disable_instant_vis_ops) {
      shinyjs::disable("instantlyVisualize")
      shinyjs::hide("instantlyVisualize")
    } else {
      shinyjs::enable("instantlyVisualize")
    }
  })

  observeEvent(input$add_point, {
    chosen_lonPoints(c(chosen_lonPoints(), input$lonPoint))
    chosen_latPoints(c(chosen_latPoints(), input$latPoint))
    updateNumericInput(session, "lonPoint", label = "Select longitude point", value = 0)
    updateNumericInput(session, "latPoint", label = "Select latitude point", value = 0)
    output$chosen_points <- renderTable({
      df <- data.frame(cbind(chosen_lonPoints(), chosen_latPoints()))
      names(df) <- c("lon", "lat")
      df
    })
  })

  ## Remove file choosing
  volumes_output <- c(Home = fs::path_home(), shinyFiles::getVolumes()())
  shinyFiles::shinyFileChoose(input, "ncSecondFileRemote", roots = volumes_output, session = session)

  output$secondFile <- renderPrint({
    if (is.integer(input$ncSecondFileRemote)) {
      cat("No file has been selected.")
    } else {
      file <- shinyFiles::parseFilePaths(volumes_output, input$ncSecondFileRemote)
      second_infile( file$datapath )
      file$datapath
    }
  })

  # Observing checkboxes
  observeEvent(input$applyAnother, {
    if (!input$applyAnother) {
      shinyjs::show("instantlyVisualize")
    } else {
      shinyjs::hide("instantlyVisualize")
    }
  }, ignoreInit = TRUE)

  # Toggle states of input ui element options for the different operators.
  observeEvent(operatorInput_value(), {
    req(operatorInput_value())

    # Operator options can be found in global.R
    currentOperatorOption("None")

    for (option in operatorOptions) {
      if (is.element(operatorInput_value(), operatorOptionsDict[[option]])) {
        currentOperatorOption(option)
      } else {
        shinyjs::hide(option)
        shinyjs::hide("dateRange_to_select")
        shinyjs::hide("climatology_years")
        shinyjs::hide("accumulateInfile")
        shinyjs::hide("attachToExisting")
        shinyjs::hide("years_to_select")
        shinyjs::hide("region_to_select")
        shinyjs::hide("times_to_select")
        shinyjs::hide("points_to_select")
        shinyjs::hide("select_country")
        shinyjs::hide("plot_format")
        shinyjs::hide("monitorClimateAnalyzeMethod")
        shinyjs::hide("analyzeTimeSize")
		    shinyjs::hide("stripecol")
		    shinyjs::hide("circular")
		    shinyjs::hide("absrel")
      }
    }

    if (currentOperatorOption() != "None") {
      if (currentOperatorOption() == "dateRange") {
        shinyjs::show("dateRange_to_select")
      } else if (currentOperatorOption() == "years") {
        shinyjs::show("years_to_select")
      } else if (currentOperatorOption() == "times") {
        shinyjs::show("times_to_select")
      } else if (currentOperatorOption() == "region") {
        shinyjs::show("region_to_select")
      } else if (currentOperatorOption() == "point.multi") {
        shinyjs::show("points_to_select")
      } else if (currentOperatorOption() == "monitor_climate") {
        shiny::hideTab(inputId = "mainVisualizeTabset", target = "Metrics")
        shinyjs::show("accumulateInfile")
        shinyjs::show("attachToExisting")
        shinyjs::show("dateRange_to_select")
        if (operatorInput_value() %in% c("warming_stripes_plot", "time_series_plot", "trend_plot")) {
          shinyjs::hide("dateRange_to_select")
        }
        if (!(operatorInput_value() %in% c("absolute_map"))) {
          shinyjs::show("climatology_years")
        }
		
		    if ((operatorInput_value() %in% c("anomaly_map"))) {
          shinyjs::show("stripecol")
		      shinyjs::show("absrel")
        }

        shinyjs::show("region_to_select")
        shinyjs::show("plot_format")
        shinyjs::show("select_country")
        if(operatorInput_value() %in% c("time_series_plot", "trend_plot")){
          shinyjs::show("monitorClimateAnalyzeMethod")
          shinyjs::show("analyzeTimeSize")
          shinyjs::hide("plot_format")
          #shinyjs::hide("region_to_select")
          shinyjs::hide("accumulateInfile")
          #shinyjs::hide("attachToExisting")
        } 
        if (operatorInput_value() %in% c("warming_stripes_plot")) {
          shinyjs::show("monitorClimateAnalyzeMethod")
          shinyjs::show("analyzeTimeSize")
          shinyjs::show("stripecol")
          shinyjs::show("circular")
          shinyjs::hide("plot_format")
          shinyjs::hide("accumulateInfile")
        }
      } else if(currentOperatorOption() == "compare_data") {
          shinyjs::show("file_selection")
      } else {
        shinyjs::show(currentOperatorOption())
      }
    }

    if (operatorInput_value() == "selpoint.multi") {
      shinyjs::show("add_point")
      shinyjs::show("multi_warning")
      shinyjs::show("chosen_points")
    } else {
      shinyjs::hide("add_point")
      shinyjs::hide("multi_warning")
      shinyjs::hide("chosen_points")
    }
    
    if(operatorInput_value() == "cmsaf.adjust.two.files") {
      shinyjs::show("multi_warning_adjust_two_files")
    } else {
      shinyjs::hide("multi_warning_adjust_two_files")
    }

    if (!isRunningLocally && (operatorInput_value() %in% c("remap", 
                                                         "cmsaf.add", 
                                                         "cmsaf.sub", 
                                                         "fldcor", 
                                                         "fldcovar", 
                                                         "timcor", 
                                                         "timcovar") || input$attachToExisting)) {
      shinyjs::show("twofiles")
    } else {
      shinyjs::hide("twofiles")
    }

  }, ignoreInit = TRUE)

  # Updating the operator table and toggle panel state.
  observeEvent(operatorDataFrameAction(), {
    if (nrow(operatorDataFrame) > 0) {
      shinyjs::hide("spinner_analyze")
      shinyjs::show("listOfOperators")
    }

    output$appliedOperators <- renderTable({
      operatorDataFrame
    })

    output$ncShortInfo <- renderPrint({
      req(nc_path_analyze())
      cmsafops::ncinfo(nc_path_analyze(), nc = nc_object_analyze())
    })
	
  # Operator Group Infos
	output$ogInfo <- renderPrint({
    req(input$operatorGroup)    
	  if(input$operatorGroup == "Hourly statistics") {
		  cat("Hourly statistics\n")
	    cat("Calculate hourly statistics from data with a temporal resolution\n")
	    cat("below one hour (e.g., 1/2 h or 15 min). Thus, it makes no sense to\n")
	    cat("apply these operators for daily or monthly data.\n")
	  }
	  if(input$operatorGroup == "Daily statistics") {
	    cat("Daily statistics\n")
	    cat("Calculate daily statistics from data with a temporal resolution\n")
	    cat("below one day (e.g., instantaneous). Thus, it makes no sense to\n")
	    cat("apply these operators for monthly data.\n")
	    cat("Multi-year operators will give you values for each day of the year.\n")
	    cat("The date information in the output file is the date of the first\n")
      cat("contributing input field.\n")
	  }
	  if(input$operatorGroup == "Monthly statistics") {
	    cat("Monthly statistics\n")
	    cat("Calculate monthly statistics from all timesteps of the same month.\n")
	    cat("Multi-year operators will give you values for each month of the year.\n")
	    cat("The date information in the output file is the date of the first\n")
	    cat("contributing input field.\n")
	  }
	  if(input$operatorGroup == "Seasonal statistics") {
	    cat("Seasonal statistics\n")
	    cat("Calculate seasonal statistics from all timesteps of the same\n") 
	    cat("season.Multi-year operators will give you values for each season\n")
	    cat("of the year.The standard seasons are defined as DJF (output field 1),\n")
	    cat("MAM (2), JJA (3) and SON (4).\n") 
	    cat("The date information in the output file is the date of the first\n")
	    cat("contributing input field.\n")
	  }
	  if(input$operatorGroup == "Annual statistics") {
	    cat("Annual statistics\n")
	    cat("Calculate annual statistics from all timesteps of the same year.\n")
	    cat("The date information in the output file is the date of the first\n")
	    cat("contributing input field.\n")
	  }
	  if(input$operatorGroup == "Temporal operators") {
	    cat("Temporal operators\n")
	    cat("Calculate statistics over all timesteps of a file.\n")
	    cat("Besides standard statistics you will also find operators to do\n")
	    cat("trend analysis or to calculate simple indices.\n")
	    cat("The date information in the output file is the date of the first\n")
	    cat("contributing input field.\n")
	  }
	  if(input$operatorGroup == "Running statistics") {
	    cat("Running statistics\n")
	    cat("Calculate statistics over a selected number of timesteps.\n")
	    cat("You will have to give the number of time steps or number of days\n")
	    cat("(for multi-year statistics).\n")
	    cat("The date information in the output file is the date of the first\n")
	    cat("contributing input field.\n")
	  }
	  if(input$operatorGroup == "Zonal statistics") {
	    cat("Zonal statistics\n")
	    cat("Calculate zonal (along latitude) statistics for\n")
	    cat("each timestep of a file.\n")
	  }
	  if(input$operatorGroup == "Meridional statistics") {
	    cat("Meridional statistics\n")
	    cat("Calculate meridional (along longitude) statistics for\n")
	    cat("each timestep of a file.\n")
	  }
	  if(input$operatorGroup == "Grid boxes statistics") {
	    cat("Grid boxes statistics\n")
	    cat("Calculate statistics for a given grid box size.\n")
	  }
	  if(input$operatorGroup == "Spatial operators") {
	    cat("Spatial operators\n")
	    cat("Calculate spatial statistics for each timestep of a file.\n")
	    cat("The resulting file will contain a 1D-timeseries.\n")
	  }
	  if(input$operatorGroup == "Correlation and covariance") {
	    cat("Correlation and covariance\n")
	    cat("Calculate spatial or temporal correlations or covariances.\n")
	    cat("These operators require a second file.\n")
	  }
	  if(input$operatorGroup == "Mathematical operators") {
	    cat("Mathematical operators\n")
	    cat("Add, multiply, subtract or divide your data by a constant\n")
	    cat("or data from a second file.\n")
	    cat("If you use data from a second file, make sure that\n")
	    cat("the dimensions are matching.\n")
	  }
	  if(input$operatorGroup == "Selection") {
	    cat("Selection\n")
	    cat("These operators provide spatial or temporal selection from your data.\n")
	    cat("Please make sure that the selected values are within the\n")
	    cat("available range.\n")
	  }
	  if(input$operatorGroup == "Data manipulation") {
	    cat("Data manipulation\n")
	    cat("Regrid your data using different interpolation methods.\n")
	    cat("Grid information is taken from a second, which has to be provided.\n")
	  }
	  if(input$operatorGroup == "Climate Analysis") {
	    cat("Climate Analysis\n")
	    cat("Here you will find some more complex operators to do climate analysis.\n")
	    cat("Some of these operators require continous time series of daily data,\n")
	    cat("which might cause some time consuming computations. But, the reults\n")
	    cat("are worth waiting. So far, the resulting graphics or animations\n")
	    cat("are not interactive.\n")
	    cat("For animations you will have to install the ffmpeg library.\n")
	  }
	  if(input$operatorGroup == "Compare Data") {
		  cat("Compare Data\n")
	    cat("This operator provides the option to compare data of two input files.\n")
	    cat("You can compare your spatial data to other spatial data or station\n")
	    cat("data. Station data have to follow a specific format (for an example\n")
	    cat("have a look at the output of 'Select data at multiple points' in\n")
	    cat("CSV format). Adaptation options for the output graphics are limited \n")
	    cat("and the calculation might take some time - we try to improve as soon\n")
	    cat("as possible.\n")
	  }
	  if(input$operatorGroup == "Time range statistics") {
	    cat("Time range statistics\n")
	    cat("These operators compute the mean or sum for a given number\n")
	    cat("of timesteps.\n")
	  }
	 })

    if (nrow(operatorDataFrame) == 0) {
      shinyjs::hide("listOfOperators")
    }
  }, ignoreInit = TRUE)


  # multi day accu graphic message
  observe({
    #shinyjs::hide("multiDayNonAccuGraphic")
    req(input$operatorGroup)
    req(input$operatorGroup == "Climate Analysis")
    req(!(is.null(input$accumulateInfile)))
    req(input$dateRange_analyze)
    req(input$plot_format)
    req(!any(is.na(input$dateRange_analyze)))

    # if (!input$accumulateInfile &&
    #     input$plot_format == "graphic" &&
    #     input$dateRange_analyze[1] != input$dateRange_analyze[2]) {
    #   shinyjs::show("multiDayNonAccuGraphic")
    # }
  })

  observeEvent(input$attachToExisting, {
    if (input$attachToExisting) {
      shinyjs::show("attach_warning")
      updateDateRangeInput(session, "dateRange_analyze",
                           label = "Select date range",
                           min = as.Date("1983-01-01"),
                           max = Sys.Date(),
                           )
      updateSelectInput(session, "climate_year_start",
                        label = "Climatology start year",
                        choices = as.character(format(as.Date("1983-01-01"), format = "%Y"):format(Sys.Date(), format = "%Y"))
                        )
      updateSelectInput(session, "climate_year_end",
                        label = "Climatology end year",
                        choices = as.character(format(as.Date("1983-01-01"), format = "%Y"):format(Sys.Date(), format = "%Y"))
                        )
    } else {
      shinyjs::hide("attach_warning")
      # TODO Can the idea of attaching be thought of when an nc object is used?
      nc <- ncdf4::nc_open(isolate(nc_path_analyze()))
      date_time <- as.Date(cmsafops::get_time(ncdf4::ncatt_get(nc, "time", "units")$value, ncdf4::ncvar_get(nc, "time")))
      ncdf4::nc_close(nc)
      updateDateRangeInput(session, "dateRange_analyze",
                                          label = "Select date range",
                                          start = min(date_time[format(date_time, "%Y") == format(max(date_time), "%Y")]),
                                          end = max(date_time),
                                          min = min(date_time),
                                          max = max(date_time)
                           )
      years <- unique(format(date_time, format = "%Y"))
      if (length(years) == 1) {
        end_year <- years[1]
      } else {
        end_year <- years[length(years) - 1]
      }

      updateSelectInput(session, "climate_year_start",
                             label = "Climatology start year",
                             choices = years,
                             selected = years[1])
      updateSelectInput(session, "climate_year_end",
                             label = "Climatology end year",
                             choices = years,
                             selected = end_year)

    }
  }, ignoreInit = TRUE)

  applyOperatorActiv <<- FALSE   # because something went wrong, when apply compare data
  # Apply the operator and show details in table.
  observeEvent(input$applyOperator, {
    req(operatorInput_value())
    req(input$usedVariable)
    
    applyOperatorActiv <<- TRUE
    
    # Disable till done.
    shinyjs::disable("applyOperator")
    shinyjs::hide("listOfOperators")
    shinyjs::show("spinner_analyze", anim = TRUE, animType = "fade")

    # Update the current operator value.
    if (currentOperatorOption() == "None") {
      currentOperatorValue(NULL)
    } else {
      if (currentOperatorOption() == "dateRange") {
        currentOperatorValue(input[["dateRange_analyze"]])
      } else {
        currentOperatorValue(input[[currentOperatorOption()]])
      }
    }

    # Create a time stamp
    time <- as.numeric(format(Sys.time(), "%H%M%S"))

    # Update outfile path
    newOutfile <- file.path(outputDir, paste0(input$usedVariable, "_", operatorInput_value(), time, ".nc"))

    if (newOutfile == nc_path_analyze()) {
      # Adding a star tag at end  to prevent equal input and output file name.
      newOutfile <- file.path(outputDir, paste0(input$usedVariable, "_", operatorInput_value(), time, "x.nc"))
    }

    # Here I chose a shorter outfile. Easily revertable.
    # newOutfile <- paste0(outputDir, "/", input$usedVariable,"_Apply.Function_", operatorInput_value(), time, ".nc")

    # Run the operator
    if (currentOperatorOption() == "None") {
      argumentList <- list(var = input$usedVariable,
                           infile = nc_path_analyze(),
                           outfile = newOutfile,
                           nc34 = input$format,
                           overwrite = TRUE,
                           nc = nc_object_analyze())
    } else if (currentOperatorOption() == "threshold") {
      argumentList <- list(var = input$usedVariable,
                           thld = input$threshold,
                           infile = nc_path_analyze(),
                           outfile = newOutfile,
                           nc34 = input$format,
                           overwrite = TRUE,
                           nc = nc_object_analyze())
	} else if (currentOperatorOption() == "constant") {
      argumentList <- list(var = input$usedVariable,
                           const = input$constant,
                           infile = nc_path_analyze(),
                           outfile = newOutfile,
                           nc34 = input$format,
                           overwrite = TRUE,
                           nc = nc_object_analyze())
    } else if (currentOperatorOption() == "region") {
      # Sellonlatbox
      argumentList <- list(var = input$usedVariable,
                           infile = nc_path_analyze(),
                           outfile = newOutfile,
                           # lon1 = input$lonRegionSlider[1],
                           # lon2 = input$lonRegionSlider[2],
                           # lat1 = input$latRegionSlider[1],
                           # lat2 = input$latRegionSlider[2],
                           lon1 = input$lonRegionMin,
                           lon2 = input$lonRegionMax,
                           lat1 = input$latRegionMin,
                           lat2 = input$latRegionMax,
                           nc34 = input$format,
                           overwrite = TRUE,
                           nc = nc_object_analyze())
    } else if (currentOperatorOption() == "point") {
      if (operatorInput_value() == "selpoint") {
        argumentList <- list(var = input$usedVariable,
                             infile = nc_path_analyze(),
                             outfile = newOutfile,
                             lon1 = input$lonPoint,
                             lat1 = input$latPoint,
                             nc34 = input$format,
                             overwrite = TRUE,
                             nc = nc_object_analyze())
      } else {
        newOutfile <- nc_path_analyze()
        format <- "nc"
        nc34 <- input$format
        if (input$format == 5) {
          format <- "csv"
          nc34 <- 3
        }
        argumentList <- list(var = input$usedVariable,
                             infile = nc_path_analyze(),
                             outpath = outputDir,
                             lon1 = as.numeric(chosen_lonPoints()),
                             lat1 = as.numeric(chosen_latPoints()),
                             nc34 = nc34,
                             format = format,
                             nc = nc_object_analyze())
        chosen_lonPoints(c())
        chosen_latPoints(c())
      }
    } else if (currentOperatorOption() == "dateRange") {
      argumentList <- list(var = input$usedVariable,
                           start = input$dateRange_analyze[1],
                           end = input$dateRange_analyze[2],
                           infile = nc_path_analyze(),
                           outfile = newOutfile,
                           nc34 = input$format,
                           overwrite = TRUE,
                           nc = nc_object_analyze())
    } else if (currentOperatorOption() == "useFastTrend") {
      trendValue <- 1
      if (!input$useFastTrend) {
        trendValue <- 2
      }
      argumentList <- list(var = input$usedVariable,
                           infile = nc_path_analyze(),
                           outfile = newOutfile,
                           option = trendValue,
                           nc34 = input$format,
                           overwrite = TRUE,
                           nc = nc_object_analyze())
    } else if (currentOperatorOption() == "percentile") {
      argumentList <- list(var = input$usedVariable,
                           p = input$percentile,
                           infile = nc_path_analyze(),
                           outfile = newOutfile,
                           nc34 = input$format,
                           overwrite = TRUE,
                           nc = nc_object_analyze())
    } else if (currentOperatorOption() == "gridbox") {
      argumentList <- list(var = input$usedVariable,
                           lonGrid = input$gridbox_lon,
                           latGrid = input$gridbox_lat,
                           infile = nc_path_analyze(),
                           outfile = newOutfile,
                           nc34 = input$format,
                           overwrite = TRUE,
                           nc = nc_object_analyze())
    } else if (currentOperatorOption() == "running") {
      argumentList <- list(var = input$usedVariable,
                           nts = input$running_nts,
                           infile = nc_path_analyze(),
                           outfile = newOutfile,
                           nc34 = input$format,
                           overwrite = TRUE,
                           nc = nc_object_analyze())
    } else if (currentOperatorOption() == "timeRange") {
      argumentList <- list(var = input$usedVariable,
                           nts = input$timeRange_nts,
                           infile = nc_path_analyze(),
                           outfile = newOutfile,
                           nc34 = input$format,
                           overwrite = TRUE,
                           nc = nc_object_analyze())
    } else if (currentOperatorOption() == "months") {
      monthList <- which(c("January", "February", "March", "April", "May",
                           "June", "July", "August", "September", "October",
                           "November", "December")
                         %in% input$months)
      argumentList <- list(var = input$usedVariable,
                           month = monthList,
                           infile = nc_path_analyze(),
                           outfile = newOutfile,
                           nc34 = input$format,
                           overwrite = TRUE,
                           nc = nc_object_analyze())
    }else if (currentOperatorOption() == "years") {
      argumentList <- list(var = input$usedVariable,
                           year = input$years,
                           infile = nc_path_analyze(),
                           outfile = newOutfile,
                           nc34 = input$format,
                           overwrite = TRUE,
                           nc = nc_object_analyze())
    }else if (currentOperatorOption() == "times") {
      argumentList <- list(var = input$usedVariable,
                           hour_min = input$times,
                           infile = nc_path_analyze(),
                           outfile = newOutfile,
                           nc34 = input$format,
                           overwrite = TRUE,
                           nc = nc_object_analyze())
    }else if (currentOperatorOption() == "method") {

      # Select second input file depending on local or remote session
      if (!isRunningLocally) {
        infile2 <- second_infile()
      } else {
        infile2 <- try( file.choose(new = TRUE) )
      }

      if (class(infile2) == "try-error") {
        # Show modal and leave silently.
        showModal(modalDialog(
          h4("An additional file is required for this operator."),
          br(),
          h4("The grid information of infile2 are the target grid for the interpolation. This File may also be an ASCII-File containing the grid information."),
          br(),
          h4("For more information please type '?cmsafops::remap' in your R console."),
          title = "No remap file given.",
          size = "l"
        ))

        # Hide spinner allow new operation and leave silently.
        shinyjs::hide("spinner_analyze")
        if (input$applyAnother) {
          shinyjs::show("listOfOperators", anim = TRUE, animType = "fade")
        }
        shinyjs::enable("applyOperator")
        req(FALSE)
      } else if (!file.exists(infile2) || !(endsWith(infile2, ".nc") || endsWith(infile2, ".txt"))) {
        # Show modal and leave silently.
        showModal(modalDialog(
          h4("The additional file needs to be a", tags$strong(".nc"), " file (or", tags$strong(".txt"), " in case of ASCII-format)."),
          br(),
          h4("For more information please type '?cmsafops::remap' in your R console."),
          title = "No remap file given.",
          size = "l"
        ))

        # Hide spinner allow new operation and leave silently.
        shinyjs::hide("spinner_analyze")
        if (input$applyAnother) {
          shinyjs::show("listOfOperators", anim = TRUE, animType = "fade")
        }
        shinyjs::enable("applyOperator")

        req(FALSE)
      }

      argumentList <- list(var = input$usedVariable,
                           infile1 = nc_path_analyze(),
                           infile2 = infile2,
                           outfile = newOutfile,
                           method = input$method,
                           nc34 = input$format,
                           overwrite = TRUE,
                           nc1 = nc_object_analyze())
    } else if (currentOperatorOption() == "file_select") {
      # Select second input file depending on local or remote session
      if (!isRunningLocally) {
        infile2 <- second_infile()
      } else {
        infile2 <- try( file.choose(new = TRUE) )
      }

      if (class(infile2) == "try-error") {
        # Show modal and leave silently.
        showModal(modalDialog(
          h4("An additional file is required for this operator."),
          br(),
          h4("If you want to add/subtract a constant value, please select the operator 'Add constant to data'/'Subtract constant from data'"),
          title = "No additional file given.",
          size = "l"
        ))

        # Hide spinner allow new operation and leave silently.
        shinyjs::hide("spinner_analyze")
        if (input$applyAnother) {
          shinyjs::show("listOfOperators", anim = TRUE, animType = "fade")
        }
        shinyjs::enable("applyOperator")
        req(FALSE)
      } else if (!file.exists(infile2) || !(endsWith(infile2, ".nc"))) {
        # Show modal and leave silently.
        showModal(modalDialog(
          h4("The additional file needs to be a", tags$strong(".nc"), " file."),
          br(),
          h4("For more information please type '?cmsafops::cmsaf.add' in your R console."),
          title = "File selection error",
          size = "l"
        ))

        # Hide spinner allow new operation and leave silently.
        shinyjs::hide("spinner_analyze")
        if (input$applyAnother) {
          shinyjs::show("listOfOperators", anim = TRUE, animType = "fade")
        }
        shinyjs::enable("applyOperator")

        req(FALSE)
      }
      argumentList <- list(var1 = input$usedVariable,
                           var2 = input$usedVariable,
                           infile1 = nc_path_analyze(),
                           infile2 = infile2,
                           outfile = newOutfile,
                           nc34 = input$format,
                           overwrite = TRUE,
                           nc1 = nc_object_analyze())
    } else if (currentOperatorOption() == "file_selection") {
      if(infile2_analyze_value() == "" || second_variable_analyze() == 0){
        
        # Hide spinner allow new operation and leave silently.
        shinyjs::hide("spinner_analyze")
        if (input$applyAnother) {
          shinyjs::show("listOfOperators", anim = TRUE, animType = "fade")
        }
        shinyjs::enable("applyOperator")
        showNotification("This operator requires a second NetCDF file. Please select a second file. ")
        req(FALSE)
      }
      
      if(operatorInput_value() == "cmsaf.adjust.two.files") {
        two_files_compare_data_vis(1)
        time <- as.numeric(format(Sys.time(), "%H%M%S"))
        newOutfile1 <- file.path(outputDir, paste0("match_data_", time, "_", cmsafops::get_basename(nc_path_analyze(), nc_object_analyze())))
        newOutfile2 <- file.path(outputDir, paste0("match_data_", time, "_", cmsafops::get_basename(infile2_analyze_value())))
    
        argumentList <- list(var1 = input$usedVariable, infile1 = nc_path_analyze(), 
                             var2 = second_variable_analyze(), infile2 = infile2_analyze_value(), 
                             outfile1 = newOutfile1, outfile2 = newOutfile2, 
                             nc34 = input$format, overwrite = FALSE, verbose = FALSE,
                             nc1 = nc_object_analyze())
      } else {
        plot_type_1d <<- operatorInput_value()
        plot_type_2d <<- operatorInput_value()
        # adjust the two input files
        temp_infile_one <- file.path(tempdir(), "infile_one_tmp.nc")
        temp_infile_two <- file.path(tempdir(), "infile_two_tmp.nc")
        
        # unlink two tmp files
        if(file.exists(temp_infile_one)){
          unlink(temp_infile_one)
        }
        if(file.exists(temp_infile_two)){
          unlink(temp_infile_two)
        }
        
        cmsafops::cmsaf.adjust.two.files(var1 = input$usedVariable, infile1 = nc_path_analyze(), 
                                         var2 = second_variable_analyze(), infile2 = infile2_analyze_value(), 
                                         outfile1 = temp_infile_one, outfile2 = temp_infile_two, 
                                         nc34 = 4, overwrite = FALSE, verbose = FALSE,
                                         nc1 = nc_object_analyze())
        
        # set the new location of input files
        nc_path_analyze(temp_infile_one)
        nc_object_analyze(NULL)
        infile2_analyze_value(temp_infile_two)
        
        argumentList <- list(var1 = input$usedVariable,
                             var2 = second_variable_analyze(),
                             infile1 = nc_path_analyze(),
                             infile2 = infile2_analyze_value(),
                             outfile = newOutfile,
                             nc34 = input$format,
                             overwrite = TRUE,
                             verbose = TRUE,
                             # This is currently always NULL but included for consistency.
                             nc1 = nc_object_analyze())
      }
    } else if(currentOperatorOption() == "compare_data") {
      if(infile2_analyze_value() == ""){
        
        # Hide spinner allow new operation and leave silently.
        shinyjs::hide("spinner_analyze")
        if (input$applyAnother) {
          shinyjs::show("listOfOperators", anim = TRUE, animType = "fade")
        }
        shinyjs::enable("applyOperator")
        showNotification("This operator requires a second NetCDF file. Please select a second file. ")
        req(FALSE)
      }
      
      compare_temp_dir <- file.path(tempdir(), "compare_temp")
      # remove if it exists
      if (dir.exists(compare_temp_dir)) {
        unlink(compare_temp_dir, recursive = TRUE)
      }

      # create new nc_temp
      if (!dir.exists(compare_temp_dir)) {
        dir.create(compare_temp_dir)
      }
      
      if((endsWith(infile2_analyze_value(), ".nc"))) {
        # Set as the filename of the nc object if it is being used.
        if (!is.null(nc_object_analyze())) analyze_file1_plot(nc_object_analyze()$filename)
        else analyze_file1_plot(nc_path_analyze())
        analyze_file2_plot(infile2_analyze_value())
        
        temp_infile_one_sel <- file.path(tempdir(), "infile_one_tmp_sel.nc")
        temp_infile_two_sel <- file.path(tempdir(), "infile_two_tmp_sel.nc")
        
        if(file.exists(temp_infile_one_sel)){
          unlink(temp_infile_one_sel)
        }
        if(file.exists(temp_infile_two_sel)){
          unlink(temp_infile_two_sel)
        }
        
        cmsafops::selperiod(var = input$usedVariable, 
                            start = input$dateRange_compare_data[1], end = input$dateRange_compare_data[2], 
                            infile = nc_path_analyze(), outfile = temp_infile_one_sel, 
                            nc34 = input$format, overwrite = TRUE,
                            nc = nc_object_analyze())
        cmsafops::selperiod(var = second_variable_analyze(), 
                            start = input$dateRange_compare_data[1], end = input$dateRange_compare_data[2], 
                            infile = infile2_analyze_value(), outfile = temp_infile_two_sel, 
                            nc34 = input$format, overwrite = TRUE)
        
        # set the new location of input files
        nc_path_analyze(temp_infile_one_sel)
        nc_object_analyze(NULL)
        infile2_analyze_value(temp_infile_two_sel)
        
        if(operatorInput_value() == "cmsaf.diff.absolute"){
          # set first operator of checkbox for dropdown visualize
          outfile_compare <- file.path(compare_temp_dir, paste0(input$usedVariable, "_", operatorInput_value(), time, ".nc"))
          if (outfile_compare == nc_path_analyze()) {
            outfile_compare <- file.path(compare_temp_dir, paste0(input$usedVariable, "_", operatorInput_value(), time, "x.nc"))
          }
          checkboxCompare_value <- operatorInput_value()
          list_compare_data[[checkboxCompare_value]] <<- outfile_compare
          #list_compare_data[[operatorInput_value()]] <<- newOutfile
          newOutfile <- outfile_compare
          argumentList <- list(var1 = input$usedVariable,
                               var2 = second_variable_analyze(),
                               infile1 = nc_path_analyze(),
                               infile2 = infile2_analyze_value(),
                               outfile = outfile_compare,
                               nc34 = input$format,
                               relative = FALSE,
                               overwrite = TRUE,
                               toolbox = TRUE,
                               nc1 = nc_object_analyze())
        } else if(operatorInput_value() == "cmsaf.diff.relative"){
          # set first operator of checkbox for dropdown visualize
          outfile_compare <- file.path(compare_temp_dir, paste0(input$usedVariable, "_", operatorInput_value(), time, ".nc"))
          if (outfile_compare == nc_path_analyze()) {
            outfile_compare <- file.path(compare_temp_dir, paste0(input$usedVariable, "_", operatorInput_value(), time, "x.nc"))
          }
          checkboxCompare_value <- operatorInput_value()
          list_compare_data[[checkboxCompare_value]] <<- outfile_compare
          #list_compare_data[[operatorInput_value()]] <<- newOutfile
          newOutfile <- outfile_compare
          argumentList <- list(var1 = input$usedVariable,
                               var2 = second_variable_analyze(),
                               infile1 = nc_path_analyze(),
                               infile2 = infile2_analyze_value(),
                               outfile = outfile_compare,
                               nc34 = input$format,
                               relative = TRUE,
                               overwrite = TRUE,
                               toolbox = TRUE,
                               nc1 = nc_object_analyze())
        } else {
          two_files_compare_data_vis(1)
          time <- as.numeric(format(Sys.time(), "%H%M%S"))
          newOutfile1 <- file.path(compare_temp_dir, paste0(input$usedVariable, "_", operatorInput_value(), "_1_", time, ".nc"))
          newOutfile2 <- file.path(compare_temp_dir, paste0(second_variable_analyze(), "_", operatorInput_value(), "_2_", time, ".nc"))
          if (newOutfile1 == nc_path_analyze()) {
            newOutfile1 <- file.path(compare_temp_dir, paste0(input$usedVariable, "_", operatorInput_value(), "_1_", time, "x.nc"))
          }
          if (newOutfile2 == nc_path_analyze()) {
            newOutfile2 <- file.path(compare_temp_dir, paste0(second_variable_analyze(), "_", operatorInput_value(), "_2_", time, "x.nc"))
          }
          checkboxCompare_value <- operatorInput_value()
          list_compare_data[[checkboxCompare_value]] <<- newOutfile1
          checkboxCompare_value <- paste0(checkboxCompare_value, "2")
          list_compare_data[[checkboxCompare_value]] <<- newOutfile2
          
          argumentList <- list(var1 = input$usedVariable, 
                               infile1 = nc_path_analyze(), 
                               var2 = second_variable_analyze(), 
                               infile2 = infile2_analyze_value(), 
                               outfile1 = newOutfile1, 
                               outfile2 = newOutfile2, 
                               nc34 = input$format, 
                               overwrite= TRUE, 
                               verbose = FALSE,
                               toolbox = TRUE,
                               nc1 = nc_object_analyze())
        } 
  
        if(length(checkboxCompareData()) > 1) {
          for(i in 2:length(checkboxCompareData())){
            # Create a time stamp
            time <- as.numeric(format(Sys.time(), "%H%M%S"))
  
            if(checkboxCompareData()[i] == "cmsaf.diff.absolute"){
              outfile_compare <- file.path(compare_temp_dir, paste0(input$usedVariable, "_", checkboxCompareData()[i], time, ".nc"))
              if (outfile_compare == nc_path_analyze()) {
                outfile_compare <- file.path(compare_temp_dir, paste0(input$usedVariable, "_", checkboxCompareData()[i], time, "x.nc"))
              }
              checkboxCompare_value <- checkboxCompareData()[i]
              list_compare_data[[checkboxCompare_value]] <<- outfile_compare
              
              argumentList_compare_data <- list(var1 = input$usedVariable,
                                               var2 = second_variable_analyze(),
                                               infile1 = nc_path_analyze(),
                                               infile2 = infile2_analyze_value(),
                                               outfile = outfile_compare,
                                               nc34 = input$format,
                                               relative = FALSE,
                                               overwrite = TRUE,
                                               toolbox = TRUE,
                                               nc1 = nc_object_analyze())
              fun <- get("cmsaf.diff", asNamespace("cmsafvis"))
            }
            else if(checkboxCompareData()[i] == "cmsaf.diff.relative"){
              outfile_compare <- file.path(compare_temp_dir, paste0(input$usedVariable, "_", checkboxCompareData()[i], time, ".nc"))
              if (outfile_compare == nc_path_analyze()) {
                outfile_compare <- file.path(compare_temp_dir, paste0(input$usedVariable, "_", checkboxCompareData()[i], time, "x.nc"))
              }
              checkboxCompare_value <- checkboxCompareData()[i]
              list_compare_data[[checkboxCompare_value]] <<- outfile_compare
              
              argumentList_compare_data <- list(var1 = input$usedVariable,
                                               var2 = second_variable_analyze(),
                                               infile1 = nc_path_analyze(),
                                               infile2 = infile2_analyze_value(),
                                               outfile = outfile_compare,
                                               nc34 = input$format,
                                               relative = TRUE,
                                               overwrite = TRUE,
                                               toolbox = TRUE,
                                               nc1 = nc_object_analyze())
              fun <- get("cmsaf.diff", asNamespace("cmsafvis"))
            } else if(checkboxCompareData()[i] == "cmsaf.stats") {
              outfile_compare <- file.path(compare_temp_dir, paste0(input$usedVariable, "_", checkboxCompareData()[i], time, ".csv"))
              if (outfile_compare == nc_path_analyze()) {
                outfile_compare <- file.path(compare_temp_dir, paste0(input$usedVariable, "_", checkboxCompareData()[i], time, "x.csv"))
              }
              checkboxCompare_value <- checkboxCompareData()[i]
              list_compare_data[[checkboxCompare_value]] <<- outfile_compare
              argumentList_compare_data <- list(var1 = input$usedVariable,
                                                var2 = second_variable_analyze(),
                                                infile1 = nc_path_analyze(),
                                                infile2 = infile2_analyze_value(),
                                                outfile = outfile_compare,
                                                nc34 = input$format,
                                                overwrite = TRUE,
                                                nc1 = nc_object_analyze())
              fun <- get("cmsaf.stats", asNamespace("cmsafops"))
              cmsaf_stats_enable(1)
            } else {
              # Update outfile path
              newOutfile1 <- file.path(compare_temp_dir, paste0(input$usedVariable, "_", checkboxCompareData()[i], "_1_", time, ".nc"))
              newOutfile2 <- file.path(compare_temp_dir, paste0(second_variable_analyze(), "_", checkboxCompareData()[i], "_2_",time, ".nc"))
              if (newOutfile1 == nc_path_analyze()) {
                newOutfile1 <- file.path(compare_temp_dir, paste0(input$usedVariable, "_", checkboxCompareData()[i], "_1_", time, "x.nc"))
              }
              if (newOutfile2 == nc_path_analyze()) {
                newOutfile2 <- file.path(compare_temp_dir, paste0(second_variable_analyze(), "_", checkboxCompareData()[i], "_2_", time, "x.nc"))
              }
              checkboxCompare_value <- checkboxCompareData()[i]
              list_compare_data[[checkboxCompare_value]] <<- newOutfile1
              checkboxCompare_value <- paste0(checkboxCompare_value, "2")
              list_compare_data[[checkboxCompare_value]] <<- newOutfile2
        
              argumentList_compare_data <- list(var1 = input$usedVariable, 
                                                infile1 = nc_path_analyze(), 
                                                var2 = second_variable_analyze(), 
                                                infile2 = infile2_analyze_value(), 
                                                outfile1 = newOutfile1, 
                                                outfile2 = newOutfile2, 
                                                nc34 = input$format, 
                                                overwrite= TRUE, 
                                                verbose = FALSE,
                                                toolbox = TRUE,
                                                nc1 = nc_object_analyze())
              fun <- get(checkboxCompareData()[i], asNamespace("cmsafvis"))
            } 
            try(do.call(fun, argumentList_compare_data))
          }
        }
      } else {
        if (!is.null(nc_object_analyze())) analyze_file1_plot(nc_object_analyze()$filename)
        else analyze_file1_plot(nc_path_analyze())
        analyze_file2_plot(infile2_analyze_value())
        
        if(operatorInput_value() %in% c("cmsaf.diff.absolute", "cmsaf.diff.relative")) {
          outfile_compare <- file.path(compare_temp_dir, paste0(input$usedVariable, "_", operatorInput_value(), time, ".nc"))
          if (outfile_compare == nc_path_analyze()) {
            outfile_compare <- file.path(compare_temp_dir, paste0(input$usedVariable, "_", operatorInput_value(), time, "x.nc"))
          }
          checkboxCompare_value <- operatorInput_value()
          list_compare_data[[checkboxCompare_value]] <<- outfile_compare
          newOutfile <- outfile_compare
          cmsafops::selperiod(var = input$usedVariable, 
                              start = input$dateRange_compare_data[1], end = input$dateRange_compare_data[2], 
                              infile = nc_path_analyze(), outfile = outfile_compare, 
                              nc34 = input$format, overwrite = TRUE,
                              nc = nc_object_analyze())
        } else {
          two_files_compare_data_vis(1)
          time <- as.numeric(format(Sys.time(), "%H%M%S"))
          newOutfile1 <- file.path(compare_temp_dir, paste0(input$usedVariable, "_", operatorInput_value(), "_1_", time, ".nc"))
          if (newOutfile1 == nc_path_analyze()) {
            newOutfile1 <- file.path(compare_temp_dir, paste0(input$usedVariable, "_", operatorInput_value(), "_1_", time, "x.nc"))
          }
          
          checkboxCompare_value <- operatorInput_value()
          list_compare_data[[checkboxCompare_value]] <<- newOutfile1
          checkboxCompare_value <- paste0(checkboxCompare_value, "2")
          list_compare_data[[checkboxCompare_value]] <<- infile2_analyze_value()
          cmsafops::selperiod(var = input$usedVariable, 
                              start = input$dateRange_compare_data[1], end = input$dateRange_compare_data[2], 
                              infile = nc_path_analyze(), outfile = newOutfile1, 
                              nc34 = input$format, overwrite = TRUE,
                              nc = nc_object_analyze())
        }
        
        if(length(checkboxCompareData()) > 1) {
          for(i in 2:length(checkboxCompareData())) {
            if(checkboxCompareData()[i] == "cmsaf.diff.absolute") {
              outfile_compare <- file.path(compare_temp_dir, paste0(input$usedVariable, "_", checkboxCompareData()[i], time, ".nc"))
              if (outfile_compare == nc_path_analyze()) {
                outfile_compare <- file.path(compare_temp_dir, paste0(input$usedVariable, "_", checkboxCompareData()[i], time, "x.nc"))
              }
              checkboxCompare_value <- checkboxCompareData()[i]
              list_compare_data[[checkboxCompare_value]] <<- outfile_compare
              
              cmsafops::selperiod(var = input$usedVariable, 
                                  start = input$dateRange_compare_data[1], end = input$dateRange_compare_data[2], 
                                  infile = nc_path_analyze(), outfile = outfile_compare, 
                                  nc34 = input$format, overwrite = TRUE,
                                  nc = nc_object_analyze())
            } else if(checkboxCompareData()[i] == "cmsaf.diff.relative") {
              outfile_compare <- file.path(compare_temp_dir, paste0(input$usedVariable, "_", checkboxCompareData()[i], time, ".nc"))
              if (outfile_compare == nc_path_analyze()) {
                outfile_compare <- file.path(compare_temp_dir, paste0(input$usedVariable, "_", checkboxCompareData()[i], time, "x.nc"))
              }
              checkboxCompare_value <- checkboxCompareData()[i]
              list_compare_data[[checkboxCompare_value]] <<- outfile_compare
              
              cmsafops::selperiod(var = input$usedVariable, 
                                  start = input$dateRange_compare_data[1], end = input$dateRange_compare_data[2], 
                                  infile = nc_path_analyze(), outfile = outfile_compare, 
                                  nc34 = input$format, overwrite = TRUE,
                                  nc = nc_object_analyze())
            } else if(checkboxCompareData()[i] == "cmsaf.stats") {
              outfile_compare <- file.path(compare_temp_dir, paste0(input$usedVariable, "_", checkboxCompareData()[i], time, ".csv"))
              if (outfile_compare == nc_path_analyze()) {
                outfile_compare <- file.path(compare_temp_dir, paste0(input$usedVariable, "_", checkboxCompareData()[i], time, "x.csv"))
              }
              checkboxCompare_value <- checkboxCompareData()[i]
              list_compare_data[[checkboxCompare_value]] <<- outfile_compare
              
              cmsafops::cmsaf.stats.station.data(
                var = input$usedVariable,
                infile = nc_path_analyze(),
                data_station = station_data_compare(),
                outfile = outfile_compare,
                overwrite = TRUE,
                nc = nc_object_analyze()
              )
              cmsaf_stats_enable(1)
            } else {
              newOutfile1 <- file.path(compare_temp_dir, paste0(input$usedVariable, "_", checkboxCompareData()[i], "_1_", time, ".nc"))
              if (newOutfile1 == nc_path_analyze()) {
                newOutfile1 <- file.path(compare_temp_dir, paste0(input$usedVariable, "_", checkboxCompareData()[i], "_1_", time, "x.nc"))
              }
              checkboxCompare_value <- checkboxCompareData()[i]
              list_compare_data[[checkboxCompare_value]] <<- newOutfile1
              checkboxCompare_value <- paste0(checkboxCompare_value, "2")
              list_compare_data[[checkboxCompare_value]] <<- infile2_analyze_value()
              
              cmsafops::selperiod(var = input$usedVariable, 
                                  start = input$dateRange_compare_data[1], end = input$dateRange_compare_data[2], 
                                  infile = nc_path_analyze(), outfile = newOutfile1, 
                                  nc34 = input$format, overwrite = TRUE,
                                  nc = nc_object_analyze())
            }
          }
        }
      }
    }
    else if (currentOperatorOption() == "monitor_climate") {
      # THE MONITOR CLIMATE FROM CMSAFVIS
      if (input$plot_format == "graphic") {
        fileext <- ".png"
      }  else {
        fileext <- ".mp4"
      }
      
      if(operatorInput_value() %in% c("warming_stripes_plot", "time_series_plot", "trend_plot")){
        fileext <- ".png"
      }

      #monitor_climate_out_dir <- tempdir()
      monitor_climate_temp_dir <- file.path(outputDir, "mc_temp")
      if (!dir.exists(monitor_climate_temp_dir)) {
        dir.create(monitor_climate_temp_dir)
      }

      monitor_climate_out_dir <- file.path(outputDir)

      monitor_climate_outfile <- paste0(input$usedVariable, "_", operatorInput_value(), time, fileext)
      monitor_climate_outfile_path <- file.path(monitor_climate_out_dir, monitor_climate_outfile)

      if (input$attachToExisting) {
      # Select second input file depending on local or remote session
      if (!isRunningLocally) {
        infile_attach <- second_infile()
      } else {
        infile_attach <- try( file.choose(new = TRUE) )
      }

      if (class(infile_attach) == "try-error") {
        # Show modal and leave silently.
        showModal(modalDialog(
          h4("An additional file is required for this operator."),
          br(),
          h4("If you want to add/subtract a constant value, please select the operator 'Add constant to data'/'Subtract constant from data'"),
          title = "No additional file given.",
          size = "l"
        ))

        # Hide spinner allow new operation and leave silently.
        shinyjs::hide("spinner_analyze")
        if (input$applyAnother) {
          shinyjs::show("listOfOperators", anim = TRUE, animType = "fade")
        }
        shinyjs::enable("applyOperator")
        req(FALSE)
      } else if (!file.exists(infile_attach) || !(endsWith(infile_attach, ".nc"))) {
        # Show modal and leave silently.
        showModal(modalDialog(
          h4("The additional file needs to be a", tags$strong(".nc"), " file."),
          br(),
          h4("For more information please type '?cmsafvis::monitor_climate' in your R console."),
          title = "File selection error",
          size = "l"
        ))

        # Hide spinner allow new operation and leave silently.
        shinyjs::hide("spinner_analyze")
        if (input$applyAnother) {
          shinyjs::show("listOfOperators", anim = TRUE, animType = "fade")
        }
        shinyjs::enable("applyOperator")

        req(FALSE)
      }
      } else {
      infile_attach <- "auto"
    }

      argumentList <- list(
        plot_type = operatorInput_value(),
        infile = nc_path_analyze(),
        accumulate = input$accumulateInfile,   # if true: accumulate infile
        mean_value = !(input$accumulateInfile),   # if true: mean infile
        variable = input$usedVariable,
        output_format = input$plot_format,
        animation_pace = input$animation_pace,
        freeze_animation = FALSE,
        lang = "eng",
        outfile_name = monitor_climate_outfile,
        start_date = input$dateRange_analyze[1],
        end_date = input$dateRange_analyze[2],
        country_code = input$country,
        # lon_min = input$lonRegionSlider[1],
        # lon_max = input$lonRegionSlider[2],
        # lat_min = input$latRegionSlider[1],
        # lat_max = input$latRegionSlider[2],
        lon_min = input$lonRegionMin,
        lon_max = input$lonRegionMax,
        lat_min = input$latRegionMin,
        lat_max = input$latRegionMax,
        out_dir = monitor_climate_out_dir,
        temp_dir = monitor_climate_temp_dir,
        climate_dir = monitor_climate_temp_dir,
        attach = input$attachToExisting,
        infile_attach = infile_attach
      )

      if (operatorInput_value() != "absolute_map") {
        argumentList <- append(
          argumentList,
          list(
            climate_year_start = as.numeric(input$climate_year_start),
            climate_year_end = as.numeric(input$climate_year_end)
          )
        )
      }
	  
	  if (operatorInput_value() == "anomaly_map") {
        argumentList <- append(
          argumentList,
          list(
            color_pal = as.numeric(input$stripecol),
            relative  = as.logical(input$absrel)
          )
        )
      }
      
      if(operatorInput_value() %in% c("time_series_plot", "trend_plot")){
        argumentList <- append(
          argumentList,
          list(
            analyze_method = input$monitorClimateAnalyzeMethod,
            selected_number = as.numeric(input$analyzeTimeSize)
          )
        )
      }
      if(operatorInput_value() %in% c("warming_stripes_plot")){
        argumentList <- append(
          argumentList,
          list(
            analyze_method = input$monitorClimateAnalyzeMethod,
            selected_number = as.numeric(input$analyzeTimeSize),
            color_pal = as.numeric(input$stripecol),
            circ_plot = as.numeric(input$circular)
          )
        )
      }
    }

    climate_analysis_ops <- c("absolute_map", "anomaly_map", "climatology_map", "fieldmean_plot", "fieldmean_and_anomaly_map", 
                              "warming_stripes_plot", "time_series_plot", "trend_plot")

    # Get package and function
    if (operatorInput_value() %in% climate_analysis_ops) {
      fun <- get("monitor_climate", asNamespace("cmsafvis"))
    } else if(operatorInput_value() %in% operatorOptionsDict[["compare_data"]]) {
      if((endsWith(infile2_analyze_value(), ".nc"))) {
        if(operatorInput_value() == "cmsaf.diff.absolute" || operatorInput_value() == "cmsaf.diff.relative") {
          fun <- get("cmsaf.diff", asNamespace("cmsafvis"))
        } else {
          fun <- get(operatorInput_value(), asNamespace("cmsafvis"))
        }
      }
    }
    else {
      fun <- get(operatorInput_value(), asNamespace("cmsafops"))
    }
    
    if((endsWith(infile2_analyze_value(), ".nc")) || (infile2_analyze_value() == "")) {   # if second file is a nc-file or no second file is available
      res <- try(do.call(fun, argumentList))
    } else {
      res <- ""
    }
    
    # Error handling
    if (class(res) == "try-error") {
      showModal(modalDialog(
        h4("An error occured while applying the operator."),
        tags$p(paste0("Message: ", res)),
        title = "Error!",
        size = "l"
      ))
    } else {
      shinyjs::hide("add_point")
      # No error. Continue with rest.

      # If monitor climate store png/mp4 paths
      if (operatorInput_value() %in% climate_analysis_ops) {
        image_path_visualize( monitor_climate_outfile_path )
        actionVisualizeMonitorClimate(actionVisualizeMonitorClimate() + 1)

        shinyjs::hide("spinner_analyze")
        if (input$applyAnother) {
          shinyjs::show("listOfOperators", anim = TRUE, animType = "fade")
        }
        shinyjs::enable("applyOperator")
        return()
      } else {
        if(two_files_compare_data_vis() == 1){   # two files to visualize 
          operator_Input2 <- paste0(operatorInput_value(), "2")
          nc_path_analyze(list_compare_data[[operatorInput_value()]])
          nc_object_analyze(NULL)
          infile2_analyze_value(list_compare_data[[operator_Input2]])
          nc_path_visualize(list_compare_data[[operatorInput_value()]])
          nc_object_visualize(NULL)
          nc_path_visualize_2(list_compare_data[[operator_Input2]])
        } else {
          if((endsWith(infile2_analyze_value(), ".nc"))) {
            nc_path_analyze(newOutfile)
            nc_object_analyze(NULL)
            nc_path_visualize(newOutfile)
            nc_object_visualize(NULL)
          } else {
            nc_path_analyze(newOutfile)
            nc_object_analyze(NULL)
            nc_path_visualize(newOutfile)
            nc_object_visualize(NULL)
          }
        }
      }

      # Variable 'isRunningLocally' can be found in global.R
      if (repeatWarning() && !isRunningLocally) {
        showModal(modalDialog(
          tags$p("A .nc file has been created for you. ",
                 "Its contents are temporarily stored in the session folder.",
                 "Please download the session folder if you want to save it.",
                 "All files will be removed after closing this app!"),
          checkboxInput("noRepeat", "Do not show this message again."),
          title = "Warning to prevent data loss!",
          size = "l"
        ))
      }

      if (input$applyAnother) {
        # Depending on operator give option details.
        if (currentOperatorOption() == "None") {
          newRow <- data.frame(operatorInput_value(), "None", "None")
        } else if (currentOperatorOption() == "point") {
          newRow <- data.frame(operatorInput_value(), "point", paste0("lat: ", input$latPoint, ", lon: ", input$lonPoint))
        } else if (currentOperatorOption() == "region") {
          # newRow <- data.frame(operatorInput_value(), "region", paste0("lat: [", input$latRegionSlider[1], " ", input$latRegionSlider[2], "], ",
          #                                                            "lon: [", input$lonRegionSlider[1], " ", input$lonRegionSlider[2], "]"))
          newRow <- data.frame(operatorInput_value(), "region", paste0("lat: [", input$latRegionMin, " ", input$latRegionMax, "], ",
                                                                       "lon: [", input$lonRegionMin, " ", input$lonRegionMax, "]"))
        } else if (currentOperatorOption() == "dateRange") {
          newRow <- data.frame(operatorInput_value(), "dateRange", paste0("from ", input$dateRange_analyze[1], " to ", input$dateRange_analyze[1]))
        } else {
          newRow <- data.frame(operatorInput_value(), currentOperatorOption(), input[[currentOperatorOption()]])
        }

        lastCols <- data.frame(cmsafops::get_basename(newOutfile))
        newRow <- cbind(newRow, lastCols)

        # Give the row names.
        names(newRow) <- c("Operator", "Option", "Value", "Output File")
        # Bind row to table
        if (nrow(operatorDataFrame)) {
          operatorDataFrame <<- rbind(operatorDataFrame, newRow)
          operatorDataFrameAction(operatorDataFrameAction() + 1)
        } else {
          operatorDataFrame <<- newRow
          operatorDataFrameAction(operatorDataFrameAction() + 1)
        }
      } else if (input$instantlyVisualize) {
        # Switching to visualize screen.
        actionVisualize(actionVisualize() + 1)
      } else {
        # Remove spinner here and reset to analyze.
        resetToAnalyzePanel()
      }
    }

    # Either way allow to apply another operator and remove spinner.
    shinyjs::hide("spinner_analyze")
    if (input$applyAnother) {
      shinyjs::show("listOfOperators", anim = TRUE, animType = "fade")
    }
    shinyjs::enable("applyOperator")

  }, ignoreInit = TRUE)

  observeEvent({
    actionVisualize()
    action_visualize_post_modal()
  },{
    shinyjs::hide("downloadExitMonitorClimate")
    shinyjs::hide("myImage_monitorClimate")
    shinyjs::show("downloadExit")
  })

  observeEvent(actionVisualizeMonitorClimate(), {
    shinyjs::hide("downloadExit")
    shinyjs::show("downloadExitMonitorClimate")
  })
  
  # second file with variable
  observeEvent(input$file_selection_button, {
    # Select second input file depending on local or remote session
    if (!isRunningLocally) {
      infile2 <- second_infile()
    } else {
      infile2 <- try( file.choose(new = TRUE) )
    }
    
    if (class(infile2) != "try-error") {
      if((endsWith(infile2, ".nc"))) {
        station_data_compare(0)
        infile2_analyze_value(infile2)
        id <- ncdf4::nc_open(infile2)
        variable_second <- names(id$var)
        
        showModal(modalDialog(
          h4("It seems that you have selected a second file. Please select a variable to continue."),
          br(),
          fluidRow(column(7, selectInput(inputId = "second_variable_analyze",
                                         label = "Please choose a variable.",
                                         choices = variable_second)),
                   column(5, actionButton("action_visualize_two_variables",
                                          "Using this variable.",
                                          width = "100%"))),
          title = "We need your help.",
          size = "l",
          footer = NULL
        ))
      } else if((endsWith(infile2, ".RData"))){
        infile2_analyze_value(infile2)
        station_rdata <- get(load(infile2))
        station_data_compare(as.data.frame(station_rdata))
        showModal(modalDialog(
          h4("It seems that you have selected a .RData file. "),
          br(),
          fluidRow(column(5, actionButton("action_visualize_two_variables",
                                          "Using this file.",
                                          width = "100%"))),
          title = "We need your help.",
          size = "l",
          footer = NULL
        ))
      } else if((endsWith(infile2, ".csv"))){
        infile2_analyze_value(infile2)
        station_csv <- utils::read.csv(infile2,header = TRUE, sep = ";")
        station_data_compare(as.data.frame(station_csv))
        showModal(modalDialog(
          h4("It seems that you have selected a .csv file. "),
          br(),
          fluidRow(column(5, actionButton("action_visualize_two_variables",
                                          "Using this file.",
                                          width = "100%"))),
          title = "We need your help.",
          size = "l",
          footer = NULL
        ))
      }
    } else {
      station_data_compare(0)
      showModal(modalDialog(
        h4("An additional file is required for this operator."),
        title = "No additional file given.",
        size = "l"
      ))
      
      # Hide spinner allow new operation and leave silently.
      shinyjs::hide("spinner_analyze")
      if (input$applyAnother) {
        shinyjs::show("listOfOperators", anim = TRUE, animType = "fade")
      }
      shinyjs::enable("applyOperator")
      req(FALSE)
    }
  })
  
  observeEvent(input$action_visualize_two_variables, {
    if(endsWith(infile2_analyze_value(), ".nc")) {
      # Update the variable
      second_variable_analyze(input$second_variable_analyze)
      
      # Show selected file name in UI
      output$ncFile_analyze_second_file <- renderUI({
        tags$pre("You selected the following .nc file: ",
                 cmsafops::get_basename(infile2_analyze_value()))
      })
      shinyjs::show("ncFile_analyze_second_file")
      
      if(currentOperatorOption() == "compare_data"){
        list_date_range <- cmsafops::calc_overlapping_time(var1 = input$usedVariable, infile1 = nc_path_analyze(), 
                                                           var2 = second_variable_analyze(), infile2 = infile2_analyze_value())
        
        # Show date range of second file
        start_date_reac(list_date_range[[1]])
        end_date_reac(list_date_range[[2]])
        
        output$date_range_compare_data <- renderUI({
          dateRangeInput(inputId = "dateRange_compare_data",
                         label = "Please select a date range.",
                         start = start_date_reac(),
                         end = end_date_reac(),
                         min = start_date_reac(),
                         max = end_date_reac(),
                         startview = "year"
          )
        })
        shinyjs::show("date_range_compare_data")
      }
    } else {
      # Show selected file name in UI
      output$ncFile_analyze_second_file <- renderUI({
        tags$pre("You selected the following file: ",
                 cmsafops::get_basename(infile2_analyze_value()))
      })
      shinyjs::show("ncFile_analyze_second_file")
      
      if(currentOperatorOption() == "compare_data") {
        list_date_range <- cmsafops::calc_overlapping_time(var1 = input$usedVariable, infile1 = nc_path_analyze(), 
                                                           var2 = second_variable_analyze(), infile2 = infile2_analyze_value(),
                                                           nc1 = nc_object_analyze())
        
        # Show date range of second file
        start_date_reac(list_date_range[[1]])
        end_date_reac(list_date_range[[2]])
        
        output$date_range_compare_data <- renderUI({
          dateRangeInput(inputId = "dateRange_compare_data",
                         label = "Please select a date range.",
                         start = start_date_reac(),
                         end = end_date_reac(),
                         min = start_date_reac(),
                         max = end_date_reac(),
                         startview = "year"
          )
        })
        shinyjs::show("date_range_compare_data")
      }
    }
    # This will remove the modal.
    removeModal()
  })

  #### VISUALIZE ####
  getVariableData <- function(timestep_index, id, var) {
    return(ncdf4::ncvar_get(id, var, start = c(1, 1, timestep_index), count = c(-1, -1, 1)))
  }

  # A function to read all required information from nc file
  # that's needed for the visualize options.
  # Also sets the correct image width and height.
  get_visualize_options <- function(infile, var, infile2 = NULL, var2 = NULL,
                                    nc1 = NULL, nc2 = NULL) {
    # Open file and get data
    if (!is.null(nc1)) id <- nc1
    else id <- ncdf4::nc_open(infile)
    # Remap to regGrid if necessary
    file_info <- cmsafops:::check_dims(id)
    if (is.null(nc1)) ncdf4::nc_close(id)
    if (!file_info$isRegGrid) {
      remap_timestamp <- format(Sys.time(), "%Y%m%d%H%M%S", tz = "UTC")
      remap_name <- paste0("remap_", remap_timestamp, ".nc")
      outfile <- file.path(userDir, remap_name)
      # grid_filepath can be  found in global.R
      cmsafops::remap(var, infile, grid_filepath, outfile, overwrite = TRUE, nc1 = nc1)
      infile <- outfile
      # To prevent nc1 being used in place of outfile.
      nc1 <- NULL
      nc_path_visualize(infile)
      nc_object_visualize(NULL)
    }
    
    if((!is.null(nc2) || !is.null(infile2)) && (endsWith(infile2_analyze_value(), ".nc"))) {
      if (!is.null(nc2)) id2 <- nc2
      else id2 <- ncdf4::nc_open(infile2)
      
      lon2 <- ncdf4::ncvar_get(id2, "lon")
      lat2 <- ncdf4::ncvar_get(id2, "lat")
      
      data2 <- try(ncdf4::ncvar_get(id2, var2, collapse_degen = FALSE))
      if (all(is.na(data2))) {
        stop("The second file you are trying to visualize constains only NA values.")
      }
    }
    # Open file and get data
    if (!is.null(nc1)) id <- nc1
    else id <- ncdf4::nc_open(infile)

    lon <- ncdf4::ncvar_get(id, "lon")
    lat <- ncdf4::ncvar_get(id, "lat")
    
    data <- try(ncdf4::ncvar_get(id, var, collapse_degen = FALSE))

    if (all(is.na(data))) {
      stop("The file you are trying to visualize constains only NA values.")
    }

    visualizeDataTimestep(getVariableData(1, id, var))
    
    date <- ncdf4::ncvar_get(id, "time")
    t_unit <- ncdf4::ncatt_get(id, "time", "units")$value
    date.time <- as.character(cmsafops::get_time(t_unit, date))
    
    unit <- ncdf4::ncatt_get(id, var, "units")$value
    if (unit == 0)
      (unit <- "-")
    vn <- var
    varname <- ncdf4::ncatt_get(id, var, "long_name")$value
    if (varname == 0)
      (varname <- ncdf4::ncatt_get(id, var, "standard_name")$value)
    if (varname == 0)
      (varname <- var)
    
    time_bounds = NULL
    if (file_info$has_time_bnds){
      time_bound0 <- ncdf4::ncvar_get(id, "time_bnds", collapse_degen = FALSE)
      time_bound1 <- as.character(cmsafops::get_time(t_unit, time_bound0[1,]))
      time_bound2 <- as.character(cmsafops::get_time(t_unit, time_bound0[2,]))
      if (startsWith(t_unit, "hours") & nchar(time_bound1[1]) > 10) {
        time_bound1 <- as.POSIXct(time_bound1, format = "%Y-%m-%d %R")
        time_bound2 <- as.POSIXct(time_bound2, format = "%Y-%m-%d %R")
      } else {
        time_bound1 <- as.Date(time_bound1)
        time_bound2 <- as.Date(time_bound2)
      }
      for (i in seq_along(time_bound1)){
        time_bounds <- append(time_bounds, paste(time_bound1[i], " \u2013 ", time_bound2[i], sep = "")) 
      }
    }

    creator_att <- ncdf4::ncatt_get(id, 0, "institution")
    if (!creator_att$hasatt) {
      creator_att <- ncdf4::ncatt_get(id, 0, "publisher_name")
      if (!creator_att$hasatt) {
        creator_att <- ncdf4::ncatt_get(id, 0, "creator_name")  
      } 
    } 
    creator <- ifelse(creator_att$hasatt, creator_att$value, "-")
    copyrightText <- paste0("Data Source: ", creator)

    if (is.null(nc1)) ncdf4::nc_close(id)

    # In HOAPS files problems can occur due to different sorted values
    # check data dimensions

    validData <- (class(data) != "try-error")

    reversedDimensions$transpose  <- FALSE
    reversedDimensions$lonReverse <- FALSE
    reversedDimensions$latReverse <- FALSE
    if(length(lon) > 1 && length(lat) > 1){   # added this, because of some new operators (eg.zon and mer)
      if (dim(visualizeDataTimestep())[1] != length(lon)) {
        if (dim(visualizeDataTimestep())[2] == length(lon)) {
          reversedDimensions$transpose <- TRUE
          visualizeDataTimestep(aperm(visualizeDataTimestep(), c(2, 1)))
          if (validData) {
            data <- aperm(data, c(2, 1, 3))
          }
        }
      }
    }
    
    # check longitude
    if (lon[1] > lon[length(lon)]) {
      reversedDimensions$lonReverse <- TRUE
      lon <- rev(lon)

      visualizeDataTimestep(visualizeDataTimestep()[rev(seq_len(length(lon))), ])
      if (validData) {
        if (dim(data)[3] == 1) {
          data[, , 1] <- data[rev(seq_len(length(lon))), , ]
        } else {
          data <- data[rev(seq_len(length(lon))), , ]
        }
      }
    }
    # check latitude
    if (lat[1] > lat[length(lat)]) {
      lat <- rev(lat)
      reversedDimensions$latReverse <- TRUE
      visualizeDataTimestep(visualizeDataTimestep()[, rev(seq_len(length(lat)))])

      if (validData) {
        if (dim(data)[3] == 1) {
          data[, , 1] <- data[, rev(seq_len(length(lat))), ]
        } else {
          data <- data[, rev(seq_len(length(lat))), ]
        }
      }
    }
    
    if(!is.null(nc2) || !is.null(infile2)) { # Returning compare data plots for two files
      #visualizeDataTimestep(getVariableData(1, id2, var2))
      if((endsWith(infile2_analyze_value(), ".nc"))) {
        date2 <- ncdf4::ncvar_get(id2, "time")
        t_unit2 <- ncdf4::ncatt_get(id2, "time", "units")$value
        date.time2 <- as.character(cmsafops::get_time(t_unit2, date2))
        
        unit2 <- ncdf4::ncatt_get(id2, var2, "units")$value
        if (unit2 == 0)
          (unit2 <- "-")
        vn2 <- var2
        varname2 <- ncdf4::ncatt_get(id2, var2, "long_name")$value
        if (varname2 == 0)
          (varname2 <- ncdf4::ncatt_get(id2, var2, "standard_name")$value)
        if (varname2 == 0)
          (varname2 <- var2)
        
        creator_att2 <- ncdf4::ncatt_get(id2, 0, "publisher_name")
        if (!creator_att2$hasatt) {
          creator_att2 <- ncdf4::ncatt_get(id2, 0, "creator_name")  
        } 
        creator2 <- ifelse(creator_att2$hasatt, creator_att2$value, "-")
        copyrightText2 <- paste0("Data Source: ", creator2)
        
        ylabel <- paste0(varname2, " [", unit2, "]")
        
        if (is.null(nc2)) ncdf4::nc_close(id2)
      }
      visualizeDataMin(min(data, na.rm = TRUE))
      visualizeDataMax(max(data, na.rm = TRUE))
      
      # if (startsWith(t_unit, "hours")) {
      #   date.time <- as.POSIXct(date.time, format = "%Y-%m-%d %R")
      # } else {
      #date.time <- as.Date(date.time)
      #}
      
      fit <- stats::lm(as.vector(data) ~ c(seq_along(data)))
      dummy <- fit$fitted.values
      if (sum(!is.na(data)) == length(dummy)) {
        fitted <- data
        fitted[which(!is.na(fitted))] <- dummy
        rm(dummy)
      }
      
      xlabel <- paste0(varname, " [", unit, "]")
      x_range <- length(date.time)
      
      
      # Returning 2D plot information (for side by side plot)
      min_lon <- min(lon, na.rm = TRUE)
      max_lon <- max(lon, na.rm = TRUE)
      
      min_lat <- min(lat, na.rm = T)
      max_lat <- max(lat, na.rm = T)
      
      if (class(data) != "try-error") {
        min_data <- min(data, na.rm = TRUE)
        max_data <- max(data, na.rm = TRUE)
        
        if (round(min_data, digits = 1) == round(max_data, digits = 1)) {
          min_data <- min_data - 0.05
          max_data <- max_data + 0.05
        }
        
        visualizeDataMin(min_data)
        visualizeDataMax(max_data)
      }
      
      if(checkboxCompareData_dropdown() == "cmsaf.side.by.side"){
        plot_dim_value = 2
      } else {
        date.time <- as.Date(date.time)
        plot_dim_value = 1
      }
      if((endsWith(infile2_analyze_value(), ".nc"))) {
        return(
          list(
            plot_type = checkboxCompareData_dropdown(),
            plot_dim = plot_dim_value,
            min_lon = min_lon,
            max_lon = max_lon,
            min_lat = min_lat,
            max_lat = max_lat,
            data = data,
            data2 = data2,
            date.time = date.time,
            time_bounds = time_bounds,
            x_range = x_range,
            ylabel = ylabel,
            xlabel = xlabel,
            vn = vn,
            vn2 = vn2,
            varname = varname,
            varname2 = varname2,
            file_name = infile,
            file_name2 = infile2,
            unit = unit,
            lat = lat,
            lon = lon,
            fitted = fitted,
            copyrightText = copyrightText,
            nc = nc1,
            nc2 = nc2
          )
        )
      } else {   # actual .RData and csv files
        if(checkboxCompareData_dropdown() == "cmsaf.time.series") {
          station_data_time_series_plot <- cmsafvis::helper_time_series_compare(list(
            data = data,
            data2 = station_data_compare(),
            date.time = date.time,
            lat = lat,
            lon = lon
          ))
        } else {
          station_data_time_series_plot <- list()
        }
        ylabel <- paste0(varname, " [", unit, "]")
        return(
          list(
            plot_type = checkboxCompareData_dropdown(),
            plot_dim = plot_dim_value,
            min_lon = min_lon,
            max_lon = max_lon,
            min_lat = min_lat,
            max_lat = max_lat,
            data = data,
            data2 = station_data_compare(),
            data3 = station_data_time_series_plot,   # only for time series plot (compare data)
            date.time = date.time,
            time_bounds = time_bounds,
            x_range = x_range,
            ylabel = ylabel,
            xlabel = xlabel,
            vn = vn,
            varname = varname,
            file_name = infile,
            unit = unit,
            lat = lat,
            lon = lon,
            fitted = fitted,
            copyrightText = copyrightText,
            nc = nc1,
            nc2 = NULL
          )
        )
      }
    } else if (length(lon) == 1 && length(lat) == 1) {   # Returning 1D plot information
      min_lon <- lon
      max_lon <- lon
      min_lat <- lat
      max_lat <- lat

      visualizeDataMin(min(data, na.rm = TRUE))
      visualizeDataMax(max(data, na.rm = TRUE))
      x_range <- length(data)
      ltype <- c("l", "p", "o", "s", "h")
      
      if (startsWith(t_unit, "hours") & nchar(date.time[1]) > 10) {
        date.time <- as.POSIXct(date.time, format = "%Y-%m-%d %R")
      } else {
        date.time <- as.Date(date.time)
      }
      
      fit <- stats::lm(as.vector(data) ~ c(seq_along(data)))
      dummy <- fit$fitted.values
      if (sum(!is.na(data)) == length(dummy)) {
        fitted <- data
        fitted[which(!is.na(fitted))] <- dummy
        rm(dummy)
      }
      ylabel <- paste0(varname, " [", unit, "]")
    
      return(
        list(
          plot_type = plot_type_1d,
          plot_dim = 1,
          data = data,
          date.time = date.time,
          time_bounds = time_bounds,
          x_range = x_range,
          ylabel = ylabel,
          vn = vn,
          varname = varname,
          unit = unit,
          lat = lat,
          lon = lon,
          fitted = fitted,
          copyrightText = copyrightText
        )
      )
    } else if ((length(lon) == 1 && length(lat) != 1) ||
               (length(lon) != 1 && length(lat) == 1)) {   # plot x-axis: lat or lon and y-axis: data
      # Rendering 1D Plot information
      if(length(lon) == 1 && length(lat) != 1){    # x-axis is lat
        x_range <- length(lat)
      } else if(length(lon) != 1 && length(lat) == 1){    # x-axis is lon
        x_range <- length(lon)
      }
      
      visualizeDataMin(min(data, na.rm = TRUE))
      visualizeDataMax(max(data, na.rm = TRUE))
      
      if (startsWith(t_unit, "hours") & nchar(date.time[1]) > 10) {
        date.time <- as.POSIXct(date.time, format = "%Y-%m-%d %R")
      } else {
        date.time <- as.Date(date.time)
      }
      
      fit <- stats::lm(as.vector(data) ~ c(seq_along(data)))
      dummy <- fit$fitted.values
      if (sum(!is.na(data)) == length(dummy)) {
        fitted <- data
        fitted[which(!is.na(fitted))] <- dummy
        rm(dummy)
      }
      ylabel <- paste0(varname, " [", unit, "]")
      
      return(
        list(
          plot_dim = 1,
          data = data,
          date.time = date.time,
          time_bounds = time_bounds,
          x_range = x_range,
          ylabel = ylabel,
          vn = vn,
          varname = varname,
          unit = unit,
          lat = lat,
          lon = lon,
          fitted = fitted,
          copyrightText = copyrightText
        )
      )
    } else if(length(lon) != 1 && length(lat) != 1) {
      # Returning 2D plot information
      min_lon <- min(lon, na.rm = TRUE)
      max_lon <- max(lon, na.rm = TRUE)

      min_lat <- min(lat, na.rm = T)
      max_lat <- max(lat, na.rm = T)

      if (class(data) != "try-error") {
        min_data <- min(data, na.rm = TRUE)
        max_data <- max(data, na.rm = TRUE)

        if (round(min_data, digits = 1) == round(max_data, digits = 1)) {
          min_data <- min_data - 0.05
          max_data <- max_data + 0.05
        }

        visualizeDataMin(min_data)
        visualizeDataMax(max_data)
      }
      
      if(!(endsWith(analyze_file2_plot(), ".nc"))){   # second file station data for compare diff plot
        plot_station_data = 1;
      } else {
        plot_station_data = 0;
      }
    
      return(
        list(
          plot_type = checkboxCompareData_dropdown(),
          plot_station_data = plot_station_data,
          plot_dim = 2,
          data = data,
          date.time = date.time,
          time_bounds = time_bounds,
          min_lon = min_lon,
          max_lon = max_lon,
          min_lat = min_lat,
          max_lat = max_lat,
          vn = vn,
          varname = varname,
          unit = unit,
          lat = lat,
          lon = lon,
          copyrightText = copyrightText
        )
      )
    }
  }
 
  observeEvent(input$action_visualize_variable_modal, {
    # Update the variable
    variable_visualize_modal(input$variable_visualize_modal)

    # This will re-trigger the visualization process
    action_visualize_post_modal(action_visualize_post_modal() + 1)

    # This will remove the modal.
    removeModal()
  })
  
  switchButtonCompare <<- FALSE
  # Compare data dropdown
  observeEvent(input$operatorInput_dropdown, {
    req(operatorInput_value() != "")
    if(switchButtonCompare){
      if(input$operatorInput_dropdown %in% operators[["Compare Data"]]) {
        shinyjs::hide("visualizePage")
        checkboxCompareData_dropdown(input$operatorInput_dropdown)
        if(input$operatorInput_dropdown == "cmsaf.diff.absolute" || input$operatorInput_dropdown == "cmsaf.diff.relative") {
          nc_path_visualize_2("")   # reset path of second file
          nc_path_visualize(list_compare_data[[input$operatorInput_dropdown]])
          nc_object_visualize(NULL)
        }
        else {
          operatorInput_file_2 <- paste0(input$operatorInput_dropdown, "2")
          nc_path_visualize_2(list_compare_data[[operatorInput_file_2]])
          nc_path_visualize(list_compare_data[[input$operatorInput_dropdown]])
          nc_object_visualize(NULL)
        }
        actionVisualize(actionVisualize() + 1)
        shinyjs::show("spinner_visualize_compare_data", anim = TRUE, animType = "fade")
      } 
    } else {
      switchButtonCompare <<- TRUE
    }
  })
  
  # This will set up the intial input values on visualize page.
  observeEvent({
    actionVisualize()
    action_visualize_post_modal()
  }, {
    req(nc_path_visualize())
    shinyjs::hide("panel_visualizeGo")
    shinyjs::show("spinner_visualize", anim = TRUE, animType = "fade")
    shiny::showTab(inputId = "mainVisualizeTabset", target = "Statistics")
    shiny::showTab(inputId = "mainVisualizeTabset", target = "File Summary")
    shiny::hideTab(inputId = "mainVisualizeTabset", target = "Parameters") # hide main parameters of monitor climate
    
    # compare data
    if(operatorInput_value() %in% operatorOptionsDict[["compare_data"]]){
      shinyjs::show("dropdown_compare_data")
      
      tmp_vec <- checkboxCompareData()
      
      tmp_vec <- tmp_vec[tmp_vec != "cmsaf.stats"]
      
      if((endsWith(infile2_analyze_value(), ".csv")) || endsWith(infile2_analyze_value(), ".RData")) {
        tmp_vec <- tmp_vec[tmp_vec != "cmsaf.hovmoller"]
        plots_station <- c()
        plots_station[["Compare Data"]] <- c(
          "Difference plot (absolute)" = "cmsaf.diff.absolute",
          "Difference plot (relative)" = "cmsaf.diff.relative",
          "Scatterplot" = "cmsaf.scatter",
          "Bar chart" = "cmsaf.hist",
          "Side-by-Side plot" = "cmsaf.side.by.side",
          "Comparison of time series" = "cmsaf.time.series"
        )
        match_plot <- match(tmp_vec, plots_station[["Compare Data"]])
        new_operators <- plots_station[["Compare Data"]]
      } else {
        match_plot <- match(tmp_vec, operators[["Compare Data"]])
        new_operators <- operators[["Compare Data"]]
      }
      
      output$dropdown_compare_data <- renderUI({
        selectInput("operatorInput_dropdown",
                    label = "Select a plot type",
                    choices = new_operators[match_plot],
                    selected = checkboxCompareData_dropdown(),
                    selectize = FALSE)
      })
      
      if(nc_path_visualize_2() != ""){
        if((endsWith(infile2_analyze_value(), ".nc"))) {
          id_2 <- ncdf4::nc_open(nc_path_visualize_2())
          vn_2 <- names(id_2$var)
          ncdf4::nc_close(id_2)
        }
      }
      
      if("cmsaf.stats" %in% checkboxCompareData()){
        path_cmsaf_stats <- list_compare_data[["cmsaf.stats"]]
        
        if(file.exists(path_cmsaf_stats)){
          stats_compare_data <- read.csv(path_cmsaf_stats)
          stats_compare_data_df <- as.data.frame(stats_compare_data)
          output$metrics <- renderPrint({
            print(stats_compare_data_df)
          })
        }
      }
    } else
        shinyjs::hide("dropdown_compare_data")

    if (!is.null(nc_object_visualize())) id <- nc_object_visualize()
    else id <- ncdf4::nc_open(nc_path_visualize())
    vn <- names(id$var)
    dn <- names(id$dim)
    if (is.null(nc_object_visualize())) ncdf4::nc_close(id)

    if (!("time" %in% dn)) {
      showModal(modalDialog(
        h4("Sorry, the file you chose does not contain a time dimension."),
        title = "Error!",
        size = "l"))

      resetToPreparePanel()
    } else {

    vn <- subset(vn, !(vn %in% c("lat", "lon", "latitude", "longitude", "time_bnds", "nb2", "time", "crs")))

    # If more than one we allow user to choose a variable. Catch this input here.
    if (!is.null(variable_visualize_modal())) {
      if (is.element(variable_visualize_modal(), vn)) {
        vn <- variable_visualize_modal()

        variable_visualize_modal(NULL)
      } else {
        showModal(modalDialog(
          h4("The chosen input variable doesn't exist in this file. Try another file or input argument."),
          br(),
          title = "Oops.",
          size = "l"
        ))
      }
    }

    if (length(vn) > 1) {
      showModal(modalDialog(
        h4("Seems like you are trying to visualize a file with multiple variables. Please select a variable in order to continue."),
        br(),
        fluidRow(column(7, selectInput(inputId = "variable_visualize_modal",
                                       label = "Please choose a variable.",
                                       choices = vn)),
                 column(5, actionButton("action_visualize_variable_modal",
                                        "Visualize using this variable.",
                                        width = "100%"))),
        title = "We need your help.",
        size = "l",
        footer = NULL
      ))

      # Leave
      req(FALSE)
    } else if (length(vn) < 1) {
      showModal(modalDialog(
        h4("The chosen file doesn't have a variable."),
        title = "Error!",
        size = "m"
      ))

      # Leave
      req(FALSE)
    } else if (vn == "sinusoidal") {
      # TODO: Change this as soon as sinusodial is done.
      # Stop if data are in sinusoidal projection
      showModal(modalDialog(
        h4("Sorry, the CM SAF R Toolbox can not handle data in sinusoidal projection.
             Please use the 'change projection' option during the order process.
             Your NetCDF data have to be on a regular lon-lat grid."),
        title = "Error!",
        size = "l"
      ))

      # Leave
      req(FALSE)
    } else {
      # Trying. If error go back to Visualize page.
      # Maybe visualizeVariables isn't loaded correctly second time?
      if(nc_path_visualize_2() != "") {
        res <- try(visualizeVariables(get_visualize_options(nc_path_visualize(), vn, nc_path_visualize_2(), vn_2, nc1 = nc_object_visualize())))
      } else {
        res <- try(visualizeVariables(get_visualize_options(nc_path_visualize(), vn, nc1 = nc_object_visualize())))
      }

      if (class(res) == "try-error") {
        showModal(modalDialog(
          h3("An error occured while preparing the visualization. Please try another file."),
          br(),
          h5(paste0(res)),
          title = "Error!",
          size = "l"))

        # Go to visualize page.
        resetToVisualizePanel()
      } else {

        shinyjs::hide("setupPage")
        shinyjs::hide("spinner_visualize")
        shinyjs::hide("spinner_visualize_compare_data")
        shinyjs::show("visualizePage", anim = TRUE, animType = "fade")

        # No error. Let's plot!
        # Rendering all gui elements dependent on file.
        # 2D Plot:
        if (visualizeVariables()$plot_dim == 2) {

          shiny::showTab(inputId = "mainVisualizeTabset", target = "Statistics")
          shinyjs::hide("sidebar_1d_plot")
          shinyjs::hide("myImage_1d")
          shinyjs::hide("spinner_visualize")
          shinyjs::hide("filedownload")
          shinyjs::hide("dropdown_station_number")

          shinyjs::show("myImage_2d")
          shinyjs::show("sidebar_2d_plot")
          
          if(cmsaf_stats_enable() == 0){   # checkbox "Show statistics" is not enabled
            shiny::hideTab(inputId = "mainVisualizeTabset", target = "Metrics")
          } else {
            shiny::showTab(inputId = "mainVisualizeTabset", target = "Metrics")
          }
          
          value_text2 <- " "
          if(checkboxCompareData_dropdown() == "cmsaf.side.by.side"){
            shiny::hideTab(inputId = "mainVisualizeTabset", target = "Statistics")
            shinyjs::hide("num_rmax")
            shinyjs::hide("num_rmin")
            if((endsWith(infile2_analyze_value(), ".nc"))){
              shinyjs::show("title_text2")
              shinyjs::show("subtitle_text2")
              output$title_text2 <- renderUI({
                textInput("text1_2",
                          label = "Title",
                          value = visualizeVariables()$varname2)
              })
              
              pattern <- "[^\\/]+(\\.nc)$" # regular exp. to extract filenames
              # regex1 <- regmatches( analyze_file1_plot(), regexpr(pattern, analyze_file1_plot()))
              # Replace with cmsafops::get_basename() which also accounts for URLs
              regex1 <- cmsafops::get_basename(analyze_file1_plot())
              value_text2 <- regex1
              regex2 <- regmatches(analyze_file2_plot(), regexpr(pattern, analyze_file2_plot()))
              output$subtitle_text2 <- renderUI({
                textInput("text2_2",
                          label = "Subtitle",
                          value = regex2)
              })
            } else {
              shinyjs::hide("title_text2")
              shinyjs::hide("subtitle_text2")
            }
            shinyjs::hide("proj")
          } else {
            shinyjs::hide("title_text2")
            shinyjs::hide("subtitle_text2")
            shinyjs::show("num_rmax")
            shinyjs::show("num_rmin")
            if(checkboxCompareData_dropdown() == "cmsaf.diff.absolute" || checkboxCompareData_dropdown() == "cmsaf.diff.relative"){
              shinyjs::hide("proj")
            } else {
              shinyjs::show("proj")
            }
          }
          
          # initialize timestep_c
          timestep_c(visualizeVariables()$date.time[1])
          
          if (!is.null(visualizeVariables()$time_bounds)){
            output$timestep_visualize <- renderUI({
              selectInput("timestep",
                          label = "Select Time Step",
                          choices = visualizeVariables()$time_bounds,
                          selected = visualizeVariables()$time_bounds[1],
                          selectize = FALSE)
            })
          } else {
            output$timestep_visualize <- renderUI({
              selectInput("timestep",
                          label = "Select Time Step",
                          choices = visualizeVariables()$date.time,
                          selected = visualizeVariables()$date.time[1],
                          selectize = FALSE)
            })
          }
          
          observeEvent(input$timestep, {
            if (!is.null(visualizeVariables()$time_bounds)){
              timestep_c(visualizeVariables()$date.time[which(visualizeVariables()$time_bounds == input$timestep)])
            } else {
              timestep_c(visualizeVariables()$date.time[which(visualizeVariables()$date.time == input$timestep)])
            }
          })
          
          # output$lon_visualize <- renderUI({
          #   tmp <- c(max(round(as.numeric(visualizeVariables()$min_lon)), -180), min(round(as.numeric(visualizeVariables()$max_lon)), 180))
          #   lon_bounds(tmp)
          #   sliderInput("slider1",
          #               label = "Longitude",
          #               min = max(round(as.numeric(visualizeVariables()$min_lon)) - 20, -180),
          #               max = min(round(as.numeric(visualizeVariables()$max_lon)) + 20, 180),
          #               value = c(tmp[1], tmp[2]))
          # })
          
          # Use shinyWidgets instead of lon / lat slider
          #
          output$lon_visualize <- renderUI({
            tmp <- c(max(round(as.numeric(visualizeVariables()$min_lon), digits = 2), -180), 
                     min(round(as.numeric(visualizeVariables()$max_lon), digits = 2), 180))
            lon_bounds(tmp)
            shinyWidgets::numericRangeInput("slider1",
                        label = "Longitude",
                        min = -180,
                        max = 180,
                        value = c(tmp[1], tmp[2]))
          })
         
          output$lat_visualize <- renderUI({
            tmp <- c(max(round(as.numeric(visualizeVariables()$min_lat), digits = 2), -90), 
                     min(round(as.numeric(visualizeVariables()$max_lat), digits = 2), 90))
            lat_bounds(tmp)
            shinyWidgets::numericRangeInput("slider2",
                        label = "Latitude",
                        min = -90,
                        max = 90,
                        value = c(tmp[1], tmp[2]))
          })
          
          # output$lat_visualize <- renderUI({
          #   tmp <- c(max(round(as.numeric(visualizeVariables()$min_lat)), -90), min(round(as.numeric(visualizeVariables()$max_lat)), 90))
          #   lat_bounds(tmp)
          # 
          #   sliderInput("slider2",
          #               label = "Latitude",
          #               min = max(round(as.numeric(visualizeVariables()$min_lat)) - 20, -90),
          #               max = min(round(as.numeric(visualizeVariables()$max_lat)) + 20, 90),
          #               value = c(tmp[1], tmp[2]))
          # })
          
          output$ihsf_visualize <- renderUI({
            tmp <- 0.1
            ihsf(tmp)
            sliderInput("decimal",
                        label = "Image Ratio",
                        min = -0.9, max = 0.9,
                        value = 0.1, ticks = FALSE)
          })
          
          output$title_text <- renderUI({
            textInput("text1",
                      label = "Title",
                      value = visualizeVariables()$varname)
          })
          
          output$subtitle_text <- renderUI({
            textInput("text2",
                      label = "Subtitle",
                      value = value_text2)   # because side.by.side plot has a default value
          })
          
          if(plot_type_2d %in% c("timcor", "timcovar")){
            if(plot_type_2d == "timcor"){
              caption_scale <- "Correlation over time"
            }
            if(plot_type_2d == "timcovar"){
              caption_scale <- "Covariance over time"
            }
          } else {
            caption_scale <- paste0(visualizeVariables()$varname, " [", visualizeVariables()$unit, "]")
          }
          
          output$scale_caption <- renderUI({
            textInput("text3",
                      label = "Scale Caption",
                      value = caption_scale)
          })
        } else if(nc_path_visualize_2() != "") {
          if(cmsaf_stats_enable() == 0){   # checkbox "Show statistics" is not enabled
            shiny::hideTab(inputId = "mainVisualizeTabset", target = "Metrics")
          } else {
            shiny::showTab(inputId = "mainVisualizeTabset", target = "Metrics")
          }
          
          # Hide Statistics panel
          shiny::hideTab(inputId = "mainVisualizeTabset", target = "Statistics")
          
          if(checkboxCompareData_dropdown() == "cmsaf.time.series") {
            shinyjs::hide("sidebar_2d_plot")
            shinyjs::hide("myImage_2d")
            
            shinyjs::show("myImage_1d")
            shinyjs::show("sidebar_1d_plot")
            shinyjs::hide("analyze_timeseries")
            shinyjs::hide("trend")
            shinyjs::show("filedownload")
            shinyjs::show("dateformat")
            
            shinyjs::hide("date_dropdown_visualize")
            
            output$title_text_1d <- renderUI({
              textInput("text1_1d",
                        label = "Title",
                        value = visualizeVariables()$varname)
            })
            
            output$subtitle_text_1d <- renderUI({
              textInput("text2_1d",
                        label = "Subtitle",
                        value = " ")
            })
			
			output$x_axis_text_1d <- renderUI({
                textInput("x_axis_label_1d",
                          label = "X-Label",
                          value = "time")
              })
              
            output$y_axis_text_1d <- renderUI({
                textInput("y_axis_label_1d",
                          label = "Y-Label",
                          value = visualizeVariables()$varname)
            })
	            
            if((endsWith(infile2_analyze_value(), ".csv")) || (endsWith(infile2_analyze_value(), ".RData"))){
              if("time" %in% colnames(station_data_compare())){
                station_time_first <- station_data_compare()$time[1]
                b <- lengths(regmatches( station_data_compare()$time, gregexpr(station_time_first,  station_data_compare()$time)))
                station_count <- length(b[b==1])
              } else if ("date" %in% colnames(station_data_compare())){
                station_count <- length(unique(station_data_compare()$date))
              } else if ("zeit" %in% colnames(station_data_compare())){
                station_count <- length(unique(station_data_compare()$zeit))
              } else if ("t" %in% colnames(station_data_compare())){
                station_count <- length(unique(station_data_compare()$t))
              } else if ("get_time.file_data.time_info.units..file_data.dimension_data.t." %in% colnames(station_data_compare())){
                station_count <- length(unique(station_data_compare()$get_time.file_data.time_info.units..file_data.dimension_data.t.))
              }
              shinyjs::show("dropdown_station_number")
              #station_count_seq <- seq(station_count)
              
              labs <- NULL
              for (i in seq_along(station_data_compare()$lon)) {
                dummy <- paste0("[", round(station_data_compare()$lon[i], digits = 1), ";", round(station_data_compare()$lat[i], digits = 1), "]")
                labs <- append(labs, dummy)
              }
              station_seq <- unique(labs)
              
              output$dropdown_station_number <- renderUI({
                selectInput("operatorInput_dropdown_station_number",
                            label = "Select a station",
                            choices = station_seq,
                            selected = station_seq[1],
                            selectize = FALSE)
              })
              
            } else {
              shinyjs::hide("dropdown_station_number")
            }
            
            pattern <- "[^\\/]+(\\.nc)$" # regular exp. to extract filenames
            # regex1 <- regmatches( analyze_file1_plot(), regexpr(pattern, analyze_file1_plot()))
            # Replace with cmsafops::get_basename() which also accounts for URLs
            regex1 <- cmsafops::get_basename(analyze_file1_plot())
            
            if((endsWith(infile2_analyze_value(), ".csv"))){
              pattern <- "[^\\/]+(\\.csv)$" # regular exp. to extract filenames
            }
            if((endsWith(infile2_analyze_value(), ".RData"))){
              pattern <- "[^\\/]+(\\.RData)$" # regular exp. to extract filenames
            }
            regex2 <- regmatches(analyze_file2_plot(), regexpr(pattern, analyze_file2_plot()))
            output$x_axis_text_1d <- renderUI({
              textInput("x_axis_label_1d",
                        label = "Legend label 1",
                        value = regex1)
            })
            
            output$y_axis_text_1d <- renderUI({
              textInput("y_axis_label_1d",
                        label = "Legend label 2",
                        value = regex2)
            })
            
            shinyjs::show("x_axis_text_1d")
            shinyjs::show("y_axis_text_1d")
            
            shinyjs::hide("x_visualize")
            shinyjs::hide("y_visualize")
            shinyjs::show("title_text_1d")
            shinyjs::show("subtitle_text_1d")
            shinyjs::hide("integer")
            shinyjs::hide("ticknumber")
            shinyjs::hide("checkGroup_type")
          } else if(checkboxCompareData_dropdown() == "cmsaf.hovmoller"){
            shinyjs::hide("sidebar_2d_plot")
            shinyjs::hide("myImage_2d")
            
            shinyjs::show("myImage_1d")
            shinyjs::show("sidebar_1d_plot")
            shinyjs::hide("analyze_timeseries")
            shinyjs::hide("trend")
            shinyjs::show("filedownload")
            shinyjs::hide("dateformat")
            shinyjs::hide("date_dropdown_visualize")
            shinyjs::hide("dropdown_station_number")
            
            pattern <- "[^\\/]+(\\.nc)$" # regular exp. to extract filenames
            # regex1 <- regmatches( analyze_file1_plot(), regexpr(pattern, analyze_file1_plot()))
            # Replace with cmsafops::get_basename() which also accounts for URLs
            regex1 <- cmsafops::get_basename(analyze_file1_plot())
            if((endsWith(infile2_analyze_value(), ".csv"))){
              pattern <- "[^\\/]+(\\.csv)$" # regular exp. to extract filenames
            }
            if((endsWith(infile2_analyze_value(), ".RData"))){
              pattern <- "[^\\/]+(\\.RData)$" # regular exp. to extract filenames
            }
            regex2 <- regmatches(analyze_file2_plot(), regexpr(pattern, analyze_file2_plot()))
            output$x_axis_text_1d <- renderUI({
              textInput("x_axis_label_1d",
                        label = "Title 1",
                        value = paste0(visualizeVariables()$xlabel, " (", regex1, ")"))
            })
            
            output$y_axis_text_1d <- renderUI({
              textInput("y_axis_label_1d",
                        label = "Title 2",
                        value = paste0(visualizeVariables()$ylabel, " (", regex2, ")"))
            })
            
            shinyjs::hide("x_axis_text_1d")
            shinyjs::hide("y_axis_text_1d")
            
            shinyjs::hide("x_visualize")
            shinyjs::hide("y_visualize")
            shinyjs::hide("title_text_1d")
            shinyjs::hide("subtitle_text_1d")
            shinyjs::hide("integer")
            shinyjs::hide("ticknumber")
            shinyjs::hide("checkGroup_type")
          }
          else {
            shinyjs::hide("sidebar_2d_plot")
            shinyjs::hide("myImage_2d")
            
            shinyjs::show("myImage_1d")
            shinyjs::show("sidebar_1d_plot")
            shinyjs::hide("analyze_timeseries")
            shinyjs::hide("trend")
            shinyjs::hide("dateformat")
            shinyjs::show("filedownload")
            shinyjs::hide("dropdown_station_number")
            
            output$date_dropdown_visualize <- renderUI({
              selectInput("timestep_1d_visualize",
                          label = "Select Time Step",
                          choices = visualizeVariables()$date.time,
                          selected = visualizeVariables()$date.time[1],
                          selectize = FALSE)
            })
            
            shinyjs::show("date_dropdown_visualize")
            
            output$title_text_1d <- renderUI({
              textInput("text1_1d",
                        label = "Title",
                        value = visualizeVariables()$varname)
            })
            
            output$subtitle_text_1d <- renderUI({
              textInput("text2_1d",
                        label = "Subtitle",
                        value = " ")
            })
			
			output$x_axis_text_1d <- renderUI({
                textInput("x_axis_label_1d",
                          label = "X-Label",
                          value = "time")
              })
              
            output$y_axis_text_1d <- renderUI({
                textInput("y_axis_label_1d",
                          label = "Y-Label",
                          value = visualizeVariables()$varname)
            })
			              
              shinyjs::show("x_axis_text_1d")
              shinyjs::show("y_axis_text_1d")
            
            if(checkboxCompareData_dropdown() == "cmsaf.scatter") {
              pattern <- "[^\\/]+(\\.nc)$" # regular exp. to extract filenames
              # regex1 <- regmatches( analyze_file1_plot(), regexpr(pattern, analyze_file1_plot()))
              # Replace with cmsafops::get_basename() which also accounts for URLs
              regex1 <- cmsafops::get_basename(analyze_file1_plot())
              if((endsWith(infile2_analyze_value(), ".csv"))){
                pattern <- "[^\\/]+(\\.csv)$" # regular exp. to extract filenames
              }
              if((endsWith(infile2_analyze_value(), ".RData"))){
                pattern <- "[^\\/]+(\\.RData)$" # regular exp. to extract filenames
              }
              regex2 <- regmatches(analyze_file2_plot(), regexpr(pattern, analyze_file2_plot()))
              output$x_axis_text_1d <- renderUI({
                textInput("x_axis_label_1d",
                          label = "Label x axis",
                          value = paste0(visualizeVariables()$xlabel, " (", regex1, ")"))
              })
              
              output$y_axis_text_1d <- renderUI({
                textInput("y_axis_label_1d",
                          label = "Label y axis",
                          value = paste0(visualizeVariables()$ylabel, " (", regex2, ")"))
              })
              
              shinyjs::show("x_axis_text_1d")
              shinyjs::show("y_axis_text_1d")
            } else if(checkboxCompareData_dropdown() == "cmsaf.hist"){
                shinyjs::hide("dropdown_station_number")
              
              pattern <- "[^\\/]+(\\.nc)$" # regular exp. to extract filenames
              # regex1 <- regmatches( analyze_file1_plot(), regexpr(pattern, analyze_file1_plot()))
              # Replace with cmsafops::get_basename() which also accounts for URLs
              regex1 <- cmsafops::get_basename(analyze_file1_plot())
              
              if((endsWith(infile2_analyze_value(), ".csv"))){
                pattern <- "[^\\/]+(\\.csv)$" # regular exp. to extract filenames
              }
              if((endsWith(infile2_analyze_value(), ".RData"))){
                pattern <- "[^\\/]+(\\.RData)$" # regular exp. to extract filenames
              }
              regex2 <- regmatches(analyze_file2_plot(), regexpr(pattern, analyze_file2_plot()))
              output$x_axis_text_1d <- renderUI({
                textInput("x_axis_label_1d",
                          label = "Legend label 1",
                          value = regex1)
              })
              
              output$y_axis_text_1d <- renderUI({
                textInput("y_axis_label_1d",
                          label = "Legend label 2",
                          value = regex2)
              })
              
              shinyjs::show("x_axis_text_1d")
              shinyjs::show("y_axis_text_1d")
            }
            else {
              shinyjs::hide("x_axis_text_1d")
              shinyjs::hide("y_axis_text_1d")
            }
            
            
            shinyjs::hide("x_visualize")
            shinyjs::hide("y_visualize")
            shinyjs::show("title_text_1d")
            shinyjs::show("subtitle_text_1d")
            shinyjs::hide("integer")
            shinyjs::hide("ticknumber")
            shinyjs::hide("checkGroup_type")
          }
        } else{
          shinyjs::show("separator")
          shinyjs::show("downloadFile")
          if(length(visualizeVariables()$lon) == 1 && length(visualizeVariables()$lat) == 1){
            # 1D-Plot (x-axis: time and y-axis: variable)
            # Hide Statistics panel
            shiny::hideTab(inputId = "mainVisualizeTabset", target = "Statistics")
            shiny::hideTab(inputId = "mainVisualizeTabset", target = "Metrics")
            
            shinyjs::hide("sidebar_2d_plot")
            shinyjs::hide("myImage_2d")
            
            shinyjs::show("myImage_1d")
            shinyjs::show("sidebar_1d_plot")
            shinyjs::show("dateformat")
            shinyjs::show("filedownload")
            
            if(plot_type_1d %in% c("fldcor", "fldcovar")){
              shinyjs::hide("analyze_timeseries")
              shinyjs::hide("trend")
            } else {
              shinyjs::show("analyze_timeseries")
              shinyjs::show("trend")
            }
            
            output$x_visualize <- renderUI({
              sliderInput("sliderx",
                          label = "X-Range",
                          min = 1,
                          max = visualizeVariables()$x_range,
                          value = c(1, visualizeVariables()$x_range))
            })
            
            output$title_text_1d <- renderUI({
              textInput("text1_1d",
                        label = "Title",
                        value = visualizeVariables()$varname)
            })
            
            output$subtitle_text_1d <- renderUI({
              textInput("text2_1d",
                        label = "Subtitle",
                        value = " ")
            })
			
			      output$x_axis_text_1d <- renderUI({
                textInput("x_axis_label_1d",
                          label = "X-Label",
                          value = "time")
              })
              
            output$y_axis_text_1d <- renderUI({
                textInput("y_axis_label_1d",
                          label = "Y-Label",
                          value = visualizeVariables()$varname)
            })
			              
              #shinyjs::show("x_axis_text_1d")
              #shinyjs::show("y_axis_text_1d")
          } else if((length(visualizeVariables()$lon) == 1 && length(visualizeVariables()$lat) != 1) ||
                    (length(visualizeVariables()$lon) != 1 && length(visualizeVariables()$lat) == 1)){
            # 1D-Plot (x-axis: lat or lon and y-axis: variable)
            
            # Hide Statistics panel
            shiny::hideTab(inputId = "mainVisualizeTabset", target = "Statistics")
            shiny::hideTab(inputId = "mainVisualizeTabset", target = "Metrics")
            
            shinyjs::hide("sidebar_2d_plot")
            shinyjs::hide("myImage_2d")
            
            shinyjs::show("myImage_1d")
            shinyjs::show("sidebar_1d_plot")
            shinyjs::hide("analyze_timeseries")
            shinyjs::hide("trend")
            shinyjs::hide("dateformat")
            shinyjs::show("filedownload")
            
            output$date_dropdown_visualize <- renderUI({
              selectInput("timestep_1d_visualize",
                          label = "Select Time Step",
                          choices = visualizeVariables()$date.time,
                          selected = visualizeVariables()$date.time[1],
                          selectize = FALSE)
            })
            shinyjs::show("date_dropdown_visualize")
            
            output$x_visualize <- renderUI({
              sliderInput("sliderx",
                          label = "X-Range",
                          min = 1,
                          max = visualizeVariables()$x_range,
                          value = c(1, visualizeVariables()$x_range))
            })
            
            output$title_text_1d <- renderUI({
              textInput("text1_1d",
                        label = "Title",
                        value = visualizeVariables()$varname)
            })
            
            output$subtitle_text_1d <- renderUI({
              textInput("text2_1d",
                        label = "Subtitle",
                        value = " ")
            })
          }
        }

        # Start timer independently of 1D/2D plot.
        shinyjs::delay(2000, readyToPlot(TRUE))
      }
    }}

  }, ignoreInit = TRUE, ignoreNULL = FALSE)

  # Logic after png or mp4 passed to visualizer
  # This will set up the intial input values on visualize page.
  observeEvent({
    actionVisualizeMonitorClimate()
  }, {
    req(image_path_visualize())
    shinyjs::hide("panel_visualizeGo")
    shinyjs::show("spinner_visualize", anim = TRUE, animType = "fade")

    shinyjs::hide("setupPage")
    shinyjs::hide("spinner_visualize")
    shinyjs::show("visualizePage", anim = TRUE, animType = "fade")

    shiny::hideTab(inputId = "mainVisualizeTabset", target = "Statistics")
    shiny::showTab(inputId = "mainVisualizeTabset", target = "Parameters") # show main parameters of monitor climate
    shiny::hideTab(inputId = "mainVisualizeTabset", target = "File Summary")
    shinyjs::hide("sidebar_1d_plot")
    shinyjs::hide("myImage_1d")
    shinyjs::hide("sidebar_2d_plot")
    shinyjs::hide("myImage_2d")
    shinyjs::hide("spinner_visualize")
    shinyjs::hide("filedownload")
    shinyjs::hide("date_dropdown_visualize")
    shinyjs::hide("dropdown_compare_data")
    
    # if warming stripes plot or time series plot
    climate_analysis_ops <- c("warming_stripes_plot", "time_series_plot", "trend_plot")
    if(operatorInput_value() %in% climate_analysis_ops)
    {
      #TODO add Interactivity 
    }
    
    shinyjs::show("myImage_monitorClimate")
    
    # show parameters monitor climate
    infile_path <- file.path(tempdir(),"mc_parameters.csv")
    
    if(file.exists(infile_path)){
      mc_parameters <- read.csv(infile_path)
      df_parameters <- as.data.frame(mc_parameters)
      
      # number.of.rows <- nrow(df_parameters)
      # number.of.columns <- ncol(df_parameters)
      
      output$mc_parameters <- renderPrint({
        # print(df_parameters[1:number.of.rows, 2:number.of.columns])
        print(df_parameters)
      })
      
      unlink(infile_path)
    }
    
    # show ranking monitor climate
    infile_ranking_path <- file.path(tempdir(),"mc_ranking.csv")
    if(file.exists(infile_ranking_path)){
      mc_ranking <- read.csv(infile_ranking_path)
      df_ranking <- as.data.frame(mc_ranking)
      # number.of.rows <- nrow(df_ranking)
      # number.of.columns <- ncol(df_ranking)
      
      output$mc_ranking <- renderPrint({
        cat("Ranking\n")
        #print(head(df_ranking[1:number.of.rows, 2:number.of.columns]))
        print(df_ranking)
      })
      
      # remove ranking file
      unlink(infile_ranking_path)
    }

    if (endsWith(image_path_visualize(), "png")) {
      rnd <- list(
        src = image_path_visualize(),
        contentType = "image/png"
      )

      shinyjs::show("monitorClimate_PNG")
      shinyjs::hide("monitorClimate_MP4")

      output$monitorClimate_PNG <- renderImage(rnd, deleteFile = FALSE)
    } else if (endsWith(image_path_visualize(), "mp4")) {
      rnd <- list(
        src = image_path_visualize(),
        contentType = "video/mp4"
      )

      shinyjs::show("monitorClimate_MP4")
      shinyjs::hide("monitorClimate_PNG")

      output$monitorClimate_MP4 <- renderUI({
        # Temporarily copy video to www directory
        # Reason: Giving absolute path is not allowed due to security issues
        if (!dir.exists(videoDir())) {
          dir.create(videoDir())
        }

        tmpVideo <- file.path(videoDir(), "animation.mp4")

        file.copy(
          from = image_path_visualize(),
          to = tmpVideo,
          overwrite = TRUE
        )

        # Render the video
        tags$video(
          id = "video",
          type = "video/mp4",
          src = "video/animation.mp4",
          controls = "controls")
      })
    }

    # Start timer independently of 1D/2D plot.
    shinyjs::delay(2000, readyToPlot(TRUE))

  }, ignoreInit = TRUE, ignoreNULL = FALSE)

  # Observe changes to lon, lat slider and update image plot width/height
  observeEvent({
    lon_bounds()
    lat_bounds()
    ihsf()
  }, {

    req(visualizeVariables()$plot_dim == 2)

    imDim <- cmsafvis::recalculateImageDimensions(
      visualizeVariables = visualizeVariables(),
      lon_bounds = lon_bounds(),
      lat_bounds = lat_bounds(),
      image_def = image_def,
      ihsf = ihsf()
      )

    imagewidth(imDim$imagewidth)
    imageheight(imDim$imageheight)
    #
    #
    # lon <- visualizeVariables()$lon[visualizeVariables()$lon <= lon_bounds()[2]]
    # lon <- lon[lon_bounds()[1] <= lon]
    #
    # lat <- visualizeVariables()$lat[visualizeVariables()$lat <= lat_bounds()[2]]
    # lat <- lat[lat_bounds()[1] <= lat]
    #
    # # Update this value if you want to change min width/height of plot.
    # minSize <- 200
    # tmpWidth  <- max(minSize, image_def)
    # tmpHeight <- max(minSize, image_def)
    #
    # # Update width and height according to visualizeVariables lat and lon vectors
    # if (length(lon) >= length(lat)) {
    #   # Shrink height
    #   tmpHeight <- round(tmpWidth * length(lat) / length(lon))
    #   if (tmpHeight < minSize) {
    #     tmpWidth <- minSize / tmpHeight * tmpWidth
    #     tmpHeight <- minSize
    #   }
    #
    #   # Why are we doing this? (And why not in the else block?)
    #   imageheight(tmpHeight + (round((ihsf * tmpHeight))))
    #   imagewidth(tmpWidth)
    # } else {
    #   # No need to check against minSize since we will multiply with a value > 1.
    #   tmpWidth <- round(tmpHeight * length(lat) / length(lon))
    #
    #   imagewidth(tmpWidth)
    #   imageheight(tmpHeight)
    # }

    lat_lon_trigger(lat_lon_trigger() + 1)
  })

  # Render scale ranges when data range changes.
  output$num_rmin <- renderUI({
    numericInput("num_rmin",
                 label = "Scale Range Min",
                 value = round(visualizeDataMin(), digits = 1),
                 step = 0.1)
  })

  # Render scale ranges when data range changes.
  output$num_rmax <- renderUI({
    if (round(visualizeDataMin(), digits = 1) == round(visualizeDataMax(), digits = 1)) {
      value <- round(visualizeDataMax(), digits = 1) + 0.1
    } else {
      value <- round(visualizeDataMax(), digits = 1)
    }

    numericInput("num_rmax",
                 label = "Scale Range Max",
                 value = value,
                 step = 0.1)
  })

  # Y-Range of 1D plot.
  output$y_visualize <- renderUI({
    req(visualizeDataMax())
    req(visualizeDataMin())
    
    # max values between -1 and 1
    if(visualizeDataMax() <= 1 && visualizeDataMax() >= -1) {
      value_max <- round(visualizeDataMax(), 4)
    } else {
      value_max <- trunc(visualizeDataMax())
    }
      
    # min values between -1 and 1
    if(visualizeDataMin() <= 1 && visualizeDataMin() >= -1) {
      value_min <- round(visualizeDataMin(), 4)
    } else {
      value_min <- trunc(visualizeDataMin())
    }
    
    diff <- visualizeDataMax() - visualizeDataMin()

    sliderInput("slidery",
                label = "Y-Range",
                min = round(visualizeDataMin() - (0.25 * diff), 1),
                max = round(visualizeDataMax() + (0.25 * diff), 1),
                value = c(value_min, value_max))
  })
  
  output$x_visualize <- renderUI({
    req(visualizeVariables()$x_range)
    sliderInput("sliderx",
                label = "X-Range",
                min = 1,
                max = visualizeVariables()$x_range,
                value = c(1, visualizeVariables()$x_range))
  })
  

  # Observe changes to visualize data. If all data are available update min and max values globally.
  # Else we'll need to keep track of them
  observe({
    req(class(visualizeVariables()$data) == "try-error")

    min_data <- min(visualizeDataTimestep(), na.rm = TRUE)
    max_data <- max(visualizeDataTimestep(), na.rm = TRUE)

    if (round(min_data, digits = 1) == round(max_data, digits = 1)) {
      min_data <- min_data - 0.05
      max_data <- max_data + 0.05
    }

    visualizeDataMin(min_data)
    visualizeDataMax(max_data)
  })

  # Observing changes to shape file path
  observeEvent(shapeFile_path_action(), {
    region_data(countriesHigh)
    req(shapeFile_path())
    req(file.exists(shapeFile_path()))

    # data of all regions
    region_data(suppressWarnings(raster::shapefile(shapeFile_path())))
  })

  # Set divisions
  observeEvent(region_data(), {
    all_divisions <- names(region_data())
    if (!is.element("COUNTRY", all_divisions)) {
      all_divisions <- c("COUNTRY", all_divisions)
    }
    output$division_options <- renderUI({
      selectInput("division",
                  "Division",
                  choices = c("Select division", all_divisions))
    })
  })

  # Set regions
  observeEvent(input$division, {
    if (input$division != "Select division") {
      if (input$division != "COUNTRY") {
        all_regions <- levels(region_data()[[input$division]])
      } else {
        # data of all countries
        countries_choosable <- codes[, "iso3c"]
        names(countries_choosable) <- codes[, "country.name.en"]

        all_regions <- countries_choosable
      }

      output$region_options <- renderUI({
        selectInput("region",
                    "Region",
                    choices = c("Select region", all_regions),
                    selected = "Select region")
      })
    } else {
      output$region_options <- renderUI({
        selectInput("region",
                    "Region",
                    choices = c("Select region"))
      })
    }
  })

  # Toggle instat file upload
  observeEvent(input$plot_rinstat, {
    # Is set in global.R
    if (isRunningLocally) {
      if (input$plot_rinstat) {
        shinyjs::show("instat_file_local")
      } else {
        shinyjs::hide("instat_file_local")
      }
    } else {
      if (input$plot_rinstat) {
        shinyjs::show("instat_file_remote")
      } else {
        shinyjs::hide("instat_file_remote")
      }
    }
  }, ignoreInit = TRUE)

  # Go back to set up page.
  observeEvent(input$backToSetup, {
    operatorInput_value("")
    nc_path_visualize_2("")
    resetToVisualizePanel()
  }, ignoreInit = TRUE)

  # Go back to set up page (from monitor climate visualization).
  observeEvent(input$backToSetup2, {
    # Unlink viedo dir
    if (dir.exists(videoDir())) {
      unlink(
        x = videoDir(),
        recursive = TRUE,
        force = TRUE
      )
    }

    resetToVisualizePanel()
  }, ignoreInit = TRUE)

  # Reacting to instat file data.
  instat.data <- reactive({
    req(instat_path())
    req(endsWith(instat_path(), ".RData") || endsWith(instat_path(), ".csv"))
    if(endsWith(instat_path(), ".RData")){
      a <- get(load(instat_path()))
    } else if(endsWith(instat_path(), ".csv")){
      a <- data.table::fread(instat_path(), sep="auto")
    }
    a <- as.data.frame(a)
    a
  })

  # get data for diff plots in compare data
  co.data.compare.diff <- reactive({ 
    req(analyze_file2_plot())
    req(endsWith(analyze_file2_plot(), ".RData") || endsWith(analyze_file2_plot(), ".csv"))
    req(timestep_c())
    
    a <- station_data_compare()
    data_nc <- visualizeVariables()$data
    date.time <- visualizeVariables()$date.time

    lon <- visualizeVariables()$lon
    lat <- visualizeVariables()$lat
    min_lon <- min(lon, na.rm = TRUE)
    max_lon <- max(lon, na.rm = TRUE)
    min_lat <- min(lat, na.rm = T)
    max_lat <- max(lat, na.rm = T)
    
    # lon
    slider1 <- c(max(round(as.numeric(min_lon)), -180), min(round(as.numeric(max_lon)), 180))
    
    # lat
    slider2 <- c(max(round(as.numeric(min_lat)), -90), min(round(as.numeric(max_lat)), 90))

    lo_dummy <- c("lon", "longitude", "laenge", "x", "lon_rep")
    la_dummy <- c("lat", "latitude", "breite", "y", "lat_rep")
    ti_dummy <- c("time", "date", "zeit", "t", "get_time.file_data.time_info.units..file_data.dimension_data.t.")
    da_dummy <- c("data", "daten", "z", "element", "result")
    
    dn <- attr(a, "element_name")
    if (!is.null(dn)) {
      da_dummy <- append(da_dummy, dn)
    } else {
      dn <- attr(a, "data_name")
      if (!is.null(dn)) {
        da_dummy <- append(da_dummy, dn)
      }
    }
    
    instat_names <- names(a)
    
    lo_n <- 0
    la_n <- 0
    ti_n <- 0
    da_n <- 0
    
    for (i in seq_along(instat_names)) {
      if (toupper(instat_names[i]) %in% toupper(lo_dummy)) (lo_n <- i)
      if (toupper(instat_names[i]) %in% toupper(la_dummy)) (la_n <- i)
      if (toupper(instat_names[i]) %in% toupper(ti_dummy)) (ti_n <- i)
      if (toupper(instat_names[i]) %in% toupper(da_dummy)) (da_n <- i)
    }
    
    if (lo_n > 0 & la_n > 0 & ti_n > 0 & da_n > 0) {
      # check monthly or daily
      # station
      time_station <- a[, ti_n]
      if (length(time_station) > 500) (time_station <- time_station[1:500])
      mon_station  <- format(as.Date(time_station), "%m")
      year_station <- format(as.Date(time_station), "%Y")
      day_station  <- format(as.Date(time_station), "%d")
      
      dummy <- which(mon_station == mon_station[1] & year_station == year_station[1])
      mmdm <- "d"
      
      if (length(unique(day_station[dummy])) == 1) {
        mmdm <- "m"
      }
      
      # satellite
      time_sat <- date.time
      if (length(time_sat) > 40) (time_sat <- time_sat[1:40])
      mon_sat  <- format(as.Date(time_sat), "%m")
      year_sat <- format(as.Date(time_sat), "%Y")
      day_sat  <- format(as.Date(time_sat), "%d")
      dummy <- which(mon_sat == mon_sat[1] & year_sat == year_sat[1])
      mmdm_sat <- "d"
      if (length(unique(day_sat[dummy])) == 1) {
        mmdm_sat <- "m"
      }
      
      # extract data for chosen time step
      if (mmdm == "m" & mmdm_sat == "m") {
        match_time   <- which(format(as.Date(station_data_compare()[, ti_n]), "%Y-%m") == format(as.Date(timestep_c()), "%Y-%m"), arr.ind = TRUE)
      } else {
        match_time   <- which(station_data_compare()[, ti_n] == timestep_c(), arr.ind = TRUE)
      }
      
      lon_station  <- a[, lo_n][match_time]
      lat_station  <- a[, la_n][match_time]
      data_station <- a[, da_n][match_time]
      
      # delete NAs
      dummy <- !is.na(data_station)
      data_station <- data_station[dummy]
      data_station <- data_station
      lon_station  <- lon_station[dummy]
      lat_station  <- lat_station[dummy]
      # Extract corresponding data points
      
      data_sat <- c(seq_along(data_station))
      
      result_x <- c()
      result_y <- c()
      
      result_x <- rep(lon, length(lat))
      
      for(j in seq_along(lat)){
        result_y <- append(result_y, rep(lat[j], length(lon)))
      }
      
      A <- cbind(x=result_x, y=result_y)
      
      for (istation in seq_along(data_station)) {
        B <- cbind(x=c(lon_station[istation]), y=c(lat_station[istation]))
        tree <- SearchTrees::createTree(A)
        inds <- SearchTrees::knnLookup(tree, newdat=B, k=1)
        
        lon_coor <- coor_sat[inds,1]
        lat_coor <- coor_sat[inds,2]
        
        data_sat[istation] <- data_nc[which(lon == lon_coor),which(lat == lat_coor), which(date.time == timestep_c())]
      }
      
      data_station_diff_absolute <- data_sat - data_station
      
      # relative diff plot data: ((datensatz1 - datensatz2)/datensatz2)*100
      data_station_diff_relative <- ((data_sat - data_station)/data_station)*100
      
      if(checkboxCompareData_dropdown() == "cmsaf.diff.absolute"){
        # max
        station_max <- max(data_station_diff_absolute, na.rm = TRUE)
        visualizeDataMax(station_max)
        # min
        station_min <- min(data_station_diff_absolute, na.rm = TRUE)
        visualizeDataMin(station_min)
      }
      
      if(checkboxCompareData_dropdown() == "cmsaf.diff.relative") {
        # max
        station_max <- max(data_station_diff_relative, na.rm = TRUE)
        visualizeDataMax(station_max)
        # min
        station_min <- min(data_station_diff_relative, na.rm = TRUE)
        visualizeDataMin(station_min)
      }
     
      cd <- data.frame(data_station_diff_absolute, data_station_diff_relative, data_sat, lon_station, lat_station)
      cd
    }
  })
  
  # Combine the CM SAF R Toolbox and R-Instat
  co.data <- reactive({
    # Only recompute if we want to add r_instat stuff to plot.
    req(instat_path())
    req(endsWith(instat_path(), ".RData") || endsWith(instat_path(), ".csv"))
    
    data_nc <- visualizeVariables()$data
    date.time <- visualizeVariables()$date.time
    lon <- visualizeVariables()$lon
    lat <- visualizeVariables()$lat
    
    # check row.names of data frame
    lo_dummy <- c("lon", "longitude", "laenge", "x", "lon_rep")
    la_dummy <- c("lat", "latitude", "breite", "y", "lat_rep")
    ti_dummy <- c("time", "date", "zeit", "t", "get_time.file_data.time_info.units..file_data.dimension_data.t.")
    da_dummy <- c("data", "daten", "z", "element", "result")

    dn <- attr(instat.data(), "element_name")
    if (!is.null(dn)) {
      da_dummy <- append(da_dummy, dn)
    } else {
      dn <- attr(instat.data(), "data_name")
      if (!is.null(dn)) {
        da_dummy <- append(da_dummy, dn)
      }
    }

    instat_names <- names(instat.data())

    lo_n <- 0
    la_n <- 0
    ti_n <- 0
    da_n <- 0

    for (i in seq_along(instat_names)) {
      if (toupper(instat_names[i]) %in% toupper(lo_dummy)) (lo_n <- i)
      if (toupper(instat_names[i]) %in% toupper(la_dummy)) (la_n <- i)
      if (toupper(instat_names[i]) %in% toupper(ti_dummy)) (ti_n <- i)
      if (toupper(instat_names[i]) %in% toupper(da_dummy)) (da_n <- i)
    }

    if (lo_n > 0 & la_n > 0 & ti_n > 0 & da_n > 0) {

      # check monthly or daily
      # station
      time_station <- instat.data()[, ti_n]
      if (length(time_station) > 500) (time_station <- time_station[1:500])
      mon_station  <- format(as.Date(time_station), "%m")
      year_station <- format(as.Date(time_station), "%Y")
      day_station  <- format(as.Date(time_station), "%d")
      dummy <- which(mon_station == mon_station[1] & year_station == year_station[1])
      mmdm <- "d"
      if (length(unique(day_station[dummy])) == 1) {
        mmdm <- "m"
      }

      # satellite
      time_sat <- visualizeVariables()$date.time
      if (length(time_sat) > 40) (time_sat <- time_sat[1:40])
      mon_sat  <- format(as.Date(time_sat), "%m")
      year_sat <- format(as.Date(time_sat), "%Y")
      day_sat  <- format(as.Date(time_sat), "%d")
      dummy <- which(mon_sat == mon_sat[1] & year_sat == year_sat[1])
      mmdm_sat <- "d"
      if (length(unique(day_sat[dummy])) == 1) {
        mmdm_sat <- "m"
      }

      # extract data for chosen time step
      if (mmdm == "m" & mmdm_sat == "m") {
        match_time   <- which(format(as.Date(instat.data()[, ti_n]), "%Y-%m") == format(as.Date(timestep_c()), "%Y-%m"), arr.ind = TRUE)
      } else {
        match_time   <- which(instat.data()[, ti_n] == timestep_c(), arr.ind = TRUE)
      }

      lon_station  <- instat.data()[, lo_n][match_time]
      lat_station  <- instat.data()[, la_n][match_time]
      data_station <- instat.data()[, da_n][match_time]

      # delete NAs
      dummy <- !is.na(data_station)
      data_station <- data_station[dummy]
      data_station <- data_station
      lon_station  <- lon_station[dummy]
      lat_station  <- lat_station[dummy]
      # Extract corresponding data points
      data_sat <- c(seq_along(data_station))
      
      result_x <- c()
      result_y <- c()
      
      result_x <- rep(lon, length(lat))
      
      for(j in seq_along(lat)){
        result_y <- append(result_y, rep(lat[j], length(lon)))
      }
      
      A <- cbind(x=result_x, y=result_y)
      
      for (istation in seq_along(data_station)) {
        B <- cbind(x=c(lon_station[istation]), y=c(lat_station[istation]))
        tree <- SearchTrees::createTree(A)
        inds <- SearchTrees::knnLookup(tree, newdat=B, k=1)
        
        lon_coor <- coor_sat[inds,1]
        lat_coor <- coor_sat[inds,2]
        
        data_sat[istation] <- data_nc[which(lon == lon_coor),which(lat == lat_coor), which(date.time == timestep_c())]
      }
      
      cd <- data.frame(data_station, data_sat, lon_station, lat_station)
      print(cd)
      cd
    } # end if lo_n,la_n,ti_n,da_n
  })

  # A function to validate all numeric inputs.
  # This should only be called knowing all required inputs exist!
  validNumericInputs <- reactive({
    validity <- list()
    # Set to false first
    validity$valid <- FALSE

    # Occurs either way
    if (!is.numeric(input$num_brk) || input$num_brk < 2 || input$num_brk > 64) {
      validity$argument <- "Number of colors"
      validity$value <- input$num_brk
      validity$required <- "in [2, 64]"
      return(validity)
    }

    if (input$slider1[1] == input$slider1[2]) {
      validity$argument <- "Longitude slider"
      validity$value <- "min = max"
      validity$required <- "min < max"
      return(validity)
    }

    if (input$slider2[1] == input$slider2[2]) {
      validity$argument <- "Latitude slider"
      validity$value <- "min = max"
      validity$required <- "min < max"
      return(validity)
    }

    if (input$proj == "rect") {
      # inputs only in rectangular

      if (!is.numeric(input$num_tick) || input$num_tick < 2 || input$num_tick > 64) {
        validity$argument <- "Number of ticks"
        validity$value <- input$num_tick
        validity$required <- "in [2, 64]"
        return(validity)
      }

      if (!is.numeric(input$num_rmin) || !is.numeric(input$num_rmax) || input$num_rmin >= input$num_rmax) {
        if (is.na(input$num_rmin) && is.na(input$num_rmax)) {
          validity$argument <- "Scale range"
          validity$value <- "Seems like you are trying to visualize data that consits of only 'NA' values. Please choose another file."
          validity$required <- "min < max"

        } else {
          validity$argument <- "Scale range"
          validity$value <- paste("min =", input$num_rmin, "max =", input$num_rmax)
          validity$required <- "min < max"

        }
        return(validity)
      }

      if (input$location) {
        if (!is.numeric(input$lon_loc) || abs(input$lon_loc) > 180) {
          validity$argument <- "Location"
          validity$value <- input$lon_loc
          validity$required <- "in [-180, 180]"
          return(validity)
        }

        if (!is.numeric(input$lat_loc) || abs(input$lat_loc) > 90) {
          validity$argument <- "Location"
          validity$value <- input$lat_loc
          validity$required <- "in [-180, 180]"
          return(validity)
        }
      }
    } else if (input$proj == "ortho") {
      # inputs only in orthoprojection
      if (!is.numeric(input$yort) || abs(input$yort) > 180) {
        validity$argument <- "Center Lon"
        validity$value <- input$yort
        validity$required <- "in [-180, 180]"
        return(validity)
      }

      if (!is.numeric(input$xort) || abs(input$xort) >= 90) {
        validity$argument <- "Center Lat"
        validity$value <- input$xort
        validity$required <- "in (-90, 90)"
        return(validity)
      }

      if (!is.numeric(input$rort) || abs(input$rort) >= 90) {
        validity$argument <- "Rotation"
        validity$value <- input$rort
        validity$required <- "in (-90, 90)"
        return(validity)
      }
    }

    # if not returned false yet, return true.
    validity$valid <- TRUE
    return(validity)
  })

  observeEvent(input$add_loc, {
    req(input$add_loc)
    req(abs(input$lon_loc) <= 180)
    req(abs(input$lat_loc) <= 90)
    if (!is.element(input$lon_loc, lon_loc_vec()) || !is.element(input$lat_loc, lat_loc_vec())) {
      lon_loc_vec(append(lon_loc_vec(), input$lon_loc))
      lat_loc_vec(append(lat_loc_vec(), input$lat_loc))
      name_loc_vec(append(name_loc_vec(), input$name_loc))
    }
  }, ignoreInit = TRUE)

  # Get new data if timestep is updated
  observeEvent(timestep_c(), {
    req(is.element(timestep_c(), visualizeVariables()$date.time))
    # Update the data according to the time step using the visualize nc file's id and previously calculated variable.
    if (!is.null(nc_object_visualize())) id <- nc_object_visualize()
    else id <- ncdf4::nc_open(nc_path_visualize())
    tmp <- getVariableData(which(visualizeVariables()$date.time == timestep_c()), id, visualizeVariables()$vn)
    if (is.null(nc_object_visualize())) ncdf4::nc_close(id)

    if (reversedDimensions$transpose) {
      tmp <- aperm(tmp, c(2, 1))
    }

    if (reversedDimensions$lonReverse) {
      tmp <- tmp[rev(seq_len(length(visualizeVariables()$lon))), ]
    }

    if (reversedDimensions$latReverse) {
      tmp <- tmp[, rev(seq_len(length(visualizeVariables()$lat)))]
    }
    visualizeDataTimestep(tmp)
  })

  ## Colorpalette Stuff ##
  palettes <- GetPaletteConfig(gui = TRUE)

  # ----------------------------------------------------------------
  # Getting currently selected color scheme
  # ----------------------------------------------------------------
  palettes <- GetPaletteConfig(gui = TRUE)
  names(palettes) <- tolower(names(palettes))
  names(palettes)[names(palettes) == "typ"] <- "type"

  # add more color schemes
  new_row <- data.frame("more", NA, NA, NA, NA, NA, NA, NA, NA, NA, 1)
  names(new_row) <- names(palettes)
  palettes <- rbind(palettes, new_row)
  rownames(palettes)[79] <- "tim.colors"
  
  palettes <- rbind(palettes, new_row)
  rownames(palettes)[80] <- "larry"
  
  palettes <- rbind(palettes, new_row)
  rownames(palettes)[81] <- "albedo"
  
  palettes <- rbind(palettes, new_row)
  rownames(palettes)[82] <- "albedo2"

  palettes <- rbind(palettes, new_row)
  rownames(palettes)[83] <- "sunny"

  x <- list()
  for (i in seq_len(nrow(palettes))) {
    x[[sprintf("%s", rownames(palettes)[i])]] <- rownames(palettes)[i]
  }
  updateSelectInput(session, "PAL", choices = x, selected = "sunny")

  # Debouncing
  db_xort  <- shiny::debounce(reactive({input$xort}),  750)
  db_yort  <- shiny::debounce(reactive({input$yort}),  750)
  db_rort  <- shiny::debounce(reactive({input$rort}),  750)
  db_num_tick <- shiny::debounce(reactive({input$num_tick}), 750)
  db_num_rmin <- shiny::debounce(reactive({input$num_rmin}), 750)
  db_num_rmax <- shiny::debounce(reactive({input$num_rmax}), 750)
  db_num_brk  <- shiny::debounce(reactive({input$num_brk}),  750)
  db_lat_lon_trigger <- shiny::debounce(reactive({lat_lon_trigger()}), 750)
  db_int        <- shiny::debounce(reactive({input$int}),    750)
  db_region     <- shiny::debounce(reactive({input$region}), 750)
  db_checkGroup <- shiny::debounce(reactive({input$checkGroup}), 750)
  db_visualizeDataTimestep <- shiny::debounce(reactive({visualizeDataTimestep()}), 750)
  db_visualizeDataMax <- shiny::debounce(reactive({visualizeDataMax()}), 750)
  db_proj <- shiny::debounce(reactive({input$proj}), 750)
  db_text2 <- shiny::debounce(reactive({input$text2}), 750)
  db_text3 <- shiny::debounce(reactive({input$text3}), 750)
  db_text1 <- shiny::debounce(reactive({input$text1}), 1000)
  
  db_text1_2 <- shiny::debounce(reactive({input$text1_2}), 750)
  db_text2_2 <- shiny::debounce(reactive({input$text2_2}), 750)

  getPlot_1d <- reactive({
    req(readyToPlot())
    if(nc_path_visualize_2() != ""){
      c(db_text1_1d())
      c(db_text2_1d())
      c(db_x_axis_label_1d())
      c(db_y_axis_label_1d())
      c(db_operatorInput_dropdown_station_number())
    } else {
      # Triggers and requirements
      req(is.character(db_text1_1d()))
      req(db_sliderx())
      req(db_slidery())
      req(db_integer())
      req(db_checkGroup_type())
      c(db_trend())
      req(db_ticknumber())
      c(db_text2_1d())
    }

    # Catch data is error exception
    if (class(visualizeVariables()$data) == "try-error") {
      showModal(modalDialog(
        h4("We can't handle your file at the moment. Please try another file."),
        br(),
        title = "Sorry!",
        size = "l"
      ))

      # Silently leave.
      req(FALSE)
    }
    shinyjs::hide("spinner_plot1")
    if(nc_path_visualize_2() != "") {
      if(checkboxCompareData_dropdown() == "cmsaf.scatter") {
        req(db_timestep_1d_visualize())
        isolate({
          res_plot <- try(cmsafvis::render_plot_scatter(fileExtension = ".png",
                                                        visualizeVariables = visualizeVariables(),
                                                        ticknumber = input$ticknumber,
                                                        dateformat = input$dateformat,
                                                        imagewidth = imagewidth(),
                                                        imageheight = imageheight(),
                                                        text1_1d = input$text1_1d,   # title
                                                        text2_1d = input$text2_1d,   # subtitle
                                                        textsize = textsize,
                                                        linesize = linesize,
                                                        x_axis_label_1d = input$x_axis_label_1d,
                                                        y_axis_label_1d = input$y_axis_label_1d,
                                                        timestep_1d_visualize = input$timestep_1d_visualize))
        })
      } else if(checkboxCompareData_dropdown() == "cmsaf.hist") {
        req(db_timestep_1d_visualize())
        # if(!(endsWith(infile2_analyze_value(), ".nc"))){
        #   req(!is.null(input$operatorInput_dropdown_station_number))
        # }
        isolate({
          res_plot <- try(cmsafvis::render_plot_hist_compare(fileExtension = ".png",
                                                        visualizeVariables = visualizeVariables(),
                                                        imagewidth = imagewidth(),
                                                        imageheight = imageheight(),
                                                        text1_1d = input$text1_1d,   # title
                                                        text2_1d = input$text2_1d,   # subtitle
                                                        textsize = textsize,
                                                        legend_label1 = input$x_axis_label_1d,
                                                        legend_label2 = input$y_axis_label_1d,
                                                        timestep_1d_visualize = input$timestep_1d_visualize
                                                        ))
        })
      } else if(checkboxCompareData_dropdown() == "cmsaf.time.series") {
        req((visualizeVariables()$plot_type == "cmsaf.time.series"))
        req(db_dateformat())
        if(!(endsWith(infile2_analyze_value(), ".nc"))){
          req(!is.null(input$operatorInput_dropdown_station_number))
        }
        isolate({
          res_plot <- try(cmsafvis::render_plot_time_series_compare(fileExtension = ".png",
                                                             visualizeVariables = visualizeVariables(),
                                                             ticknumber = input$ticknumber,
                                                             dateformat = input$dateformat,
                                                             sliderx = input$sliderx,
                                                             slidery = input$slidery,
                                                             checkGroup_type = input$checkGroup_type,   # line type
                                                             imagewidth = imagewidth(),
                                                             imageheight = imageheight(),
                                                             text1_1d = input$text1_1d,   # title
                                                             text2_1d = input$text2_1d,   # subtitle
                                                             textsize = textsize,
                                                             linesize = linesize,
                                                             col = input$integer,   # color
                                                             legend_label1 = input$x_axis_label_1d,
                                                             legend_label2 = input$y_axis_label_1d,
                                                             station_number = input$operatorInput_dropdown_station_number))
        })
      } else if(checkboxCompareData_dropdown() == "cmsaf.hovmoller") {
        req((visualizeVariables()$plot_type == "cmsaf.hovmoller"))
        isolate({
          res_plot <- try(cmsafvis::render_plot_hovmoller(fileExtension = ".png",
                                                                    visualizeVariables = visualizeVariables(),
                                                                    imagewidth = imagewidth(),
                                                                    imageheight = imageheight(),
                                                                    textsize = textsize,
                                                                    linesize = linesize,
                                                                    title_data1 = input$x_axis_label_1d,
                                                                    title_data2 = input$y_axis_label_1d))
        })
      } 
      else {
        req(FALSE)
      }
    }
    else if(length(visualizeVariables()$lon) == 1 && length(visualizeVariables()$lat) == 1){   # plot for time and variable
      c(db_analyze_timeseries())
      req(db_dateformat())
      isolate({
        res_plot <- try(cmsafvis::render_plot_1d(fileExtension = ".png",
                                                 visualizeVariables = visualizeVariables(),
                                                 ticknumber = input$ticknumber,
                                                 dateformat = input$dateformat,
                                                 analyze_timeseries = input$analyze_timeseries,
                                                 addTrend = input$trend,
                                                 sliderx = input$sliderx,
                                                 slidery = input$slidery,
                                                 checkGroup_type = input$checkGroup_type,   # line type
                                                 imagewidth = imagewidth(),
                                                 imageheight = imageheight(),
                                                 text1_1d = input$text1_1d,   # title
                                                 text2_1d = input$text2_1d,   # subtitle
                                                 text3_1d = input$x_axis_label_1d, # X-Label
                                                 text4_1d = input$y_axis_label_1d, # Y-Label
                                                 textsize = textsize,
                                                 linesize = linesize,
                                                 col = input$integer))   # color
      })
    }
    else if((length(visualizeVariables()$lon) == 1 && length(visualizeVariables()$lat) != 1) ||
       (length(visualizeVariables()$lon) != 1 && length(visualizeVariables()$lat) == 1)){   # plot for lat/lon and variable
      req(db_timestep_1d_visualize())
      isolate({
        res_plot <- try(cmsafvis::render_plot_1d_advanced(fileExtension = ".png",
                                                 visualizeVariables = visualizeVariables(),
                                                 ticknumber = input$ticknumber,
                                                 addTrend = input$trend,
                                                 sliderx = input$sliderx,
                                                 slidery = input$slidery,
                                                 checkGroup_type = input$checkGroup_type,   # line type
                                                 imagewidth = imagewidth(),
                                                 imageheight = imageheight(),
                                                 text1_1d = input$text1_1d,   # title
                                                 text2_1d = input$text2_1d,   # subtitle
                                                 textsize = textsize,
                                                 linesize = linesize,
                                                 col = input$integer,   # color
                                                 timestep_1d_visualize = input$timestep_1d_visualize))
      })
    } else 
      req(FALSE)
    if (class(res_plot) != "try-error") {
      return(res_plot)
    } else {
      showModal(modalDialog(
        br(),
        h3("Something went wrong while creatin 1D Plot."),
        title = "Error.",
        size = "l"
      ))
      req(NULL)
    }
  })

  # A reactive, throttled function for generating the plot.
  getPlot_2d <- reactive({
    req(readyToPlot())

    # Required triggers
    req(nrow(db_visualizeDataTimestep()) > 0)  # when data at timestep changes
    req(nchar(db_text1()) > 0)                        # Need a title
    req(db_proj())                         # projection
    req(db_visualizeDataMax())             # max data (not sure why want to trigger this?)
    
    # Isolated requirements
    isolate(req(lon_bounds()))    # Require this to prevent error message
    isolate(req(lat_bounds()))    # However, do not trigger on change
    # isolate( req(imagewidth()) )    # image width (triggering is done by lat_lon_trigger)
    # isolate( req(imageheight()) )   # image height (triggering is done by lat_lon_trigger)
    
    # Non-required triggers (some are required but will be caught in validation of numeric inputs.)
    c(name_loc_vec(),    # new location
      db_checkGroup(),  # colorbar
      db_text2(),        # sub-title
      db_text3(),        # scale caption
      db_int(),         # country borders
      db_region(),      # for region plot
      db_xort(),         # center lat
      db_yort(),         # center lon
      db_rort(),         # rotation
      instat_path(),     # instat file path change
      db_num_tick(),     # number ticks
      db_num_rmin(),         # min val
      db_num_rmax(),         # max val
      db_num_brk(),          # number breaks
      db_lat_lon_trigger(),  # changes to lat, lon, bounds
      input$reverse,         # invert colors
      input$bordercolor2,     # border color for outlines
      input$PAL,             # colorspace pallete
      db_text1_2(),
      db_text2_2()
    )
    
    # Everything below this point is non-reactive.
    isolate({
      # First check validity in region plot
      if (input$plot_region) {
        if (is.null(region_data()) && (is.null(shapeFile_path()) || !file.exists(shapeFile_path()))) {
          # show message
          shinyjs::hide("spinner_plot1")
          shinyjs::enable("backToSetup")

          showModal(modalDialog(
            br(),
            h3("Please select a shape file ",
               tags$strong("(.shp)"),
               " or select the COUNTRY division to continue."),
            title = "Wrong file format.",
            size = "l"
          ))

          req(FALSE)
        }
        req(input$region != "Select region")
      }

      # Show spinner
      shinyjs::show("spinner_plot1", anim = TRUE, animType = "fade")
      shinyjs::disable("backToSetup")

      # Toggle state of plot_rinstat.
      plot_rinstat <- FALSE
      if (input$plot_rinstat) {
        if (!is.null(instat_path()) && file.exists(instat_path())) {
          plot_rinstat <- TRUE
        } else {
          # show message
          shinyjs::hide("spinner_plot1")
          shinyjs::enable("backToSetup")

          showModal(modalDialog(
            br(),
            h3("Please select a .RData instat file to continue."),
            title = "Wrong file format.",
            size = "l"
          ))

          # Leave silently.
          req(FALSE)
        }
      }

      # Validate numeric inputs
      validity <- validNumericInputs()
      if (validity$valid != TRUE) {
        # show message
        shinyjs::hide("spinner_plot1")
        shinyjs::enable("backToSetup")

        showModal(modalDialog(
          br(),
          h5(paste0("Argument: ", validity$argument)),
          h5(paste0("Value: ", validity$value)),
          h5(paste0("Expected: ", validity$required)),
          title = "Wrong input argument.",
          size = "l"
        ))

        # Leave silently.
        req(FALSE)
      }
      shinyjs::hide("spinner_plot1", anim = TRUE, animType = "fade")
      if (input$plot_region) {
        res <- try(ls <- cmsafvis::render_region_plot(infile = isolate(nc_path_visualize()),
                                                      visualizeVariables = visualizeVariables(),
                                                      visualizeDataMax = visualizeDataMax(),
                                                      lon_bounds = lon_bounds(),
                                                      lat_bounds = lat_bounds(),
                                                      lon_loc_vec = lon_loc_vec(),
                                                      lat_loc_vec = lat_loc_vec(),
                                                      name_loc_vec = name_loc_vec(),
                                                      division = input$division,
                                                      selectedRegion = input$region,
                                                      region_data = region_data(),
                                                      timestep = timestep_c(),
                                                      num_tick = input$num_tick,
                                                      num_rmin = input$num_rmin,
                                                      num_rmax = input$num_rmax,
                                                      location = input$location,
                                                      text1 = input$text1,
                                                      text2 = input$text2,
                                                      text3 = input$text3,
                                                      PAL = input$PAL,
                                                      palettes = palettes,
                                                      num_brk = input$num_brk,
                                                      reverse = input$reverse,
                                                      textsize = textsize,
                                                      bordercolor = input$bordercolor2,
                                                      plot_grid = plot_grid,
                                                      grid_col = grid_col,
                                                      image_def = image_def,
                                                      ihsf = ihsf(),
                                                      nc = nc_object_visualize()))
      } else {
        if(checkboxCompareData_dropdown() == "cmsaf.side.by.side"){
          req((visualizeVariables()$plot_type == "cmsaf.side.by.side"))
          isolate({
            res <- try(ls <- cmsafvis::render_plot_side_by_side(plot_rinstat = input$plot_rinstat,
                                                               visualizeVariables = visualizeVariables(),
                                                               visualizeDataTimestep = visualizeDataTimestep(),
                                                               nc_path_visualize = nc_path_visualize(),
                                                               visualizeDataMax = visualizeDataMax(),
                                                               timestep_2d = timestep_c(),
                                                               lon_bounds = lon_bounds(),
                                                               lat_bounds = lat_bounds(),
                                                               lon_loc_vec = lon_loc_vec(),
                                                               lat_loc_vec = lat_loc_vec(),
                                                               name_loc_vec = name_loc_vec(),
                                                               timestep = timestep_c(),
                                                               num_tick = input$num_tick,
                                                               num_rmin = input$num_rmin,
                                                               num_rmax = input$num_rmax,
                                                               num_brk = input$num_brk,
                                                               co.data = co.data(),
                                                               proj = input$proj,
                                                               imagewidth = imagewidth(),
                                                               imageheight = imageheight(),
                                                               xort = input$xort,
                                                               yort = input$yort,
                                                               rort = input$rort,
                                                               slider1 = input$slider1,
                                                               slider2 = input$slider2,
                                                               location = input$location,
                                                               text1 = input$text1,
                                                               text2 = input$text2,
                                                               text3 = input$text3,
                                                               int = input$int,
                                                               textsize = textsize,
                                                               bordercolor = input$bordercolor2,
                                                               linesize = linesize,
                                                               na.color = na.color,
                                                               PAL = input$PAL,
                                                               palettes = palettes,
                                                               reverse = input$reverse,
                                                               plot_grid = plot_grid,
                                                               grid_col = grid_col,
                                                               text1_2 = input$text1_2,
                                                               text2_2 = input$text2_2))
          })
        } else {
          res <- try(ls <- cmsafvis::render_plot(plot_rinstat = input$plot_rinstat,
                                                 visualizeVariables = visualizeVariables(),
                                                 visualizeDataTimestep = visualizeDataTimestep(),
                                                 nc_path_visualize = nc_path_visualize(),
                                                 visualizeDataMax = visualizeDataMax(),
                                                 lon_bounds = lon_bounds(),
                                                 lat_bounds = lat_bounds(),
                                                 lon_loc_vec = lon_loc_vec(),
                                                 lat_loc_vec = lat_loc_vec(),
                                                 name_loc_vec = name_loc_vec(),
                                                 timestep = timestep_c(),
                                                 num_tick = input$num_tick,
                                                 num_rmin = input$num_rmin,
                                                 num_rmax = input$num_rmax,
                                                 num_brk = input$num_brk,
                                                 co.data = co.data(),
                                                 co.data.compare.diff = co.data.compare.diff(),
                                                 proj = input$proj,
                                                 imagewidth = imagewidth(),
                                                 imageheight = imageheight(),
                                                 xort = input$xort,
                                                 yort = input$yort,
                                                 rort = input$rort,
                                                 slider1 = input$slider1,
                                                 slider2 = input$slider2,
                                                 location = input$location,
                                                 text1 = input$text1,
                                                 text2 = input$text2,
                                                 text3 = input$text3,
                                                 int = input$int,
                                                 textsize = textsize,
                                                 bordercolor = input$bordercolor2,
                                                 linesize = linesize,
                                                 na.color = na.color,
                                                 PAL = input$PAL,
                                                 palettes = palettes,
                                                 reverse = input$reverse,
                                                 plot_grid = plot_grid,
                                                 grid_col = grid_col))
        }
      }
    })
    if (class(res) == "try-error") {
      showModal(modalDialog(
        h4("An error occured while creating the plot. Please try another file or other input arguments."),
        tags$p(paste0("Message: ", res)),
        title = "Error!",
        size = "m"
      ))
      shinyjs::enable("backToSetup")
      shinyjs::hide("spinner_plot1")

      # Leave silently
      req(FALSE)
    } else {
      # Updating path to png plot
      png_path(ls$src)

      # show plot
      shinyjs::enable("backToSetup")
      shinyjs::hide("spinner_plot1")
      shinyjs::show("myImage", anim = TRUE, animType = "fade")

      # Return the image and don't delete it for now. It is stored in tmp directory anyway so it will be gone after the session.
      # We want to keep it so we can downlaod it later.
      ls
    }
  })

  # Rendering image 2d
  output$myImage_2d <- renderImage({
    getPlot_2d()
  }, deleteFile = FALSE)

  # Debounce 1D plot
  db_sliderx    <- shiny::debounce(reactive({input$sliderx}), 750)
  db_slidery    <- shiny::debounce(reactive({input$slidery}), 750)
  db_integer    <- shiny::debounce(reactive({input$integer}), 750)
  db_timestep_1d_visualize <- shiny::debounce(reactive({input$timestep_1d_visualize}), 750)
  db_trend      <- shiny::debounce(reactive({input$trend}), 750)
  db_checkGroup_type    <- shiny::debounce(reactive({input$checkGroup_type}), 750)
  db_analyze_timeseries <- shiny::debounce(reactive({input$analyze_timeseries}), 750)
  db_ticknumber <- shiny::debounce(reactive({input$ticknumber}), 750)
  db_dateformat <- shiny::debounce(reactive({input$dateformat}), 750)
  db_text2_1d   <- shiny::debounce(reactive({input$text2_1d}), 750)
  db_x_axis_label_1d <- shiny::debounce(reactive({input$x_axis_label_1d}), 750)
  db_y_axis_label_1d <- shiny::debounce(reactive({input$y_axis_label_1d}), 750)
  db_operatorInput_dropdown_station_number <- shiny::debounce(reactive({input$operatorInput_dropdown_station_number}), 750)

  # Again, this debounce is special. Compare with special debounce of plot 2d
  db_text1_1d   <- shiny::debounce(reactive({input$text1_1d}), 1000)

  # Copied from app-4
  output$myImage_1d <- renderImage({
    ls <- getPlot_1d()
    png_path(ls$src)
    ls
  },deleteFile = FALSE)

  # Creating a preview plot.
  output$previewSpatialCoveragePlot_vis <- renderPlot({
    req(input$slider1)
    req(input$slider2)
    maps::map("world", fill = TRUE, col = "gray36", bg = "white", xlim = input$slider1, ylim = input$slider2)
    maps::map("world", fill = TRUE, col = "gray36", bg = "white", xlim = input$slider1, ylim = input$slider2)
    title(main = "Zoom by selecting a region on this plot.")
  })

  # Observing changes in brushing
  observe({
    if (is.null(input$zoom_brush)) {
      lon_bounds(input$slider1)
      lat_bounds(input$slider2)
      ihsf(input$decimal)
    } else {
      brush <- input$zoom_brush
      lon <- c(brush$xmin, brush$xmax)
      lat <- c(brush$ymin, brush$ymax)
      lon_bounds(lon)
      lat_bounds(lat)
    }
  })

  # Download data for 1D-plot.
  output$downloadFile <- downloadHandler(
    filename = function() {
      return(paste0("data_", input$text1_1d, sessionName, ".csv"))
    },
    content = function(file) {
      # TODO: NOT SURE IF THIS WILL WORK IN REMOTE HOST. PLEASE TRY ON SHADOW!!
      removeModal()
      sep <- switch(as.numeric(input$separator), ";", ",", "\t")
      dataframe <- data.frame(visualizeVariables()$date.time, visualizeVariables()$data[,,])
      names(dataframe) <- c("dateTime", "data")
      utils::write.table(dataframe, file, row.names = FALSE, sep = sep)
    },
    contentType = "text/comma-separated-values"
  )

  output$downloadPlot <- downloadHandler(
    #filename:
    filename = function() {
      ext <- switch(as.numeric(input$imageformat), ".png", ".kml", ".tif", ".jpg", ".pdf")
      selected <- input$imageformat
      if (visualizeVariables()$plot_dim == 2) {
        return(paste0("plot_", input$text1, sessionName, ext))
      } else {
        return(paste0("plot_", input$text1_1d, sessionName, ext))
      }
    },
    content = function(file) {
      # TODO: NOT SURE IF THIS WILL WORK IN REMOTE HOST. PLEASE TRY ON SHADOW!!
      withProgress(message = "downloading File", value = 0,
                   {
                     removeModal()
                     for (i in 1:10) {
                       incProgress(1/10)
                       Sys.sleep(0.25)
                     }
                     if (input$imageformat == 1) {
                       file.copy(png_path(), file)
                     } else {
                       fileExtension <- switch(as.numeric(input$imageformat), ".png", ".kml", ".tif", ".jpg", ".pdf")

                       if (input$plot_region) {
                         res_plot <- cmsafvis::render_region_plot(infile = nc_path_visualize(),
                                                                  fileExtension = fileExtension,
                                                                  visualizeVariables = visualizeVariables(),
                                                                  visualizeDataMax = visualizeDataMax(),
                                                                  lon_bounds = lon_bounds(),
                                                                  lat_bounds = lat_bounds(),
                                                                  lon_loc_vec = lon_loc_vec(),
                                                                  lat_loc_vec = lat_loc_vec(),
                                                                  name_loc_vec = name_loc_vec(),
                                                                  division = input$division,
                                                                  selectedRegion = input$region,
                                                                  region_data = region_data(),
                                                                  timestep = timestep_c(),
                                                                  num_tick = input$num_tick,
                                                                  num_rmin = input$num_rmin,
                                                                  num_rmax = input$num_rmax,
                                                                  location = input$location,
                                                                  text1 = input$text1,
                                                                  text2 = input$text2,
                                                                  text3 = input$text3,
                                                                  PAL = input$PAL,
                                                                  palettes = palettes,
                                                                  num_brk = input$num_brk,
                                                                  reverse = input$reverse,
                                                                  textsize = textsize,
                                                                  bordercolor = input$bordercolor2,
                                                                  plot_grid = plot_grid,
                                                                  grid_col = grid_col,
                                                                  image_def = image_def,
                                                                  ihsf = ihsf(),
                                                                  nc = nc_object_visualize())
                         in_plot <- res_plot$src
                       } else {
                         res_plot <- cmsafvis::render_plot(plot_rinstat = input$plot_rinstat,
                                                           fileExtension = fileExtension,
                                                           visualizeVariables = visualizeVariables(),
                                                           visualizeDataTimestep = visualizeDataTimestep(),
                                                           nc_path_visualize = nc_path_visualize(),
                                                           visualizeDataMax = visualizeDataMax(),
                                                           lon_bounds = lon_bounds(),
                                                           lat_bounds = lat_bounds(),
                                                           lon_loc_vec = lon_loc_vec(),
                                                           lat_loc_vec = lat_loc_vec(),
                                                           name_loc_vec = name_loc_vec(),
                                                           timestep = timestep_c(),
                                                           num_tick = input$num_tick,
                                                           num_rmin = input$num_rmin,
                                                           num_rmax = input$num_rmax,
                                                           num_brk = input$num_brk,
                                                           co.data = co.data(),
                                                           proj = input$proj,
                                                           imagewidth = imagewidth(),
                                                           imageheight = imageheight(),
                                                           xort = input$xort,
                                                           yort = input$yort,
                                                           rort = input$rort,
                                                           slider1 = input$slider1,
                                                           slider2 = input$slider2,
                                                           location = input$location,
                                                           text1 = input$text1,
                                                           text2 = input$text2,
                                                           text3 = input$text3,
                                                           int = input$int,
                                                           textsize = textsize,
                                                           bordercolor = input$bordercolor2,
                                                           linesize = linesize,
                                                           na.color = na.color,
                                                           PAL = input$PAL,
                                                           palettes = palettes,
                                                           reverse = input$reverse,
                                                           plot_grid = plot_grid,
                                                           grid_col = grid_col)
                         in_plot <- res_plot$src
                       }
                       file.copy(in_plot,file)
                     }
                   })
    },
    contentType = switch(as.numeric(input$imageformat), "image/png", "image/kml", "image/tif", "image/jpg", "image/pdf")
  )

  # Statsics output
  observe({
    # Requirements
    req(input$lonPoint)
    req(input$latPoint)
    req(timestep_c())
    req(visualizeVariables()$date.time)
    req(visualizeDataMax())
    req(visualizeVariables()$plot_dim == 2)

    # compute some statistics
    xr <- which(visualizeVariables()$lon >= (input$slider1[1]) & visualizeVariables()$lon <= (input$slider1[2]))
    yr <- which(visualizeVariables()$lat >= (input$slider2[1]) & visualizeVariables()$lat <= (input$slider2[2]))
    dastat <- visualizeDataTimestep()[xr, yr]
    # dastat <- visualizeVariables()$data[xr, yr, which(visualizeVariables()$date.time == input$timestep, arr.ind = TRUE)]

    dg <- 2
    if (abs(visualizeDataMax()) >= 10) (dg <- 1)
    if (abs(visualizeDataMax()) >= 100) (dg <- 0)

    da_mean   <- round(mean(dastat, na.rm = TRUE), digits = dg)
    da_median <- round(stats::median(dastat, na.rm = TRUE), digits = dg)
    da_sd     <- round(stats::sd(dastat, na.rm = TRUE), digits = dg)
    da_max    <- round(max(dastat, na.rm = TRUE), digits = dg)
    da_min    <- round(min(dastat, na.rm = TRUE), digits = dg)

    # some numbers
    output$statistics <- renderPrint({
      cat(paste0("Mean:               ", da_mean), "\n")
      cat(paste0("Median:             ", da_median), "\n")
      cat(paste0("Standard deviation: ", da_sd), "\n")
      cat(paste0("Maximum:            ", da_max), "\n")
      cat(paste0("Minimum:            ", da_min), "\n")
      cat(paste0("Unit:               ", visualizeVariables()$unit), "\n")
      cat("\n")
      cat(paste0("To save the histogram figure: right-click + save image as..."), "\n")
    })

    # Missing values can be found in global.R
    # histogram
    output$myHist <- renderPlot({
      cmsafvis::render_hist_plot(dastat = as.numeric(dastat),
                                 shortDescription = input$text1,
                                 xlab = input$text3,
                                 grid_col = grid_col,
                                 bordercolor = bordercolor,
                                 linesize = linesize)
    })
  })

  # Observing changes to instat file
  observeEvent({
    instat_path_action()
    input$plot_rinstat
  }, {
    # Requirements
    req(instat_path())
    if (input$plot_rinstat && file.exists(instat_path())) {
      # grid_col, bordercolor, and linesize can be found in global.R
      output$myComp <- renderPlot({
        cmsafvis::render_instat_plot(co.data = co.data(),
                                     shortDescription = input$text1,
                                     ylab = input$text3,
                                     grid_col = grid_col,
                                     bordercolor = bordercolor,
                                     linesize = linesize)
      })
    }
  })

  # File summaries
  output$summary1 <- renderPrint({
    req(nc_path_visualize())
    cmsafops::ncinfo(nc_path_visualize(), nc = nc_object_visualize())
  })

  output$summary2 <- renderPrint({
    req(nc_path_visualize())
    cmsafops::ncinfo(nc_path_visualize(), "m", nc = nc_object_visualize())
  })

  # About part
  output$about <- renderPrint({
    cat("The CMSAF Visualizer is part of the CM SAF R Toolbox.", "\n")
    cat("This tool helps you to visualize 1D-timeseries and 2D-maps.", "\n")
    cat("\n")
    cat("This version ('Of Course I Still Love You') was tested with the cmsaf", "\n")
    cat("R-package in version 3.5.1.", "\n")
    cat("\n")
    cat("Suggestions for improvements and praise for the developers", "\n")
    cat("can be send to contact.cmsaf@dwd.de.", "\n")
    cat("\n")
    cat("                              - Steffen Kothe - 2024-05-07 -", "\n")
    cat("\n")
    cat("\n")
  })

  # Tipps
  output$tipps <- renderPrint({
    cat("You can easily plot station data, which were exported by R-Instat.", "\n")
    cat("\n")
    cat("If saving an image fails, try right-click plus 'save image as'.", "\n")
    cat("\n")
    cat("The orthographic projection includes some interpolation,", "\n")
    cat("which can have an impact on local pixel values!", "\n")
    cat("\n")
    cat("If you swim with a friend, your chances of getting eaten", "\n")
    cat("by a shark will drop by 50%.", "\n")
    cat("\n")
  })

  output$link <- renderUI({
    url <- a("https://www.cmsaf.eu/R_toolbox", href = "https://www.cmsaf.eu/R_toolbox")
    tagList("URL link:", url)
  })

  #### Destructors ####
  
  # This modal is called if the app is running remotely and there exists output files
  # to warn the user that files will be lost after exiting.
  confirm_exit_modal <- modalDialog(
    p("You have files on the server which will be lost when you exit."),
    downloadButton("downloader_modal", "Download the session files."),
    title = "Are you sure you want to exit?",
    footer = tagList(actionButton("exit_app", "Exit App"),
                     modalButton("Cancel")
    ),
    easyClose = TRUE
  )
  output$downloader_modal <- session_dir_download_handler
  
  # Stop app on exit button.
  observeEvent(input$exit, {
    n_remote_files(length(list.files(userDir, recursive = TRUE)))
    if (!isRunningLocally && n_remote_files() > 0) {
      showModal(confirm_exit_modal)
    }
    else {
      stop_toolbox()
    }
  })
  
  observeEvent(input$exit_app, {
    stop_toolbox()
  })
  
  stop_toolbox <- function() {
    stopApp(returnValue = invisible(99))
  }

  # After app is closed do cleanup. (Only if directory hasn't existed before session.)
  session$onSessionEnded(function() {
    # Variable 'isRunningLocally' can be found in global.R
    # Only removing in remote session. Keeping all files in local versions.
    if (!isRunningLocally) {
      if (dir.exists(userDir)) {
        unlink(userDir, recursive = TRUE)
      }
    } else {
      # If no files contained remove user directory. (local host)
      if (length(list.files(userDir, recursive = TRUE, include.dirs = TRUE)) == 0) {
        unlink(userDir, recursive = TRUE)
      }
    }
  })


  downloadModal1d <- function(failed = FALSE) {
    modalDialog(
      if(infile2_analyze_value() == "") {
        column(6,
               radioButtons("separator",
                            label = "Choose separator",
                            choices = list("Semicolon" = 1,
                                           "Comma" = 2,
                                           "Tab" = 3),
                            selected = 1),
               downloadButton("downloadFile", "Download Data")
        )
      },
    column(6,
           selectInput("imageformat",
                       label = "File format",
                       choices = list("PNG" = 1,
                                      "jpeg" = 4,
                                      "pdf" = 5
                       ),
                       selected = 1),
           downloadButton("downloadPlot", "Download Image")
    ),
    footer = tagList(
      modalButton("Cancel")
    )

    )
  }
  downloadModal2d <- function(failed = FALSE) {
    modalDialog(
      selectInput("imageformat",
                  label = "File format",
                  if (input$proj == "ortho") {
                    choices <- list("PNG" = 1,
                                   "jpeg" = 4,
                                   "pdf" = 5
                    )
                  } else {
                    choices <- list("PNG" = 1,
                                   "KML" = 2,
                                   "GeoTiff" = 3,
                                   "jpeg" = 4,
                                   "pdf" = 5
                    )
                  },
                  selected = 1),
      downloadButton("downloadPlot", "download Image"),
      footer = tagList(
        modalButton("Cancel")
      )

    )
  }

  # Downloader for monitor_climate
  output$download_monitor_climate <- renderUI({
    downloadButton(
      outputId = "download_monitor_climate_output",
      label = cmsafops::get_basename(image_path_visualize()),
      style = "width:100%;")
  })

  output$download_monitor_climate_output <- downloadHandler(
    filename = function() {
      paste0(cmsafops::get_basename(image_path_visualize()))
    },
    content = function(con) {
      file.copy(image_path_visualize(), con)
    }
  )

  # Show modal when button is clicked.
  observeEvent(input$showModal, {
    if (visualizeVariables()$plot_dim == 1) {
      showModal(downloadModal1d())
    } else {
      showModal(downloadModal2d())
    }
  })
}
