#!/bin/bash

# Setting up COMPSs_HOME
if [ -z "${COMPSS_HOME}" ]; then
  COMPSS_HOME="$( cd "$( dirname "${BASH_SOURCE[0]}" )"/../../.. && pwd )/"
fi
if [ ! "${COMPSS_HOME: -1}" = "/" ]; then
  COMPSS_HOME="${COMPSS_HOME}/"
fi
export COMPSS_HOME=${COMPSS_HOME}


# Load auxiliar scripts
# shellcheck source=../system/commons/logger.sh
# shellcheck disable=SC1091
source "${COMPSS_HOME}Runtime/scripts/system/commons/logger.sh"
# shellcheck source=../system/commons/version.sh
# shellcheck disable=SC1091
source "${COMPSS_HOME}Runtime/scripts/system/commons/version.sh"
# shellcheck source=../system/commons/utils.sh
# shellcheck disable=SC1091
source "${COMPSS_HOME}Runtime/scripts/system/commons/utils.sh"
# shellcheck source=../system/runtime/compss_setup.sh
# shellcheck disable=SC1091
source "${COMPSS_HOME}Runtime/scripts/system/runtime/compss_setup.sh"


#---------------------------------------------------
# CONSTANTS DEFINTION
#---------------------------------------------------
# Default value for those parameters with a quick-enabling option (e.g., --monitoring=<int> | -m).
DEFAULT_LOG_LEVEL_ARGUMENT=${LOG_LEVEL_DEBUG}
DEFAULT_GRAPH_ARGUMENT=true
DEFAULT_MONITORING_INTERVAL_ARGUMENT=2000
DEFAULT_DEBUGGER_ARGUMENT=true
DEFAULT_SHUTDOWN_IN_NODE_FAILURE=false

APPLICATION_ERROR="ERROR: Application name not provided"
LANGUAGE_ERROR="ERROR: Value of option --lang must be: java, c or python"
TRACING_ERROR="ERROR: Value of option --tracing must be: false, true, basic, advanced, scorep, arm-map, and arm-ddt"


#---------------------------------------------------
# FUNCTIONS DECLARATION
#---------------------------------------------------

