class ActionSimulatorTool implements Tool {

    @Override
    public void run(CommandLine line, ToolRunningContext context) throws Exception {
        Path caseFile = context.getFileSystem().getPath(line.getOptionValue(CASE_FILE));
        Path dslFile = context.getFileSystem().getPath(line.getOptionValue(DSL_FILE));
        List<String> contingencies = line.hasOption(CONTINGENCIES) ? Arrays.stream(line.getOptionValue(CONTINGENCIES).split(",")).collect(Collectors.toList())
                                                                     : Collections.emptyList();
        boolean verbose = line.hasOption(VERBOSE);
        boolean applyIfSolved = line.hasOption(APPLY_IF_SOLVED_VIOLATIONS);
        boolean isSubTask = line.hasOption(TASK_COUNT);

        if (isSubTask) {
            checkOptionsInParallel(line);
        }

        //Create observers
        List<LoadFlowActionSimulatorObserver> observers = new ArrayList<>();
        if (!isSubTask) {
            optionalCaseExporter(line, context.getFileSystem(), DataSourceUtil.getBaseName(caseFile))
                    .ifPresent(observers::add);
        }
        observers.add(createLogPrinter(context, verbose));

        // load network
        context.getOutputStream().println("Loading network '" + caseFile + "'");
        Properties inputParams = readProperties(line, ConversionToolUtils.OptionType.IMPORT, context);
        Network network = Importers.loadNetwork(caseFile, context.getShortTimeExecutionComputationManager(), ImportConfig.load(), inputParams);

        try {
            // load actions from Groovy DSL
            ActionDb actionDb = new ActionDslLoader(dslFile.toFile())
                    .load(network, new ActionDslLoaderObserver(context.getOutputStream(), verbose));

            if (contingencies.isEmpty()) {
                contingencies = actionDb.getContingencies().stream().map(Contingency::getId).collect(Collectors.toList());
            }

            LoadFlowActionSimulatorConfig config = LoadFlowActionSimulatorConfig.load();

            List<Consumer<SecurityAnalysisResult>> resultHandlers = new ArrayList<>();
            resultHandlers.add(createResultPrinter(network, context));
            optionalResultPrinter(line, context.getFileSystem()).ifPresent(resultHandlers::add);

            // action simulator
            LOGGER.debug("Creating action simulator.");
            if (isSubTask) {

                context.getOutputStream().println("Using parallel load flow action simulator rules engine");

                int taskCount = Integer.parseInt(line.getOptionValue(TASK_COUNT));
                ParallelLoadFlowActionSimulator actionSimulator = new ParallelLoadFlowActionSimulator(network,
                        context.getLongTimeExecutionComputationManager(), taskCount, config, applyIfSolved, resultHandlers);

                String dsl = new String(Files.readAllBytes(dslFile), StandardCharsets.UTF_8);
                actionSimulator.run(dsl, contingencies);
            } else {

                ActionSimulator actionSimulator = createActionSimulator(network, context, line, config, applyIfSolved, observers, resultHandlers);

                context.getOutputStream().println("Using '" + actionSimulator.getName() + "' rules engine");

                // start simulator
                actionSimulator.start(actionDb, contingencies);
            }
        } catch (Exception e) {
            LOGGER.trace(e.toString(), e); // to avoid user screen pollution...
            Throwable rootCause = StackTraceUtils.sanitizeRootCause(e);
            rootCause.printStackTrace(context.getErrorStream());
        }
    }

}