LoadConfigurationFile <- function(environment) {
  # This function loads all the data contained in the configuration file 
  # specified as parameter 'configfile' in the function Load() of 
  # s2dverification.
  # Extends the environment given as parameter with the variables and 
  # functions needed for the configuration file mechanism to work.
  # Check ?LoadConfigurationFile for a detailed explanation on how to prepare
  # your own configuration file.

  with(environment, {

  # This function adds a key, value pair into a dictionary and checks there is no duplication
  putInDictionary <- function(dictionary, key, value) {
    if (key %in% names(dictionary)) {
      dictionary[[key]] <- value
      dictionary
    } else {
      dictionary[[length(dictionary) + 1]] <- value
      if (is.null(names(dictionary))) {
        names(dictionary) <- c(key)
      } else {
        names(dictionary)[[length(names(dictionary))]] <- key
      }
      dictionary
    }
  }

  # This function replaces all the occurrences of a variable in a string by their corresponding string stored in the replace_values.
  replaceVariablesInString <- function(string, replace_values) {
    if (length(strsplit(string, "\\$")[[1]]) > 1) {
      parts <- strsplit(string, "\\$")[[1]]
      output <- ""
      i <- 0
      for (part in parts) {
        if (i %% 2 == 0) {
          output <- paste(output, part, sep = "")
        } else {
          if (part %in% names(replace_values)) {
            output <- paste(output, replaceVariablesInString(replace_values[[part]], replace_values), sep = "")
          } else {
            # TODO: ERROR raise
            print(paste('The variable $', part, '$ was not defined in the configuration file.', sep = ''))
          }
        }
        i <- i + 1
      }
      output
    } else {
      string
    }
  }

  # This function obtains the information of a dataset and variable pair,
  # applying all the entries that match in the configuration file.
  getDatasetInfo <- function(table, dataset_name, variable_name) {
    experiment_defaults <- c('$DEFAULT_EXP_MAIN_PATH$', '$DEFAULT_EXP_FILE_PATH$', '$DEFAULT_GRID$', '$DEFAULT_NC_VAR_NAME$')
    observation_defaults <- c('$DEFAULT_OBS_MAIN_PATH$', '$DEFAULT_OBS_FILE_PATH$', '$DEFAULT_NC_VAR_NAME$')
    info <- NULL

    for (level in table) {
      for (entry in level) {
        if (regexpr(entry[1], dataset_name)[1] > 0) {
          if (regexpr(entry[2], variable_name)[1] > 0) {
            if (is.null(info)) {
              info <- entry[-1:-2]
              if (length(info) == 4) {
                info[which(info == '*')] <- experiment_defaults[which(info == '*')]
              } else {
                info[which(info == '*')] <- observation_defaults[which(info == '*')]
              }
            } else {
              info[which(entry[-1:-2] != '*')] <- entry[-1:-2][which(entry[-1:-2] != '*')]
            }
          }
        }
      }
    }
    
    if (is.null(info)) {
      print('There are no entries in the configuration file matching the experiment %s and variable %s\n', dataset_name, variable_name)
    }
    
    info
  }

  # Read the data from the configuration file.
  if (is.null(configfile)) {
    configfile <- system.file("config", "IC3.conf", package = "s2dverification")
  }
  all_lines <- readLines(configfile)
  all_lines <- gsub("\t", "", all_lines)
  all_lines <- gsub(" ", "", all_lines)
  all_lines <- all_lines[-grep("^#", all_lines)]
  all_lines <- all_lines[-grep("^$", all_lines)]
  key_positions <- grep("^!!", all_lines)

  # Check that the format of the configuration file is right.
  if (length(key_positions) != 8) {
    print('The configuration file is corrupted: the key lines do not match the expected pattern.')
  }

  # Start parsing the configuration.
  # Parse the 2-dimensional (atmospheric) and global mean (oceanic) variable entries
  if (key_positions[1] + 1 < key_positions[2]) {
    atm_var_lines <- all_lines[(key_positions[1] + 1):(key_positions[2] - 1)]
  } else {
    atm_var_lines <- c()
  }
  atm_vars <- unlist(strsplit(atm_var_lines, ","))
  if (key_positions[2] + 1 < key_positions[3]) {
    oceanic_var_lines <- all_lines[(key_positions[2] + 1):(key_positions[3] - 1)]
  } else {
    oceanic_var_lines <- c()
  }
  oceanic_vars <- unlist(strsplit(gsub(" ", "", oceanic_var_lines), ","))

  # The variables that are used in the configuration filed are kept in 'replace_values'.
  replace_values <- c()
  # We add in this table of variables the predefined values.
  replace_values <- putInDictionary(replace_values, "VAR_NAME", var)
  replace_values <- putInDictionary(replace_values, "STORE_FREQ", storefreq)
  # Parse the variables definitions in the whole configuration file
  if (key_positions[3] + 1 < key_positions[4]) {
    exp_table_definitions <- all_lines[(key_positions[3] + 1):(key_positions[4] - 1)]
  } else {
    exp_table_definitions <- c()
  }
  if (key_positions[5] + 1 < key_positions[6]) {
    file_per_ensemble_exp_table_definitions <- all_lines[(key_positions[5] + 1):(key_positions[6] - 1)]
  } else {
    file_per_ensemble_exp_table_definitions <- c()
  }
  if (key_positions[7] + 1 < key_positions[8]) {
    obs_table_definitions <- all_lines[(key_positions[7] + 1):(key_positions[8] - 1)]
  } else {
    obs_table_definitions <- c()
  }
  all_definitions <- c(exp_table_definitions, file_per_ensemble_exp_table_definitions, obs_table_definitions)
  if (length(grep("=", all_definitions)) == length(all_definitions)) {
    for (definition in all_definitions) {
      if (length(which(strsplit(definition, "")[[1]] == "=")) == 1) {
        var_name <- strsplit(definition, "=")[[1]][1]
        var_value <- strsplit(definition, "=")[[1]][2]
        if ((length(which(strsplit(var_value, "")[[1]] == "$")) %% 2) == 0) {
          replace_values <- putInDictionary(replace_values, var_name, var_value)
        } else {
          print('The configuration file is corrupted: there are incorrect variable definition lines in the definition zones. A closing "$" symbol may be missing.')
        }
      } else {
        print('The configuration file is corrupted: there are incorrect definition lines in the definition zones.')
      }
    }
  } else {
    print('The configuration file is corrupted: there are malformed definition lines in the definition zones.')
  }

  # Parse the experiments entries
  if (key_positions[4] + 1 < key_positions[5]) {
    exp_lines <- all_lines[(key_positions[4] + 1):(key_positions[5] - 1)]
  } else {
    exp_lines <- c()
  }
  exp_lines <- strsplit(exp_lines, ",")
  experiments <- list(c(), c(), c(), c())

  default_values <- c("$DEFAULT_EXP_MAIN_PATH$", "$DEFAULT_EXP_FILE_PATH$", "$DEFAULT_GRID$", "$DEFAULT_NC_VAR_NAME$")
  previous_values <- c("*", "*", default_values)
  for (entry in exp_lines) {
    if (entry[1] == '"') {
      entry[1] <- previous_values[1]
    }
    if ((length(entry) > 1)) {
      if (entry[2] == '"') {
        entry[2] <- previous_values[2]
      }
    } else {
      print('There variable column must be defined in all the entries in the tables in the configuration file.')
    }
    for (value_position in 1:length(default_values)) {
      if ((length(entry) > value_position + 1)) {
        if (entry[value_position + 2] == '"') {
          entry[value_position + 2] <- previous_values[value_position + 2]
        }
      } else {
        entry[value_position + 2] <- '*'
      }
    }
    if (entry[1] == '*') {
      if (entry[2] == '*') {
        experiments[[1]] <- c(experiments[[1]], list(entry))
      } else {
        experiments[[3]] <- c(experiments[[3]], list(entry))
      }
    } else {
      if (entry[2] == '*') {
        experiments[[2]] <- c(experiments[[2]], list(entry))
      } else {
        experiments[[4]] <- c(experiments[[4]], list(entry))
      }
    }
    previous_values <- entry
  }

  # Parse the file per ensemble experiments entries
  if (key_positions[6] + 1 < key_positions[7]) {
    file_per_ensemble_exp_lines <- all_lines[(key_positions[6] + 1):(key_positions[7] - 1)]
  } else {
    file_per_ensemble_exp_lines <- c()
  }
  file_per_ensemble_exp_lines <- strsplit(file_per_ensemble_exp_lines, ",")
  file_per_ensemble_exps <- list(c(), c(), c(), c())

  default_values <- c("$DEFAULT_EXP_MAIN_PATH$", "$DEFAULT_EXP_FILE_PATH$", "$DEFAULT_GRID$", "$DEFAULT_NC_VAR_NAME$")
  previous_values <- c("*", "*", default_values)
  for (entry in file_per_ensemble_exp_lines) {
    if (entry[1] == '"') {
      entry[1] <- previous_values[1]
    }
    if ((length(entry) > 1)) {
      if (entry[2] == '"') {
        entry[2] <- previous_values[2]
      }
    } else {
      print('There variable column must be defined in all the entries in the tables in the configuration file.')
    }
    for (value_position in 1:length(default_values)) {
      if ((length(entry) > value_position + 1)) {
        if (entry[value_position + 2] == '"') {
          entry[value_position + 2] <- previous_values[value_position + 2]
        }
      } else {
        entry[value_position + 2] <- '*'
      }
    }
    if (entry[1] == '*') {
      if (entry[2] == '*') {
        file_per_ensemble_exps[[1]] <- c(file_per_ensemble_exps[[1]], list(entry))
      } else {
        file_per_ensemble_exps[[3]] <- c(file_per_ensemble_exps[[3]], list(entry))
      }
    } else {
      if (entry[2] == '*') {
        file_per_ensemble_exps[[2]] <- c(file_per_ensemble_exps[[2]], list(entry))
      } else {
        file_per_ensemble_exps[[4]] <- c(file_per_ensemble_exps[[4]], list(entry))
      }
    }
    previous_values <- entry
  }

  # Parse the observations entries
  if (key_positions[8] + 1 < length(all_lines)) {
    obs_lines <- all_lines[(key_positions[8] + 1):length(all_lines)]
  } else {
    obs_lines <- c()
  }
  obs_lines <- strsplit(obs_lines, ",")
  observations <- list(c(), c(), c(), c())

  default_values <- c("$DEFAULT_OBS_MAIN_PATH$", "$DEFAULT_OBS_FILE_PATH$", "$DEFAULT_NC_VAR_NAME$")
  previous_values <- c("*", "*", default_values)
  for (entry in obs_lines) {
    if (entry[1] == '"') {
      entry[1] <- previous_values[1]
    }
    if ((length(entry) > 1)) {
      if (entry[2] == '"') {
        entry[2] <- previous_values[2]
      }
    } else {
      print('There variable column must be defined in all the entries in the tables in the configuration file.')
    }
    for (value_position in 1:length(default_values)) {
      if ((length(entry) > value_position + 1)) {
        if (entry[value_position + 2] == '"') {
          entry[value_position + 2] <- previous_values[value_position + 2]
        }
      } else {
        entry[value_position + 2] <- '*'
      }
    }
    if (entry[1] == '*') {
      if (entry[2] == '*') {
        observations[[1]] <- c(observations[[1]], list(entry))
      } else {
        observations[[3]] <- c(observations[[3]], list(entry))
      }
    } else {
      if (entry[2] == '*') {
        observations[[2]] <- c(observations[[2]], list(entry))
      } else {
        observations[[4]] <- c(observations[[4]], list(entry))
      }
    }
    previous_values <- entry
  }

  })
}