# Displays available options
show_opts() {
  cat <<EOT

  Tools enablers:
    --graph=<bool>, --graph, -g             Generation of the complete graph (true/false)
                                            When no value is provided it is set to ${DEFAULT_GRAPH_ARGUMENT}
                                            Default: ${DEFAULT_GRAPH}
    --tracing=<bool>, --tracing, -t         Set generation of traces.
                                            Default: ${DEFAULT_TRACING}
    --monitoring=<int>, --monitoring, -m    Period between monitoring samples (milliseconds)
                                            When no value is provided it is set to ${DEFAULT_MONITORING_INTERVAL_ARGUMENT}
                                            Default: ${DEFAULT_MONITORING_INTERVAL}
    --external_debugger=<int>,
    --external_debugger                     Enables external debugger connection on the specified port (or ${DEFAULT_DEBUGGER_PORT} if empty)
                                            Default: ${DEFAULT_DEBUGGER}
    --jmx_port=<int>                        Enable JVM profiling on specified port

  Runtime configuration options:
    --task_execution=<compss|storage>       Task execution under COMPSs or Storage.
                                            Default: ${DEFAULT_TASK_EXECUTION}
    --storage_impl=<string>                 Path to an storage implementation. Shortcut to setting pypath and classpath. See Runtime/storage in your installation folder.
    --storage_conf=<path>                   Path to the storage configuration file
                                            Default: ${DEFAULT_STORAGE_CONF}
    --project=<path>                        Path to the project XML file
                                            Default: ${DEFAULT_PROJECT}
    --resources=<path>                      Path to the resources XML file
                                            Default: ${DEFAULT_RESOURCES}
    --lang=<name>                           Language of the application (java/c/python)
                                            Default: Inferred is possible. Otherwise: ${DEFAULT_LANGUAGE}
    --summary                               Displays a task execution summary at the end of the application execution
                                            Default: ${DEFAULT_SUMMARY}
    --log_level=<level>, --debug, -d        Set the debug level: ${LOG_LEVEL_OFF} | ${LOG_LEVEL_INFO} | ${LOG_LEVEL_API} | ${LOG_LEVEL_DEBUG} | ${LOG_LEVEL_TRACE}
                                            Warning: Off level compiles with -O2 option disabling asserts and __debug__
                                            Default: ${DEFAULT_LOG_LEVEL}

  Advanced options:
    --extrae_config_file=<path>             Sets a custom extrae config file. Must be in a shared disk between all COMPSs workers.
                                            Default: ${DEFAULT_EXTRAE_CONFIG_FILE:-Empty}
    --extrae_config_file_python=<path>      Sets a custom extrae config file for python. Must be in a shared disk between all COMPSs workers.
                                            Default: ${DEFAULT_EXTRAE_CONFIG_FILE_PYTHON:-Empty}
    --trace_label=<string>                  Add a label in the generated trace file. Only used in the case of tracing is activated.
                                            Default: Applicacion name 
    --tracing_task_dependencies=<bool>      Adds communication lines for the task dependencies (true/false)
                                            Default: ${DEFAULT_TRACING_TASK_DEPENDENCIES}
    --generate_trace=<bool>                 Converts the events register into a trace file. Only used in the case of activated tracing.
                                            Default: ${DEFAULT_GENERATE_TRACE}
    --delete_trace_packages=<bool>          If true, deletes the tracing packages created by the run.
                                            Default: ${DEFAULT_TRACING_DELETE_PACKAGES}. Automatically, disabled if the trace is not generated.
    --custom_threads=<bool>                 Threads in the trace file are re-ordered and customized to indicate the function of the thread.
                                            Only used when the tracing is activated and a trace file generated.
                                            Default: ${DEFAULT_CUSTOM_THREAD_ORDER}
    --comm=<ClassName>                      Class that implements the adaptor for communications
                                            Supported adaptors:
                                                  ├── ${NIO_ADAPTOR}
                                                  └── ${GAT_ADAPTOR}
                                            Default: ${DEFAULT_COMMUNICATION_ADAPTOR}
    --conn=<className>                      Class that implements the runtime connector for the cloud
                                            Supported connectors:
                                                  ├── ${DEFAULT_SSH_CONNECTOR}
                                                  └── ${DEFAULT_NO_SSH_CONNECTOR}
                                            Default: ${DEFAULT_CONNECTOR}
    --streaming=<type>                      Enable the streaming mode for the given type.
                                            Supported types: FILES, OBJECTS, PSCOS, ALL, NONE
                                            Default: ${DEFAULT_STREAMING:-NONE}
    --streaming_master_name=<str>           Use an specific streaming master node name.
                                            Default: Empty
    --streaming_master_port=<int>           Use an specific port for the streaming master.
                                            Default: Empty
    --scheduler=<className>                 Class that implements the Scheduler for COMPSs
                                            Supported schedulers:
                                                  ├── ${BASE_SCHEDULER}
                                                  ├── ${OS_FIFO_SCHEDULER}
                                                  ├── ${LA_FIFO_SCHEDULER}
                                                  ├── ${LA_LIFO_SCHEDULER}
                                                  ├── ${LA_LOCALITY_SCHEDULER}
                                                  ├── ${LA_SUCC_CONSTRAINTS_FIFO_SCHEDULER}
                                                  ├── ${LA_MT_SUCC_CONSTRAINTS_FIFO_SCHEDULER}
                                                  ├── ${LA_SUCC_FIFO_SCHEDULER}
                                                  ├── ${LA_MT_SUCC_FIFO_SCHEDULER}
                                                  ├── ${LA_SUCC_LIFO_SCHEDULER}
                                                  ├── ${LA_MT_SUCC_LIFO_SCHEDULER}
                                                  ├── ${LA_SUCC_LOCALITY_SCHEDULER}
                                                  └── ${LA_MT_SUCC_LOCALITY_SCHEDULER}
                                            Default: ${DEFAULT_SCHEDULER}
    --scheduler_config_file=<path>          Path to the file which contains the scheduler configuration.
                                            Default: Empty
    --checkpoint=<className>                Class that implements the Checkpoint Management policy
                                            Supported checkpoint policies:
                                                  ├── ${CHECKPOINT_INSTANTIATED_GROUP}
                                                  ├── ${CHECKPOINT_PERIODIC_TIME}
                                                  ├── ${CHECKPOINT_FINISHED_TASKS}
                                                  └── ${NO_CHECKPOINT}
                                            Default: ${DEFAULT_CHECKPOINT}
    --checkpoint_params=<string>            Checkpoint configuration parameter.
                                            Default: Empty
    --checkpoint_folder=<path>              Checkpoint folder.
                                            Default: Mandatory parameter
    --library_path=<path>                   Non-standard directories to search for libraries (e.g. Java JVM library, Python library, C binding library)
                                            Default: Working Directory
    --classpath=<path>                      Path for the application classes / modules
                                            Default: Working Directory
    --appdir=<path>                         Path for the application class folder.
                                            Default: ${DEFAULT_APPDIR}
    --pythonpath=<path>                     Additional folders or paths to add to the PYTHONPATH
                                            Default: ${DEFAULT_PYTHONPATH}
    --env_script=<path>                     Path to the script file where the application environment variables are defined.
                                            COMPSs sources this script before running the application.
                                            Default: Empty
    --log_dir=<path>                        Directory to store COMPSs log files (a .COMPSs/ folder will be created inside this location)
                                            Default: User home
    --master_working_dir=<path>             Use a specific directory to store COMPSs temporary files in master
                                            Default: <log_dir>/.COMPSs/<app_name>/tmpFiles
    --uuid=<int>                            Preset an application UUID
                                            Default: Automatic random generation
    --master_name=<string>                  Hostname of the node to run the COMPSs master
                                            Default: ${DEFAULT_MASTER_NAME:-Empty}
    --master_port=<int>                     Port to run the COMPSs master communications.
                                            Only for NIO adaptor
                                            Default: ${DEFAULT_MASTER_PORT}
    --jvm_master_opts="<string>"            Extra options for the COMPSs Master JVM. Each option separed by "," and without blank spaces (Notice the quotes)
                                            Default: ${DEFAULT_JVM_MASTER:-Empty}
    --jvm_workers_opts="<string>"           Extra options for the COMPSs Workers JVMs. Each option separed by "," and without blank spaces (Notice the quotes)
                                            Default: ${DEFAULT_JVM_WORKERS:-Empty}
    --cpu_affinity="<string>"               Sets the CPU affinity for the workers
                                            Supported options: disabled, automatic, dlb or user defined map of the form "0-8/9,10,11/12-14,15,16"
                                            Default: ${DEFAULT_CPU_AFFINITY}
    --gpu_affinity="<string>"               Sets the GPU affinity for the workers
                                            Supported options: disabled, automatic, user defined map of the form "0-8/9,10,11/12-14,15,16"
                                            Default: ${DEFAULT_GPU_AFFINITY}
    --fpga_affinity="<string>"              Sets the FPGA affinity for the workers
                                            Supported options: disabled, automatic, user defined map of the form "0-8/9,10,11/12-14,15,16"
                                            Default: ${DEFAULT_FPGA_AFFINITY}
    --fpga_reprogram="<string>"             Specify the full command that needs to be executed to reprogram the FPGA with the desired bitstream. The location must be an absolute path.
                                            Default: ${DEFAULT_FPGA_REPROGRAM:-Empty}
    --io_executors=<int>                    IO Executors per worker
                                            Default: ${DEFAULT_IO_EXECUTORS}
    --task_count=<int>                      Only for C/Python Bindings. Maximum number of different functions/methods, invoked from the application, that have been selected as tasks
                                            Default: ${DEFAULT_TASK_COUNT}
    --input_profile=<path>                  Path to the file which stores the input application profile
                                            Default: Empty
    --output_profile=<path>                 Path to the file to store the application profile at the end of the execution
                                            Default: Empty
    --PyObject_serialize=<bool>             Only for Python Binding. Enable the object serialization to string when possible (true/false).
                                            Default: ${DEFAULT_PyOBJECT_SERIALIZE}
    --persistent_worker_c=<bool>            Only for C Binding. Enable the persistent worker in c (true/false).
                                            Default: ${DEFAULT_PERSISTENT_WORKER_C}
    --enable_external_adaptation=<bool>     Enable external adaptation. This option will disable the Resource Optimizer.
                                            Default: false
    --gen_coredump                          Enable master coredump generation
                                            Default: false
    --keep_workingdir                       Do not remove the worker working directory after the execution
                                            Default: false
    --python_interpreter=<string>           Python interpreter to use (python/python3).
                                            Default: ${DEFAULT_PYTHON_INTERPRETER} Version: ${DEFAULT_PYTHON_VERSION}
    --python_propagate_virtual_environment=<bool>  Propagate the master virtual environment to the workers (true/false).
                                                   Default: ${DEFAULT_PYTHON_PROPAGATE_VIRTUAL_ENVIRONMENT}
    --python_mpi_worker=<bool>              Use MPI to run the python worker instead of multiprocessing. (true/false).
                                            Default: ${DEFAULT_PYTHON_MPI_WORKER}
    --python_memory_profile                 Generate a memory profile of the master.
                                            Default: ${DEFAULT_PYTHON_MEMORY_PROFILE}
    --python_worker_cache=<string>          Python worker cache (true/size/false).
                                            Only for NIO without mpi worker and python >= 3.8.
                                            Default: ${DEFAULT_PYTHON_WORKER_CACHE:-false}
    --python_cache_profiler=<bool>          Python cache profiler (true/false).
                                            Only for NIO without mpi worker and python >= 3.8.
                                            Default: ${DEFAULT_PYTHON_CACHE_PROFILER:-false}
    --wall_clock_limit=<int>                Maximum duration of the application (in seconds).
                                            Default: ${DEFAULT_WALL_CLOCK_LIMIT}
    --shutdown_in_node_failure=<bool>       Stop the whole execution in case of Node Failure.
                                            Default: ${DEFAULT_SHUTDOWN_IN_NODE_FAILURE}
    --provenance, -p                        Generate COMPSs workflow provenance data in RO-Crate format from YAML file. Automatically activates -graph and -output_profile.
                                            Default: false

* Application name:
    For Java applications:   Fully qualified name of the application
    For C applications:      Path to the master binary
    For Python applications: Path to the .py file containing the main program

* Application arguments:
    Command line arguments to pass to the application. Can be empty.

EOT
}

