process {
  // Default resources for components that hardly do any processing
  memory = { 2.GB * task.attempt }
  cpus = 1

  // Retry for exit codes that have something to do with memory issues
  errorStrategy = { task.exitStatus in 137..140 ? 'retry' : 'terminate' }
  maxRetries = 3
  maxMemory = null

  // CPU resources
  withLabel: singlecpu { cpus = 1 }
  withLabel: lowcpu { cpus = 4 }
  withLabel: midcpu { cpus = 10 }
  withLabel: highcpu { cpus = 20 }
  
  // Memory resources
  withLabel: verylowmem { memory = { get_memory( 4.GB * task.attempt ) } }
  withLabel: lowmem { memory = { get_memory( 8.GB * task.attempt ) } }
  withLabel: midmem { memory = { get_memory( 16.GB * task.attempt ) } }
  withLabel: highmem { memory = { get_memory( 64.GB * task.attempt ) } }
  withLabel: veryhighmem { memory = { get_memory( 75.GB * task.attempt ) } }

  // Disk space
  withLabel: lowdisk {
    disk = {process.disk ? process.disk : null}
  }
  withLabel: middisk {
    disk = {process.disk ? process.disk : null}
  }
  withLabel: highdisk {
    disk = {process.disk ? process.disk : null}
  }
  withLabel: veryhighdisk {
    disk = {process.disk ? process.disk : null}
  }
  // NOTE: The above labels intentionally do not have an effect by default.
  // The user should set the disk space requirements by adding the following
  // to the compute environment:
  //
  // withLabel: lowdisk { disk = { 20.GB * task.attempt } }
  // withLabel: middisk { disk = { 100.GB * task.attempt } }
  // withLabel: highdisk { disk = { 200.GB * task.attempt } }
  // withLabel: veryhighdisk { disk = { 500.GB * task.attempt } }
}

def get_memory(to_compare) {
  if (!process.containsKey("maxMemory") || !process.maxMemory) {
    return to_compare
  }

  try {
    if (process.containsKey("maxRetries") && process.maxRetries && task.attempt == (process.maxRetries as int)) {
      return process.maxMemory
    }
    else if (to_compare.compareTo(process.maxMemory as nextflow.util.MemoryUnit) == 1) {
      return max_memory as nextflow.util.MemoryUnit
    }
    else {
      return to_compare
    }  
  } catch (all) {
        println "Error processing memory resources. Please check that process.maxMemory '${process.maxMemory}' and process.maxRetries '${process.maxRetries}' are valid!"
        System.exit(1)
  }
}