# Displays usage message
usage() {
  exitValue=$1

  cat <<EOT
Usage: $0 [options] application_name application_arguments

* Options:
  General:
    --help, -h                              Print this help message

    --opts                                  Show available options

    --version, -v                           Print COMPSs version
EOT
  show_opts
  exit "$exitValue"
}


# Displays parsing arguments errors
arguments_error() {
  local error_msg=$1
  display_error "${error_msg}"
  usage 1
}

# Parses arguments from the command line
get_args() {
  # Parse COMPSs Options
  while getopts hvgtmdp-: flag; do
    # Treat the argument
    case "$flag" in
      h)
        # Display help
        usage 0
        ;;
      v)
        # Display version
        show_version
        exit
        ;;
      g)
        # Enable graph generation at the end of the execution
        graph=${DEFAULT_GRAPH_ARGUMENT}
        ;;
      t)
        # Enable tracing
        tracing=${TRACING_ENABLED}
        ;;
      m)
        # Enable monitoring with default value
        monitoring=${DEFAULT_MONITORING_INTERVAL_ARGUMENT}
        ;;
      d)
        # Enable debug in log level
        log_level=${DEFAULT_LOG_LEVEL_ARGUMENT}
        ;;
      p)
        # Enable provenance
        provenance=true
        if [ -z "$output_profile" ] ; then
          echo "PROVENANCE | Setting output_profile to App_Profile.json by default"
          output_profile="App_Profile.json"
        fi
        if [ -z "$graph" ] ; then
          echo "PROVENANCE | Setting --graph to true by default"
          graph=${DEFAULT_GRAPH_ARGUMENT}
        fi
        ;;
      -)
        # Check more complex arguments
        case "$OPTARG" in
          help)
            # Display help
            usage 0
            ;;
          version)
            # Show version
            show_full_version
            exit 0
            ;;
          opts)
            # Display help
            show_opts
            exit 0
            ;;
          flower)
            # Display flower
            show_flower
            exit 0
            ;;
          recipe)
            # Display recipe
            show_recipe
            exit 0
            ;;
          project=*)
            # Custom project file
            projFile=${OPTARG//project=/}
            if [ ! -f "$projFile" ]; then
              display_warning "Project XML file '$projFile' could not be found."
            fi
            ;;
          resources=*)
            # Custom resources file
            resFile=${OPTARG//resources=/}
            if [ ! -f "$resFile" ]; then
              display_warning "Resources XML file '$resFile' could not be found."
            fi
            ;;
          summary)
            summary=true
            ;;
          storage_conf=*)
            storageConf=${OPTARG//storage_conf=/}
            ;;
          storage_impl=*)
            storageImpl=${OPTARG//storage_impl=/}
            ;;
          streaming=*)
            streaming=${OPTARG//streaming=/}
            ;;
          streaming_master_name=*)
            streaming_master_name=${OPTARG//streaming_master_name=/}
            ;;
          streaming_master_port=*)
            streaming_master_port=${OPTARG//streaming_master_port=/}
            ;;
          task_execution=*)
            # Task execution under COMPSs or Storage
            taskExecution=${OPTARG//task_execution=/}
            ;;
          lang=*)
            # Language selection
            lang=${OPTARG//lang=/}
            ;;
          log_level=*)
            # Enable different log_levels by user selection
            log_level=${OPTARG//log_level=/}
            ;;
          debug*)
            # Enable debug in log level
            log_level=${DEFAULT_LOG_LEVEL_ARGUMENT}
            ;;
          graph=*)
            # Graph generation at the end of the execution with user option
            graph=${OPTARG//graph=/}
            ;;
          graph)
            # Graph generation at the end of the execution by default arg
            graph=${DEFAULT_GRAPH_ARGUMENT}
            ;;
          tracing=*)
            # Tracing system
            tracing=${OPTARG//tracing=/}
              # Tracing level
              if [ "${tracing}" == "false" ]; then
                tracing=${TRACING_DEACTIVATED}
              elif [ "${tracing}" == "true" ]; then
                tracing=${TRACING_ENABLED}
              else
                arguments_error "${TRACING_ERROR}"
              fi
            ;;
          tracing)
            # Tracing system
            tracing=${TRACING_ENABLED}
            ;;
          extrae_config_file=*)
            # Custom extrae config file
            custom_extrae_config_file=${OPTARG//extrae_config_file=/}
            ;;
          extrae_config_file_python=*)
            # Custom extrae config file
            custom_extrae_config_file_python=${OPTARG//extrae_config_file_python=/}
            ;;
          trace_label=*)
            # Custom trace_label
            trace_label=${OPTARG//trace_label=/}
            ;;
          monitoring=*)
            # Value between monitor steps (ms)
            monitoring=${OPTARG//monitoring=/}
            ;;
          monitoring)
            # Value between monitor steps (ms)
            monitoring=${DEFAULT_MONITORING_INTERVAL_ARGUMENT}
            ;;
          shutdown_in_node_failure=*)
            # Value between monitor steps (ms)
            shutdown_in_node_failure=${OPTARG//shutdown_in_node_failure=/}
            ;;
          comm=*)
            # Communication adaptor main class
            comm=${OPTARG//comm=/}
            ;;
          conn=*)
            # Communication connector main class
            conn=${OPTARG//conn=/}
            ;;
          classpath=*)
            # Additional classpath
            cp=${OPTARG//classpath=/}
            ;;
          library_path=*)
            # Additional library path
            library_path=${OPTARG//library_path=/}
            ;;
          env_script=*)
            # Application Environment script path
            if [ -z "${env_script_path}" ]; then
                env_script_path=${OPTARG//env_script=/}
            else
                env_script_path="${env_script_path}:${OPTARG//env_script=/}"
            fi
            # Application Environment script path
            ;;
          jvm_master_opts=*)
            # Master JVM option
            jvm_master_opts=${OPTARG//jvm_master_opts=/}
            ;;
          jvm_workers_opts=*)
            # Workers JVMs option
            jvm_workers_opts=${OPTARG//jvm_workers_opts=/}
            ;;
          cpu_affinity=*)
            # Worker CPU affinity
            worker_cpu_affinity=${OPTARG//cpu_affinity=/}
            ;;
          gpu_affinity=*)
            # Worker GPU affinity
            worker_gpu_affinity=${OPTARG//gpu_affinity=/}
            ;;
          fpga_affinity=*)
            # Worker FPGA affinity
            worker_fpga_affinity=${OPTARG//fpga_affinity=/}
            ;;
          fpga_reprogram=*)
            # Command to reprogram the FPGA with the specified bitstream
            fpga_prog=${OPTARG//fpga_reprogram=/}
            ;;
          io_executors=*)
            # Worker IO Executors
            worker_io_executors=${OPTARG//io_executors=/}
            ;;
          external_debugger=*)
            # Enable external debugger on specific port
            external_debugger=${DEFAULT_DEBUGGER_ARGUMENT}
            external_debugger_port=${OPTARG//external_debugger=/}
            ;;
          coverage=*)
            jacoco_agent_expression=${OPTARG//coverage=/}
            coverage=true
            ;;
          external_debugger)
            # Enable default external debugger
            external_debugger=${DEFAULT_DEBUGGER_ARGUMENT}
            ;;
          jmx_port=*)
            # Enable JMX profiler on specific port
            jmx_port=${OPTARG//jmx_port=/}
            ;;
          log_dir=*)
            # Set a custom base log dir
            log_dir=${OPTARG//log_dir=/}
            # Creating logs dir inside .COMPSs just in master worker execution
            # (compss_setup.sh assumes exec_dir will be log_dir)
            log_dir="${log_dir}/.COMPSs/"
            ;;
          base_log_dir=*)
            # Set a custom base log dir
            log_dir=${OPTARG//base_log_dir=/}
            echo "WARNING: base_log_dir is deprecated. Please, change it to log_dir."
            # Creating logs dir inside .COMPSs just in master worker execution
            # (compss_setup.sh assumes exec_dir will be log_dir)
            log_dir="${log_dir}/.COMPSs/"
            ;;
          specific_log_dir=*)
            # Set a custom specific log dir
            specific_log_dir=${OPTARG//specific_log_dir=/}
            ;;
          master_working_dir=*)
            # working directory for master
            wdir_in_master=${OPTARG//master_working_dir=/}
            ;;
          uuid=*)
            # Preset an Application UUID
            uuid=${OPTARG//uuid=/}
            ;;
          master_name=*)
            # Preset a Master hostname
            master_name=${OPTARG//master_name=/}
            ;;
          master_port=*)
            # Preset a Master port
            master_port=${OPTARG//master_port=/}
            ;;
          task_count=*)
            # Maximum task count. Only for bindings
            task_count=${OPTARG//task_count=/}
            ;;
          appdir=*)
            # Main binary directory (only for C/C++ applications)
            appdir=${OPTARG//appdir=/}
            ;;
          pythonpath=*)
            # Additional pythonpath
            pythonpath=${OPTARG//pythonpath=/}
            ;;
          PyObject_serialize=*)
            # Enable the object to string serialization (only for PyCOMPSs applications)
            PyObject_serialize=${OPTARG//PyObject_serialize=/}
            ;;
          persistent_worker_c=*)
            # Enable the persistent worker for C binding (only for C-binding applications)
            persistent_worker_c=${OPTARG//persistent_worker_c=/}
            ;;
          input_profile=*)
            # Specify the file where there is stored the tasks profiles
            input_profile=${OPTARG//input_profile=/}
            ;;
          output_profile=*)
            # Specify the file where COMPSs will store the tasks profile
            output_profile=${OPTARG//output_profile=/}
            ;;
          scheduler=*)
            # Scheduler main class
            scheduler=${OPTARG//scheduler=/}
            ;;
          scheduler_config_file=*)
            # Specify the configuration file for the scheduler policy
            scheduler_config=${OPTARG//scheduler_config_file=/}
            ;;
          checkpoint=*)
            # Checkpoint main class
            checkpoint=${OPTARG//checkpoint=/}
            ;;
          checkpoint_params=*)
            # Specify the configuration for the checkpoint policy
            checkpoint_params=${OPTARG//checkpoint_params=/}
            ;;
          checkpoint_folder=*)
            # Specify the folder for the checkpoint
            checkpoint_folder=${OPTARG//checkpoint_folder=/}
            ;;
          tracing_task_dependencies=*)
            # Specify if the tracing system registers task dependencies
            tracing_task_dependencies=${OPTARG//tracing_task_dependencies=/}
            ;;
          generate_trace=*)
            # Specify if the tracing system merges the events in a trace file
            tracing_generate_trace=${OPTARG//generate_trace=/}
            ;;
          delete_trace_packages=*)
            # Specify if the tracing system re-organizes the threads
            tracing_delete_packages=${OPTARG//delete_trace_packages=/}
            ;;
          custom_threads=*)
            # Specify if the tracing system re-organizes the threads
            tracing_custom_threads=${OPTARG//custom_threads=/}
            ;;
          enable_external_adaptation=*)
            # Enable the external adaptation (disables de Resource Optimizer)
            external_adaptation=${OPTARG//enable_external_adaptation=/}
            ;;
          python_interpreter=*)
            # Specify the python interpreter to use
            python_interpreter=${OPTARG//python_interpreter=/}
            ;;
          python_propagate_virtual_environment=*)
            # Enable or disable the virtual environment propagation
            python_propagate_virtual_environment=${OPTARG//python_propagate_virtual_environment=/}
            ;;
          python_mpi_worker=*)
            # Enable or disable the virtual environment propagation
            python_mpi_worker=${OPTARG//python_mpi_worker=/}
            ;;
          python_memory_profile)
            # Enable or disable the master memory profiling
            python_memory_profile=true
            ;;
          python_worker_cache=*)
            # Enable or disable the worker cache
            python_worker_cache=${OPTARG//python_worker_cache=/}
            ;;
          python_cache_profiler=*)
            # Enable or disable the worker cache
            python_cache_profiler=${OPTARG//python_cache_profiler=/}
            ;;
          gen_coredump)
            # Enable coredump generation
            gen_core=true
            ;;
          keep_workingdir)
            # Enable coredump generation
            keepWD=true
            ;;
          wall_clock_limit=*)
            # Set wall_clock_limit
            wall_clock_limit=${OPTARG//wall_clock_limit=/}
            ;;
          provenance)
            # Enable provenance
            provenance=true
            if [ -z "$output_profile" ] ; then
              echo "PROVENANCE | Setting output_profile to App_Profile.json by default"
              output_profile="App_Profile.json"
            fi
            if [ -z "$graph" ] ; then
              echo "PROVENANCE | Setting --graph to true by default"
              graph=${DEFAULT_GRAPH_ARGUMENT}
            fi
            ;;
          *)
            # Flag didn't match any patern. Raise exception
            arguments_error "Bad argument: $OPTARG"
            ;;
        esac
        ;;
      *)
        # Flag didn't match any patern. End of COMPSs flags
        break
        ;;
    esac
  done
  # Shift COMPSs arguments
  shift $((OPTIND-1))

  # Parse application name
  if [[ $# -eq 0 ]]; then
    arguments_error "${APPLICATION_ERROR}"
  else
    fullAppPath=$1
    if [ -z "$fullAppPath" ]; then
      arguments_error "${APPLICATION_ERROR}"
    else
      shift 1
    fi
  fi

  # Parse application arguments
  application_args=$*
  if [ $provenance ]; then
    echo $fullAppPath $application_args > compss_command_line_arguments.txt
  fi
}

check_args() {

  if [ -z "$lang" ]; then
    # Try to infer language
    infer_language "$fullAppPath" "${DEFAULT_LANGUAGE}"
  fi


  if [ "$lang" == "java" ]; then
    lang=java
  elif [ "$lang" == "c" ]; then
    lang=c
  elif [ "$lang" == "python" ]; then
    lang=python
  else
    arguments_error "${LANGUAGE_ERROR}"
  fi

  if [ -z "$shutdown_in_node_failure" ]; then
    shutdown_in_node_failure=${DEFAULT_SHUTDOWN_IN_NODE_FAILURE}
  fi

  check_compss_setup
}

clean_env() {
  clear_compss_app
  rm -f App_Profile.json compss_command_line_arguments.txt
}


#---------------------------------------------------
# MAIN EXECUTION
#---------------------------------------------------

# Environment
check_compss_env

# Validate arguments
get_args "$@"
check_args

# Trap to ensure clean end
trap clean_env EXIT

echo "[RUNCOMPSS] ${env_script_path}"
if [ -n "${env_script_path}" ]; then
  echo "[RUNCOMPSS] Loading environment scripts"
  scripts=$(echo "${env_script_path}" | tr ":" " ")
  for script in $scripts
  do
    echo "[RUNCOMPSS] Loading $script"
    source $script
  done
fi
# Real runtime execution
start_compss_app

if [ ${provenance} ]; then
  echo "PROVENANCE | GENERATING GRAPH FOR DATA PROVENANCE"
  start=`date +%s`
  "${COMPSS_HOME}Runtime/scripts/utils/compss_gengraph" "svg" "${specific_log_dir}/monitor/complete_graph.dot"
  end=`date +%s`
  echo "PROVENANCE | ENDED GENERATING GRAPH FOR DATA PROVENANCE. TIME: $(( end - start ))"

  echo "PROVENANCE | RUNNING DATA PROVENANCE SCRIPT"
  python "${COMPSS_HOME}Runtime/scripts/system/provenance/generate_COMPSs_RO-Crate.py" "ro-crate-info.yaml" "${specific_log_dir}/dataprovenance.log"
  if [ "${output_profile}" == "App_Profile.json" ]; then # Auto-generated, user doesn't want it
    rm -f App_Profile.json
  fi
  echo "PROVENANCE | ENDED DATA PROVENANCE SCRIPT"
fi
