jtabwb.launcher.Launcher.java Source code

Java tutorial

Introduction

Here is the source code for jtabwb.launcher.Launcher.java

Source

/*******************************************************************************
 * Copyright (C) 2013, 2016 Mauro Ferrari This program is free software; you can
 * redistribute it and/or modify it under the terms of the GNU General Public
 * License as published by the Free Software Foundation; either version 3 of the
 * License, or (at your option) any later version. This program is distributed
 * in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
 * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU General Public License for more details. You should have received
 * a copy of the GNU General Public License along with this program; if not, see
 * <http://www.gnu.org/licenses/>.
 ******************************************************************************/
package jtabwb.launcher;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.io.StringReader;
import java.io.StringWriter;
import java.lang.management.ManagementFactory;
import java.lang.management.ThreadMXBean;
import java.text.SimpleDateFormat;
import java.util.Collection;
import java.util.Date;
import java.util.concurrent.TimeUnit;

import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.Options;

import jtabwb.engine.Engine;
import jtabwb.engine.Engine.ExecutionMode;
import jtabwb.engine.IterationInfo;
import jtabwb.engine.ProofSearchResult;
import jtabwb.engine.ProvabilityStatus;
import jtabwb.engine.ProverName;
import jtabwb.engine.TraceException;
import jtabwb.engine._AbstractGoal;
import jtabwb.engine._Prover;
import jtabwb.tracesupport.CTree;
import jtabwb.tracesupport._LatexSupport;
import jtabwbx.problems.ProblemDescription;
import jtabwbx.problems.ProblemDescriptionException;

/**
 * A command line launcher for JTabWb provers. It allows one to define a
 * launcher providing different provers and different problem description
 * readers. A client of the launcher goes through the following steps:
 * <ul>
 * <li>Launcher configuration (mandatory).</li>
 * <li>Launcher customisation (optional).</li>
 * <li>Command line arguments processing (mandatory):</li>
 * <li>Launcher execution and data extraction.</li>
 * </ul>
 * 
 * <h3>Launcher configuration (mandatory)</h3>
 * 
 * Launcher configuration (mandatory). The client must provide the essential
 * elements needed to the launcher invoking the <code>configX()</code> methods.
 * In details the client must invoke:
 * <ul>
 * <li>{@link #configLauncherName(String)} to define the name of the main
 * application executing the launcher; this name is used in the help message
 * generated by the launcher.</li>
 * <li>{@link #configStandardInputReader(_ProblemReader)} to define the reader
 * used to read a problem from standard input.</li>
 * <li>one of the methods {@link #configProblemDescriptionReader(String, Class)}
 * and {@link #configProblemDescriptionReader(String, Class, boolean)} to define
 * at least a problem description reader (more than one reader can be
 * configured).</li>
 * <li>one of the methods {@link #configTheoremProver(String, Class)} and
 * {@link #configTheoremProver(String, Class, boolean)} to define at least a
 * theorem prover (more than one theorem prover can be configured).</li>
 * </ul>
 * 
 * 
 * <h3>Launcher customisation (optional)</h3> .
 * 
 * The client can customise the launcher behaviour using the
 * <code>optConfigX</code> methods. In details:
 * <ul>
 * <li>{@link #optConfigCmdLineOptions(Options)}: to define command line options
 * for the client. The names of the added options cannot overlap the names of
 * the options defined by the launcher.</li>
 * 
 * <li>{@link #optConfigInputSyntax(String)}: to define a message with the
 * description of the syntax of the formulas provided by standard input.</li>
 * 
 * <li>{@link #optConfigWelcomeMessage(String)}: to define a welcome message.</li>
 * 
 * <li>
 * {@link #optConfigSingleExecutionConfigurator(_SingleExecutionConfigurator)}:
 * set the configurator to invoke before every execution. a
 * {@link _SingleExecutionConfigurator} is an object allowing to properly
 * configure every element of the pipeline before its execution.
 * </ul>
 * 
 * <p>
 * The method {@link #getCmdLineOptionsManager()} can be used to get direct
 * access to the command line options manager of the launcher.
 * </p>
 * 
 * 
 * 
 * <h3>Command line arguments processing (mandatory)</h3>
 * 
 * Before executing the launcher the client must invoke
 * {@link Launcher#processCmdLineArguments(String[])} providing as argument the
 * strings on the command line. These arguments are processed according with the
 * syntax of the defined options. If the syntax of the argument does not
 * contains errors the launcher configure its runtime options accordingly. Then
 * the method returns the {@link LaunchConfiguration} describing the launch
 * configuration corresponding to the parsed options (if any).
 * 
 * 
 * <p>
 * The launcher predefined command line options are the following:
 * </p>
 * 
 * <pre>
 * {@code
 *     --f3time                Prints on the standard output timing info in
 *                             f3 format.
 *  -h                         Print usage message and exit.
 *  -i                         Read the formula from standard input.
 *     --jtabwbtime            Prints on the standard output timing info in
 *                             JTabWb format.
 *     --latex-ctrees          Save the LaTeX of the c-trees generated by the
 *                             proof-search in the specified file.
 *     --latex-proof           Save the LaTeX of the proof generated by a
 *                             successful proof-search in the specified file.
 *     --log                   Save execution details in the the specified
 *                             file.
 *     --logdir <filename>     Defines the directory used to save log files.
 *     -p <name>               Set the theorem prover, if this option is not
 *                             set the default is used. 
 *     --provers               Detailed description of available provers.
 *  -r <name>                  Set the formula reader, if this option is not
 *                             set the default is used.
 *     --readers               Detailed description of available readers.
 *     --save-trace            Save the trace of the proof-search in the
 *                             specified file.
 *     --testset <test-name>   Execute a test on the problems specified on
 *                             the command line. test-name is used to name
 *                             the log files.
 *     --time                  Save time execution details in the specified
 *                             file.
 *  -v                         Print detailed informations on the proof
 *                             process.
 * }
 * </pre>
 * 
 * 
 * <h3>Launcher execution and data extraction</h3>
 * 
 * <p>
 * The methods {@link #launch()} executes the proof-search according with the
 * specified command line arguments.
 * </p>
 * 
 * <p>
 * When the execution of the proof-search terminates, the client can inspect the
 * details of the performed proof-search accessing the {@link ProofSearchData}
 * object returned by the {@link #getLastProofSearchData()} method.
 * </p>
 * 
 * @author Mauro Ferrari
 */
public class Launcher {

    final static String DEFAULT_LOG_DIR_NAME = "log";
    final static String DEFAULT_LOG_FILE_NAME_PREFIX = "proofSearch-";
    final static String DEFAULT_LOG_FILE_NAME_SUFFIX = ".log";
    final static String DEFAULT_LOG_TIME_FILE_NAME_PREFIX = "time-";
    final static String DEFAULT_LOG_TIME_FILE_NAME_SUFFIX = ".log";
    final static String DEFAULT_LATEX_PROOF_FILE_NAME_PREFIX = "proof-";
    final static String DEFAULT_LATEX_PROOF_FILE_NAME_SUFFIX = ".tex";
    final static String DEFAULT_LATEX_CTREE_FILE_NAME_PREFIX = "ctrees-";
    final static String DEFAULT_LATEX_CTREE_FILE_NAME_SUFFIX = ".tex";
    final static String DEFAULT_TESTSET_FILE_PREFIX = "testset-";
    final static String DEFAULT_TESTSET_FILE_SUFFIX = ".log";
    final static String DEFAULT_TRACE_FILE_NAME_PREFIX = "trace-";
    final static String DEFAULT_TRACE_FILE_NAME_SUFFIX = ".log";

    final Log LOG;
    boolean processCmdLineOptionsExecuted = false;
    LaunchConfiguration currentConfiguration;
    ProofSearchData lastProofSearchData;
    TestsetDetails testsetDetails;
    ThreadMXBean bean;

    /**
     * Constructs a new launcher.
     */
    public Launcher() {
        this.LOG = new Log();
        this.processCmdLineOptionsExecuted = false;
        this.currentConfiguration = new LaunchConfiguration();
        bean = ManagementFactory.getThreadMXBean();
    }

    private _AbstractGoal buildInitialNodeSet(ProofSearchData info) {
        _AbstractGoal initialNodeSet = null;
        // build the initial node set
        try {
            if (!currentConfiguration.testsetmode)
                LOG.infoNoLn(MSG.LAUNCHER.INFO.INITIAL_NODE_SET_BUILDING_BEGIN);
            // configure the initial node set builder
            if (currentConfiguration.singleExecutionConfigurator != null)
                currentConfiguration.singleExecutionConfigurator
                        .configInitialNodeSetBuilder(info.problemDescription, currentConfiguration);
            // build initial node set
            info.initial_node_set_construction_start_time = getCurrentTimeMilleseconds();
            initialNodeSet = currentConfiguration.initialNodeSetBuilder
                    .buildInitialNodeSet(info.problemDescription);
            info.initial_node_set_construction_end_time = getCurrentTimeMilleseconds();

            if (!currentConfiguration.testsetmode)
                LOG.info(MSG.LAUNCHER.INFO.INITIAL_NODE_SET_BUILDING_END, info.getIntialNodeSetConstructionTime());
        } catch (InitialGoalBuilderException e) {
            LOG.error(MSG.LAUNCHER.ERROR_MSG.INITIAL_NODE_BUILDER_ERROR, e.getMessage());
            System.exit(1);
        }
        return initialNodeSet;
    }

    /**
     * Defines the name of the class using this launcher to execute a prover.
     * 
     * @param launcherClassName the name of the class invoking this launcher.
     */
    public void configLauncherName(String launcherClassName) {
        currentConfiguration.launcherClassName = launcherClassName;
    }

    /**
     * Adds to this launcher a theorem prover with the specified name and
     * implementation. The specified prover is not the default prover for this
     * launcher, apart from the case where the specified prover is the only prover
     * added to this launcher.
     * 
     * @param prover the class implementing the prover
     * @param <T> the class of the prover
     * @param name the name of the prover
     * @throws ProverDefinitionException if there is some problem with the added
     * prover.
     */
    public <T extends _Prover> void configTheoremProver(String name, Class<T> prover)
            throws ProverDefinitionException {
        this.configTheoremProver(name, prover, false);
    }

    /**
     * Adds a theorem prover with the specified name and implementation to this
     * launcher specifying if it is ( <code>isDefault==true</code>) or not (
     * <code>isDefault==false</code>) the default prover for this launcher. The
     * default prover is the last one for which this method is invoked with
     * <code>isDefault==true</code>.
     * 
     * @param name the name of the prover.
     * @param <T> the class of the prover
     * @param prover the class implementing the prover.
     * @param isDefault specify if this is the default prover for the launcher.
     * @throws ProverDefinitionException if there is some problem with the added
     * prover.
     */
    @SuppressWarnings("unchecked")
    public <T extends _Prover> void configTheoremProver(String name, Class<T> prover, boolean isDefault)
            throws ProverDefinitionException {

        _Prover instance = null;
        try {
            instance = (_Prover) ((Class<_Prover>) prover).newInstance();
        } catch (InstantiationException e) {
            throw new ProverDefinitionException(String
                    .format(MSG.LAUNCHER.CONFIGURATION_EXCEPTIONS.PROVER_INSTANTIATION_ERROR, prover.getName()));
        } catch (IllegalAccessException e) {
            throw new ProverDefinitionException(String
                    .format(MSG.LAUNCHER.CONFIGURATION_EXCEPTIONS.PROVER_INSTANTIATION_ERROR, prover.getName()));
        }
        if (name == null || name.equals(""))
            throw new ProverDefinitionException(
                    String.format(MSG.LAUNCHER.CONFIGURATION_EXCEPTIONS.PROVER_WRONG_NAME));

        if (currentConfiguration.availableProvers.searchByName(name) != null)
            throw new ProverDefinitionException(
                    String.format(MSG.LAUNCHER.CONFIGURATION_EXCEPTIONS.PROVER_NAME_ALREADY_DEFINED, name));

        currentConfiguration.availableProvers.addProver(name, instance.getProverName().getDescription(),
                (Class<_Prover>) prover, isDefault);
    }

    /**
     * Adds a problem description reader with the specified name and
     * implementation to this launcher. The specified reader is not the default
     * reader for this launcher, apart from the case where the specified reader is
     * the only reader added to this launcher.
     * 
     * @param name the name of the reader
     * @param reader the class implementing the reader
     * @param <T> the class implementing the problem description reader
     * @throws ReaderDefinitionException if there is some problem with the added
     * reader
     */
    public <T extends _ProblemReader> void configProblemDescriptionReader(String name, Class<T> reader)
            throws ReaderDefinitionException {
        this.configProblemDescriptionReader(name, reader, false);
    }

    /**
     * Adds a problem description reader with the specified name and
     * implementation to this launcher specifying if it is (
     * <code>isDefault==true</code>) or not (<code>isDefault==false</code>) the
     * default problem description reader for this launcher. The default reader is
     * the last one for which this method is invoked with
     * <code>isDefault==true</code> .
     * 
     * @param name the name of the reader
     * @param <T> the class implementing the problem description reader
     * @param reader the class implementing the reader
     * @param isDefault specify if this is the default reader for the launcher
     * @throws ReaderDefinitionException if there is some problem with the added
     * reader
     */
    @SuppressWarnings("unchecked")
    public <T extends _ProblemReader> void configProblemDescriptionReader(String name, Class<T> reader,
            boolean isDefault) throws ReaderDefinitionException {

        _ProblemReader instance = null;
        try {
            instance = (_ProblemReader) ((Class<_ProblemReader>) reader).newInstance();
        } catch (InstantiationException e) {
            throw new ReaderDefinitionException(String
                    .format(MSG.LAUNCHER.CONFIGURATION_EXCEPTIONS.READER_INSTANTIATION_ERROR, reader.getName()));
        } catch (IllegalAccessException e) {
            throw new ReaderDefinitionException(String
                    .format(MSG.LAUNCHER.CONFIGURATION_EXCEPTIONS.READER_INSTANTIATION_ERROR, reader.getName()));
        }
        if (name == null || name.equals(""))
            throw new ReaderDefinitionException(
                    String.format(MSG.LAUNCHER.CONFIGURATION_EXCEPTIONS.READER_WRONG_NAME));

        if (currentConfiguration.availableReaders.searchByName(name) != null)
            throw new ReaderDefinitionException(
                    String.format(MSG.LAUNCHER.CONFIGURATION_EXCEPTIONS.READER_NAME_ALREADY_DEFINED, name));

        currentConfiguration.availableReaders.addReader(name, instance.getDescription(),
                (Class<_ProblemReader>) reader, isDefault);
    }

    /**
     * Defines the initial node set builder to use.
     * 
     * @param builder the initial node set builder.
     */
    public void configInitialNodeSetBuilder(_InitialGoalBuilder builder) {
        currentConfiguration.initialNodeSetBuilder = builder;
    }

    /**
     * Defines the reader used to parse a problem from standard input when
     * <code>-i</code> option is set.
     * 
     * @param stdInputProblemReader the problem description reader for standard
     * input.
     */
    public void configStandardInputReader(_ProblemReader stdInputProblemReader) {
        currentConfiguration.stdinReader = stdInputProblemReader;
    }

    // TODO: doc
    public void optConfigSingleExecutionConfigurator(_SingleExecutionConfigurator configurator) {
        currentConfiguration.singleExecutionConfigurator = configurator;
    }

    private _Prover configProver(ProofSearchData info) {
        try {
            _Prover prover = currentConfiguration.selectedProver.getValue().newInstance();
            if (currentConfiguration.singleExecutionConfigurator != null)
                currentConfiguration.singleExecutionConfigurator.configProver(prover, info.goal,
                        currentConfiguration);

            // TODO: eliminare dipendenza da _LatexSupport
            currentConfiguration.selectedProverName = prover.getProverName();
            if (currentConfiguration.generateLatexOfProof || currentConfiguration.generateLatexOfCtrees)
                if (!(prover instanceof _LatexSupport)) {
                    LOG.error(MSG.LAUNCHER.ERROR_MSG.LATEX_SUPPORT_REQUIRED,
                            prover.getProverName().getProperNoun());
                    System.exit(0);
                }
            return prover;
            /*
             * we already tested that a visible nullary constructor exists for this
             * class when we added it to availableProvers
             */
        } catch (InstantiationException e) {
        } catch (IllegalAccessException e) {
        }
        return null;
    }

    /**
     * Returns data about the last proof-search.
     * 
     * @return the data about the last proof-search.
     */
    public ProofSearchData getLastProofSearchData() {
        return lastProofSearchData;
    }

    /**
     * Returns the command line options manger used by this launcher.
     * 
     * @return the command line options manager of this launcher.
     */
    public Options getCmdLineOptionsManager() {
        return currentConfiguration.cmdLineOptions;
    }

    /**
     * Return an object describing the relevant details about the configuration of
     * the launcher.
     * 
     * @return the configuration of the launcher
     */
    public LaunchConfiguration getCurrentLauncherConfiguration() {
        return currentConfiguration;
    }

    private TestsetDetails initilizeTesetDetails() {
        TestsetDetails testsetDetails = new TestsetDetails();
        testsetDetails.proverName = currentConfiguration.selectedProverName;
        testsetDetails.testsetName = currentConfiguration.testsetName;
        testsetDetails.startTime = new Date();
        try {
            testsetDetails.tempFile = File.createTempFile("tmp-testset-"
                    + replaceSpacesWithUnderscore(currentConfiguration.selectedProverName.getProperNoun()) + "-",
                    ".tmp", getLogDir());
            testsetDetails.pw4TempFile = new PrintWriter(
                    new BufferedWriter(new FileWriter(testsetDetails.tempFile)));
        } catch (IOException e) {
            LOG.error(MSG.LAUNCHER.ERROR_MSG.TESTSET_TMP_FILE_CANNOT_BE_CREATEd, e.getMessage());
            System.exit(1);
        }

        return testsetDetails;
    }

    /**
     * Launches the prover.
     * 
     * @throws LauncherExecutionException if processComdLineOptions has not been
     * executed before this method invocation
     * @throws LauncherConfigurationException if the current configuration cannot
     * be executed
     */
    public void launch() throws LauncherExecutionException, LauncherConfigurationException {
        try {
            if (currentConfiguration.launcherWelcomeMessage != null)
                LOG.info(currentConfiguration.launcherWelcomeMessage);

            if (!processCmdLineOptionsExecuted) // processCmdLineArguments must be executed before launch
                throw new LauncherExecutionException(
                        String.format(MSG.LAUNCHER.INVOCATION_EXCEPTIONS.PROCESS_OPTIONS_NOT_EXECUTED));

            // check compatibility of runtime options
            currentConfiguration.checkConfiguration();

            // either the input option is set or a file name is given
            String[] fileNames = currentConfiguration.commandLine.getArgs();
            if (currentConfiguration.readFromStandardInput) {
                if (fileNames.length > 0) {
                    LOG.error(MSG.LAUNCHER.ERROR_MSG.INPUT_AND_FILENAMES);
                    System.exit(1);
                }
            } else if (fileNames.length == 0) {
                LOG.error(MSG.LAUNCHER.ERROR_MSG.NO_INPUT_IS_SPECIFIED);
                System.exit(1);
            }

            if (currentConfiguration.readFromStandardInput) {
                ProofSearchData info = new ProofSearchData();
                // read problem  
                info.problemDescription = readFromStandardInput(info);
                // build initial node set;
                info.goal = buildInitialNodeSet(info);
                // configure prover
                info.selectedProver = configProver(info);
                info_preProverExecutionDetails();
                // search for proof
                searchProof(info);
                lastProofSearchData = info;
            } else if (currentConfiguration.testsetmode) {
                boolean firstTest = true;
                for (String problemFileName : fileNames) {
                    ProofSearchData info = new ProofSearchData();
                    // read problem    
                    info.problemDescription = readFromFile(info, problemFileName);
                    // build initial node set;
                    info.goal = buildInitialNodeSet(info);
                    // configure prover
                    info.selectedProver = configProver(info);
                    if (firstTest) {
                        testsetDetails = initilizeTesetDetails();
                        firstTest = false;
                    }
                    // search for proof
                    searchProof(info);
                    updateTestSetDetails(info);
                    lastProofSearchData = info;
                }
                testset_printReport();

            } else {
                for (String problemFileName : fileNames) {
                    ProofSearchData info = new ProofSearchData();
                    // read problem
                    info.problemDescription = readFromFile(info, problemFileName);
                    // build initial node set;
                    info.goal = buildInitialNodeSet(info);
                    // config prover
                    info.selectedProver = configProver(info);
                    info_preProverExecutionDetails();
                    // search for proof
                    searchProof(info);
                    lastProofSearchData = info;
                }
            }
        } catch (Exception e) {
            StringWriter strwr = new StringWriter();
            PrintWriter pw = new PrintWriter(strwr);
            e.printStackTrace(pw);
            LOG.error(MSG.LAUNCHER.ERROR_MSG.LAUNCH_EXECUTION_EXCEPTION, strwr.toString());
            System.exit(1);
        }
    }

    /**
     * Processes the command line arguments and defines the configuration of the
     * launcher; the method returns the object describing the essential details of
     * the current launcher configuration.
     * 
     * @param args the command line arguments
     * @return the launcher configuration as built processing the command line
     * options
     */
    public Launcher.LaunchConfiguration processCmdLineArguments(String[] args) {

        // TODO: put in a checkLauncherConfiguration Method
        if (currentConfiguration.availableReaders.isEmpty())
            throw new LauncherExecutionException(
                    String.format(MSG.LAUNCHER.INVOCATION_EXCEPTIONS.AVAILABLE_READERS_EMPTY));

        if (currentConfiguration.availableProvers.isEmpty())
            throw new LauncherExecutionException(
                    String.format(MSG.LAUNCHER.INVOCATION_EXCEPTIONS.AVAILABLE_PROVERS_EMPTY));

        if (currentConfiguration.initialNodeSetBuilder == null)
            throw new LauncherExecutionException(
                    String.format(MSG.LAUNCHER.INVOCATION_EXCEPTIONS.INITIAL_NODE_SET_BUILDER_UNDEFINED));

        CmdLineOptions clo = new CmdLineOptions(currentConfiguration);
        currentConfiguration = clo.processComdLineOptions(args);

        processCmdLineOptionsExecuted = true;
        return currentConfiguration;
    }

    /* INNER CLASS DESCRIBING THE LAUNCHER CONFIGURATION */

    /*
     * Read the specified and returns the parsed formula.
     */
    private ProblemDescription readFromFile(ProofSearchData info, String inputFilename) {
        try {
            // get the file
            File inputFile = new File(inputFilename);
            if (!inputFile.exists()) {
                LOG.error(MSG.LAUNCHER.ERROR_MSG.NO_SUCH_FILE, inputFilename);
                System.exit(1);
            }
            // get the reader
            try {
                currentConfiguration.selectedReader = currentConfiguration.fileReader.getValue().newInstance();
                if (!currentConfiguration.testsetmode)
                    info_preReaderExecutionDetails();
                FileReader fir = new FileReader(inputFile);
                if (!currentConfiguration.testsetmode)
                    LOG.infoNoLn(MSG.LAUNCHER.INFO.PROBLEM_DESCRIPTION_PARSING_BEGIN);

                // configure problem reader if problem reader configurator is defined
                if (currentConfiguration.singleExecutionConfigurator != null)
                    currentConfiguration.singleExecutionConfigurator
                            .configProblemReader(currentConfiguration.selectedReader, currentConfiguration);

                // read problem description
                info.parsing_problem_start_time = getCurrentTimeMilleseconds();
                ProblemDescription problemDescription = currentConfiguration.selectedReader.read(fir);
                info.parsing_problem_end_time = getCurrentTimeMilleseconds();

                if (!currentConfiguration.testsetmode)
                    LOG.info(MSG.LAUNCHER.INFO.PROBLEM_DESCRIPTION_PARSING_END, info.getParsingProblemTime());
                problemDescription.setSource(inputFile.getAbsolutePath());

                problemDetails_print(problemDescription);
                return problemDescription;
                /*
                 * we already tested that a visible nullary constructor exists for this
                 * class when we added them to availableReaders
                 */
            } catch (InstantiationException e) {
            } catch (IllegalAccessException e) {
            }
        } catch (IOException e) {
            LOG.error(MSG.LAUNCHER.ERROR_MSG.IO_EXCEPTION, e.getMessage());
            System.exit(1);
        } catch (ProblemDescriptionException e) {
            LOG.error(MSG.LAUNCHER.ERROR_MSG.PROBLEM_WRONG_FORMAT, e.getMessage());
            System.exit(1);
        }
        return null;
    }

    private ProblemDescription readFromStandardInput(ProofSearchData proofSearchData) {
        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
        if (currentConfiguration.launcherStdInputMessage != null)
            LOG.info(currentConfiguration.launcherStdInputMessage);
        LOG.info(MSG.LAUNCHER.INFO.STDIN_INPUT_TYPE_A_FORMULA);
        try {
            String strFormula = in.readLine();
            currentConfiguration.selectedReader = currentConfiguration.stdinReader;
            LOG.infoNoLn(MSG.LAUNCHER.INFO.STDIN_INPUT_PARSING_PROBLEM_BEGIN,
                    currentConfiguration.selectedReader.getName());

            // configure problem reader if problem reader configurator is defined
            if (currentConfiguration.singleExecutionConfigurator != null)
                currentConfiguration.singleExecutionConfigurator
                        .configProblemReader(currentConfiguration.selectedReader, currentConfiguration);

            BufferedReader reader = new BufferedReader(new StringReader(strFormula));
            proofSearchData.parsing_problem_start_time = System.currentTimeMillis();
            ProblemDescription problemDescription = currentConfiguration.stdinReader.read(reader);
            proofSearchData.parsing_problem_end_time = System.currentTimeMillis();
            if (problemDescription.getProblemName() == null)
                problemDescription.setName("input");
            if (problemDescription.getSource() == null)
                problemDescription.setSource("std-input");
            if (problemDescription.getProblemStatus() == null)
                problemDescription.setProblemStatus(ProvabilityStatus.UNKNOWN);
            LOG.info(MSG.LAUNCHER.INFO.STDIN_INPUT_PARSING_PROBLEM_END, proofSearchData.getParsingProblemTime());

            problemDetails_print(problemDescription);
            return problemDescription;
        } catch (ProblemDescriptionException e) {
            LOG.error(MSG.LAUNCHER.ERROR_MSG.PARSER_EXCEPTION, e.getMessage());
            System.exit(1);
        } catch (IOException e) {
            LOG.error(MSG.LAUNCHER.ERROR_MSG.IO_EXCEPTION, e.getMessage());
            System.exit(1);
        }
        return null;
    }

    private void searchProof(ProofSearchData proofSearchData) {
        // BUILD THE ENGINE
        //currentConfiguration.engineExecutionMode = ExecutionMode.ENGINE_VERBOSE;
        Engine engine = new Engine(proofSearchData.selectedProver, proofSearchData.goal,
                currentConfiguration.engineExecutionMode);

        if (!currentConfiguration.testsetmode)
            LOG.info(MSG.LAUNCHER.INFO.PROVING_BEGIN);

        // start the proof search
        ThreadMXBean bean = ManagementFactory.getThreadMXBean();
        proofSearchData.execution_start_time = getCurrentTimeMilleseconds();
        long cpuTime = bean.getCurrentThreadCpuTime();
        engine.searchProof();
        // end of proof search, set info values
        cpuTime = bean.getCurrentThreadCpuTime() - cpuTime;
        proofSearchData.execution_end_time = getCurrentTimeMilleseconds();

        // set the data of the last proof search
        IterationInfo lastIterationInfo = engine.getLastIterationInfo();
        proofSearchData.proofSearchResult = engine.getResult();
        proofSearchData.testStatus = TestStatus.getTestStatus(proofSearchData);
        proofSearchData.iterationCounter = lastIterationInfo.getNumberOfIterations();
        proofSearchData.max_stack_size = lastIterationInfo.getMaxStackSize();
        proofSearchData.proofSearchResult = engine.getResult();
        proofSearchData.numberOfRestoredBacktrackPoints = lastIterationInfo.getNumberOfRestoredBacktrackPoints();
        proofSearchData.numberOfGeneratedNodes = lastIterationInfo.getNumberOfGeneratedNodes();
        proofSearchData.numberOfRestoredBranchPoints = lastIterationInfo.getNumberOfRestoredBranchPoints();

        // generates data and data files according with defined options 
        if (currentConfiguration.engineExecutionMode == ExecutionMode.ENGINE_TRACE)
            proofSearchData.trace = engine.getTrace();

        if (currentConfiguration.testsetmode)
            testset_printSingleTestInfo(proofSearchData);
        else {
            print_postProofSearchDetails(proofSearchData);

            if (currentConfiguration.generateLogFile)
                log_generateFile(proofSearchData);

            if (currentConfiguration.generateLogTimeFile)
                timeLog_generateFile(proofSearchData);

            if (currentConfiguration.generateLatexOfProof)
                latexProof_generateFile(proofSearchData);

            if (currentConfiguration.generateLatexOfCtrees)
                latexCtrees_generateFile(proofSearchData);

            if (currentConfiguration.saveTrace)
                trace_generateFile(proofSearchData);

            if (currentConfiguration.generatef3TimeStr)
                timing_f3time_generateString(proofSearchData);

            if (currentConfiguration.generateJTabWbTimeStr)
                timing_jtabwb_generatesString(proofSearchData);
        }

    }

    private void updateTestSetDetails(ProofSearchData proofSearchData) {

        // update testdetails
        testsetDetails.numberOfTests++;
        testsetDetails.totalProofSearchTime += proofSearchData.getExecutionTime();
        testsetDetails.totalProblemParsingTime += proofSearchData.getParsingProblemTime();
        testsetDetails.totalInitalNodeSetConstructionTime += proofSearchData.getIntialNodeSetConstructionTime();

        switch (proofSearchData.proofSearchResult) {
        case FAILURE:
            testsetDetails.unsuccesfulProofSearch++;
            break;
        case SUCCESS:
            testsetDetails.succesfullProofSearch++;
            break;
        default:
            throw new ImplementationError(MSG.IMPLEMENTATION_ERROR.CASE_NOT_IMPLEMENTED);
        }
        TestStatus testStatus = TestStatus.getTestStatus(proofSearchData);
        switch (testStatus) {
        case UNCHECKED:
            testsetDetails.uncheckedTests++;
            break;
        case PASSED:
            testsetDetails.successfulTests++;
            break;
        case FAILED:
            testsetDetails.failedTests++;
            break;
        default:
            throw new ImplementationError(MSG.IMPLEMENTATION_ERROR.CASE_NOT_IMPLEMENTED);
        }
        switch (proofSearchData.problemDescription.getProblemStatus()) {
        case PROVABLE:
            testsetDetails.provableProblems++;
            break;
        case UNKNOWN:
            testsetDetails.unknownProblems++;
            break;
        case UNPROVABLE:
            testsetDetails.unprovableProblems++;
            break;
        default:
            throw new ImplementationError(MSG.IMPLEMENTATION_ERROR.CASE_NOT_IMPLEMENTED);
        }
    }

    /**
     * Add the specified command options to the command line options for this
     * launcher. The names of added options must not overlap the names of the
     * launcher options otherwise a {@link LauncherOptionDefinitionException} is
     * thrown.
     * 
     * @param options the options to add
     * @throws LauncherOptionDefinitionException if one of the added options has a
     * name conflicting with one of the launcher options
     */
    public void optConfigCmdLineOptions(Options options) throws LauncherConfigurationException {
        for (Option opt : options.getOptions())
            currentConfiguration.cmdLineOptions.addOption(opt);

    }

    /**
     * If <code>flag</code> is true the launcher invoke the engine in trace
     * execution mode. Since trace execution mode is incompatible with verbose
     * execution mode if the current configuration is inconsistent an exception is
     * thrown.
     * 
     * @param flag if <code>true</code> the trace is generated
     * @throws LauncherConfigurationException if the resulting configuration is
     * inconsistent.
     * */
    public void setTraceGenerationMode(boolean flag) {
        if (flag)
            currentConfiguration.engineExecutionMode = ExecutionMode.ENGINE_TRACE;
        currentConfiguration.checkConfiguration();
    }

    /**
     * Defines the message the launcher prints before prover execution; in general
     * the message consists of the name and the version of the launcher.
     * 
     * @param str the welcome message.
     */
    public void optConfigWelcomeMessage(String str) {
        currentConfiguration.launcherWelcomeMessage = str;
    }

    /**
     * Defines the message the launcher prints before reading from standard input;
     * in general the message consists of a short description of the syntax of
     * input formulas.
     * 
     * @param str the welcome message.
     */
    public void optConfigInputSyntax(String str) {
        currentConfiguration.launcherStdInputMessage = str;
    }

    /**
     * Describes the status of a test.
     * 
     * @author Mauro Ferrari
     *
     */
    public static enum TestStatus {
        UNCHECKED, PASSED, FAILED;

        static TestStatus getTestStatus(ProofSearchData info) {
            ProvabilityStatus problemStatus = info.problemDescription.getProblemStatus();
            if (problemStatus == ProvabilityStatus.UNKNOWN)
                return UNCHECKED;
            if (problemStatus == info.selectedProver.statusFor(info.proofSearchResult))
                return PASSED;
            if (problemStatus != info.selectedProver.statusFor(info.proofSearchResult))
                return FAILED;
            throw new ImplementationError(MSG.IMPLEMENTATION_ERROR.CASE_NOT_IMPLEMENTED);
        }
    }

    private void info_preProverExecutionDetails() {
        LOG.info(MSG.LAUNCHER.PROOF_SEARCH_INFO.PROVER_DETAILS,
                currentConfiguration.selectedProverName.getDetailedName());
    }

    private void info_preReaderExecutionDetails() {
        if (currentConfiguration.readFromStandardInput)
            LOG.infoNoLn(MSG.LAUNCHER.PROOF_SEARCH_INFO.STDIN_READER_DETAILS,
                    currentConfiguration.stdinReader.getDescription());
        else
            LOG.info(MSG.LAUNCHER.PROOF_SEARCH_INFO.READER_DETAILS, currentConfiguration.selectedReader.getName());
    }

    private String info_getPostProofSearchDetails(ProofSearchData proofSearchData) {
        StringBuffer sb = new StringBuffer();

        sb.append(MSG.LAUNCHER.PROOF_SEARCH_INFO.INFO_SEPARATOR);
        sb.append("\n");
        sb.append(String.format(MSG.LAUNCHER.PROOF_SEARCH_INFO.PROVER_DETAILS,
                proofSearchData.selectedProver.getProverName().getDetailedName()));
        sb.append("\n");
        sb.append(String.format(MSG.LAUNCHER.PROOF_SEARCH_INFO.TEST_DETAILS,
                proofSearchData.problemDescription.getProblemName(),
                proofSearchData.problemDescription.getProblemStatus().name(), proofSearchData.proofSearchResult,
                TestStatus.getTestStatus(proofSearchData).name()));
        sb.append("\n");

        sb.append(String.format(MSG.LAUNCHER.PROOF_SEARCH_INFO.STAT_STRING, //
                proofSearchData.numberOfGeneratedNodes, //
                proofSearchData.numberOfRestoredBacktrackPoints, //
                proofSearchData.numberOfRestoredBranchPoints));
        sb.append("\n");

        long proofSearch_time = proofSearchData.getExecutionTime();
        long buildInitialNodeSet_time = proofSearchData.getIntialNodeSetConstructionTime();
        long problemReading_time = proofSearchData.getParsingProblemTime();
        long totalProof_time = buildInitialNodeSet_time + proofSearch_time + problemReading_time;
        sb.append(String.format(MSG.LAUNCHER.PROOF_SEARCH_INFO.TIMINGS_DETAILS, proofSearch_time,
                buildInitialNodeSet_time, problemReading_time));
        sb.append("\n");
        String convertedTime = buildTimeString(totalProof_time);
        if (convertedTime == null)
            sb.append(String.format(MSG.LAUNCHER.PROOF_SEARCH_INFO.TOTAL_TIME_1, totalProof_time));
        else
            sb.append(String.format(MSG.LAUNCHER.PROOF_SEARCH_INFO.TOTAL_TIME_2, totalProof_time,
                    convertedTime.toString()));
        sb.append("\n");

        sb.append(MSG.LAUNCHER.PROOF_SEARCH_INFO.INFO_SEPARATOR);
        return sb.toString();
    }

    private void print_postProofSearchDetails(ProofSearchData proofSearchData) {
        LOG.info(info_getPostProofSearchDetails(proofSearchData));
    }

    private void problemDetails_print(ProblemDescription problemDescription) {
        // build the initial node set
        if (currentConfiguration.testsetmode) {
            LOG.infoNoLn(String.format(MSG.LAUNCHER.PROOF_SEARCH_INFO.TESTSET_PROBLEM_INFO,
                    problemDescription.getProblemName(), problemDescription.getProblemStatus().toString()));
        } else {
            LOG.info(String.format(MSG.LAUNCHER.PROOF_SEARCH_INFO.PROBLEM_DETAILS,
                    problemDescription.getProblemName(), problemDescription.getProblemStatus().toString()));
        }

    }

    private String testset_buildLogFileSingleTestDescription(ProofSearchData proofSearchData) {
        long proofSearch_time = proofSearchData.getExecutionTime();
        long buildInitialNodeSet_time = proofSearchData.getIntialNodeSetConstructionTime();
        long problemReading_time = proofSearchData.getParsingProblemTime();
        long totalProof_time = buildInitialNodeSet_time + proofSearch_time;
        return String.format(MSG.LAUNCHER.TESTSET_INFO.TESTSET_LOGFILE_RESULT, //
                // TEST
                proofSearchData.problemDescription.getProblemName(), // problem name
                proofSearchData.problemDescription.getProblemStatus().name(), // problem status
                proofSearchData.proofSearchResult.name(), // proof search result
                proofSearchData.testStatus.name(), // test result
                // TIMES
                totalProof_time, // total proof-time
                proofSearch_time, // proof-search time,
                buildInitialNodeSet_time, // initial node set construction
                problemReading_time, // problem parsing time
                // DETAILS
                proofSearchData.iterationCounter, // iterations,
                proofSearchData.numberOfGeneratedNodes, // generated nodes,
                proofSearchData.max_stack_size, // max stack size,
                proofSearchData.numberOfRestoredBranchPoints, // visited branches
                proofSearchData.numberOfRestoredBacktrackPoints, // failed branches
                // PROBLEM SOURCE
                proofSearchData.problemDescription.getSource() // the source of the problem
        );
    }

    private void timing_f3time_generateString(ProofSearchData proofSearchData) {
        String result = null;
        switch (proofSearchData.selectedProver.statusFor(proofSearchData.proofSearchResult)) {
        case PROVABLE:
            result = "provable";
            break;
        case UNPROVABLE:
            result = "uprovable";
            break;
        case UNKNOWN:
            result = "unknown";
            break;
        default:
            throw new ImplementationError(MSG.IMPLEMENTATION_ERROR.CASE_NOT_IMPLEMENTED);

        }

        String str = buildF3TimeString(proofSearchData.getParsingProblemTime() + proofSearchData.getExecutionTime()
                + proofSearchData.getIntialNodeSetConstructionTime()) + "\n" + result;

        LOG.info(str);
    }

    private void timing_jtabwb_generatesString(ProofSearchData proofSearchData) {
        long proofSearch_time = proofSearchData.getExecutionTime();
        long buildInitialNodeSet_time = proofSearchData.getIntialNodeSetConstructionTime();
        long problemReading_time = proofSearchData.getParsingProblemTime();
        long totalProof_time = buildInitialNodeSet_time + proofSearch_time;

        //LOG.info(MSG.LAUNCHER.TIME_STR.JTABWB_DETAILS_STRING_LEGENDA);
        LOG.info(String.format(MSG.LAUNCHER.TIME_STR.JTABWB_DETAILS_STRING, //
                // TEST
                proofSearchData.problemDescription.getProblemName(), // problem name
                proofSearchData.problemDescription.getProblemStatus().name(), // problem status
                proofSearchData.proofSearchResult.name(), // proof search result
                proofSearchData.testStatus.name(), // test result
                // TIMES
                buildSecondBasedString(totalProof_time), // total proof-time
                buildSecondBasedString(proofSearch_time), // proof-search time,
                buildSecondBasedString(buildInitialNodeSet_time), // initial node set construction
                buildSecondBasedString(problemReading_time), // problem parsing time
                // DETAILS
                proofSearchData.numberOfGeneratedNodes, // generated nodes
                proofSearchData.numberOfRestoredBacktrackPoints, // restored backtrack points
                proofSearchData.numberOfRestoredBranchPoints // restored branch points
        ));
    }

    private String buildSecondBasedString(long miliSeconds) {
        int sec = (int) TimeUnit.MILLISECONDS.toSeconds(miliSeconds);
        int mil = (int) miliSeconds % 1000;

        return String.format(MSG.LAUNCHER.TIME_STR.JTABWB_TIME_STRING, sec, mil);
    }

    private String buildF3TimeString(long miliSeconds) {
        int sec = (int) TimeUnit.MILLISECONDS.toSeconds(miliSeconds);
        int mil = (int) miliSeconds % 1000;

        return String.format(MSG.LAUNCHER.TIME_STR.F3_TIME_STRING, sec, mil);
    }

    private long getCurrentTimeMilleseconds() {
        return TimeUnit.MILLISECONDS.convert(bean.getCurrentThreadCpuTime(), TimeUnit.NANOSECONDS);
    }

    private void latexCtrees_generateFile(ProofSearchData proofSearchData) {
        Collection<CTree> ctrees = CTree.buildFrom(proofSearchData.trace);
        if (ctrees == null) {
            LOG.error(MSG.LAUNCHER.ERROR_MSG.LATEX_CTREES_NO_CTREE_DEFINED);
            return;
        }
        try {
            File file = new File(fileNameFrom(proofSearchData.problemDescription.getProblemName(),
                    currentConfiguration.latexCtreesFileNamePrefix,
                    currentConfiguration.latexCtreesFileNameSuffix));
            PrintStream ps = new PrintStream(file);
            LOG.infoNoLn(MSG.LAUNCHER.INFO.LATEX_GENERATION_BEGIN);
            CTree.toLatex(ctrees, ps, ((_LatexSupport) proofSearchData.selectedProver).getLatexProofFormatter());
            LOG.info(MSG.LAUNCHER.INFO.LATEX_GENEATION_DONE, file.getAbsolutePath());
        } catch (IOException e) {
            LOG.error(String.format(MSG.LAUNCHER.ERROR_MSG.IO_EXCEPTION, e.getMessage()));
            System.exit(1);
        } catch (TraceException e) {
            LOG.error(String.format(MSG.LAUNCHER.ERROR_MSG.LATEX_GENERATION_EXCEPTION, e.getMessage()));
            System.exit(1);
        }
    }

    private void latexProof_generateFile(ProofSearchData proofSearchData) {
        if (proofSearchData.trace.getStatus() != ProofSearchResult.SUCCESS) {
            LOG.error(MSG.LAUNCHER.ERROR_MSG.LATEX_PROOF_NOT_A_PROOF_TRACE);
            return;
        }
        try {
            File file = new File(fileNameFrom(proofSearchData.problemDescription.getProblemName(),
                    currentConfiguration.latexProofFileNamePrefix, currentConfiguration.latexProofFileNameSuffix));
            PrintStream ps = new PrintStream(file);
            proofSearchData.trace.pruneSuccessful();
            Collection<CTree> ctrees = CTree.buildFrom(proofSearchData.trace);
            // LatexTranslator translator = new
            // LatexTranslator(proofSearchData.trace,
            // ((_LatexSupport) prover).getLatexProofFormatter());
            LOG.infoNoLn(MSG.LAUNCHER.INFO.LATEX_GENERATION_BEGIN);
            // translator.generateLatex(ps);
            CTree.toLatex(ctrees, ps, ((_LatexSupport) proofSearchData.selectedProver).getLatexProofFormatter());
            LOG.info(MSG.LAUNCHER.INFO.LATEX_GENEATION_DONE, file.getAbsolutePath());
        } catch (IOException e) {
            LOG.error(String.format(MSG.LAUNCHER.ERROR_MSG.IO_EXCEPTION, e.getMessage()));
            System.exit(1);
        } catch (TraceException e) {
            LOG.error(String.format(MSG.LAUNCHER.ERROR_MSG.LATEX_GENERATION_EXCEPTION, e.getMessage()));
            System.exit(1);
        }
    }

    private String testset_buildConciseTimingDescription(ProofSearchData proofSearchData) {
        long proofSearch_time = proofSearchData.getExecutionTime();
        long buildInitialNodeSet_time = proofSearchData.getIntialNodeSetConstructionTime();
        long problemReading_time = proofSearchData.getParsingProblemTime();
        long totalProof_time = buildInitialNodeSet_time + proofSearch_time;
        return String.format(MSG.LAUNCHER.TESTSET_INFO.SINGLE_OUTPUT_RESULT, //
                proofSearchData.proofSearchResult.name(), //
                proofSearchData.testStatus.name(), // test result
                proofSearchData.testStatus == TestStatus.FAILED ? "<<==================" : "",
                // 2nd LINE PROOF-SEARCH DETAILS
                proofSearchData.iterationCounter, // iterations,
                proofSearchData.max_stack_size, // max stack size,
                proofSearchData.numberOfGeneratedNodes, // generated nodes,
                proofSearchData.numberOfRestoredBranchPoints, // visited branches
                proofSearchData.numberOfRestoredBacktrackPoints, // failed branches
                // 3rd LINE TIMES
                buildSecondBasedString(totalProof_time + problemReading_time), // proof search time + initial node set construction
                buildSecondBasedString(proofSearch_time), // execution time,
                buildSecondBasedString(buildInitialNodeSet_time), // initial node set construction
                buildSecondBasedString(problemReading_time) // parsing problem time
        );
    }

    private void testset_printSingleTestInfo(ProofSearchData proofSearchData) {
        // print result on output
        LOG.info(testset_buildConciseTimingDescription(proofSearchData));

        // print result on tmp file 
        String s = testset_buildLogFileSingleTestDescription(proofSearchData);
        testsetDetails.pw4TempFile.println(s);
    }

    /**
     * Prints the report of a testset execution on the standard output and in the
     * testset logfile
     */
    private void testset_printReport() {
        // close the temp file
        testsetDetails.pw4TempFile.flush();
        testsetDetails.pw4TempFile.close();

        // build the log file name
        String logFileName = currentConfiguration.testsetFilePrefix
                + currentConfiguration.selectedProverName.getProperNoun() + "-" + currentConfiguration.testsetName
                + "-" + (new SimpleDateFormat("yyMMdd_HHmmss")).format(testsetDetails.startTime)
                + currentConfiguration.testsetFileSuffix;

        // create report file
        testsetDetails.logFile = new File(getLogDir(), logFileName);
        try {
            testsetDetails.pw4TestsetFile = new PrintWriter(
                    new BufferedWriter(new FileWriter(testsetDetails.logFile)));
        } catch (IOException e) {
            LOG.error(MSG.LAUNCHER.ERROR_MSG.TESTSET_FILE_CANNOT_BE_CREATED,
                    testsetDetails.logFile.getAbsolutePath(), e.getMessage());
            System.exit(1);
        }

        // WRITE PREAMBLE
        StringBuffer filePreamble = new StringBuffer();
        {
            filePreamble.append(String.format(MSG.LAUNCHER.TESTSET_INFO.TESTSET_LOGFILE_PROVER_NAME,
                    testsetDetails.proverName.getProperNoun(), testsetDetails.proverName.getVersion(),
                    testsetDetails.proverName.getVariant()));
            filePreamble.append("\n");
            filePreamble.append(String.format(MSG.LAUNCHER.TESTSET_INFO.TESTSET_LOGFILE_TESTSETNAME,
                    testsetDetails.testsetName));
        }

        StringBuffer detailsStr = new StringBuffer();
        {
            detailsStr.append(String.format(MSG.LAUNCHER.TESTSET_INFO.TESTSET_PROBLEMS,
                    testsetDetails.numberOfTests, testsetDetails.provableProblems,
                    testsetDetails.unprovableProblems, testsetDetails.unknownProblems));
            detailsStr.append("\n");
            detailsStr.append(String.format(MSG.LAUNCHER.TESTSET_INFO.TESTSET_TEST, testsetDetails.failedTests,
                    testsetDetails.successfulTests, testsetDetails.uncheckedTests));
            detailsStr.append("\n");

            detailsStr.append(String.format(MSG.LAUNCHER.TESTSET_INFO.TIMINGS_DETAILS,
                    buildSecondBasedString(testsetDetails.totalProofSearchTime), //
                    buildSecondBasedString(testsetDetails.totalInitalNodeSetConstructionTime), //
                    buildSecondBasedString(testsetDetails.totalProblemParsingTime)));
            detailsStr.append("\n");

            { // PROOF TIME STRING
                long totalProofTime = testsetDetails.totalInitalNodeSetConstructionTime
                        + testsetDetails.totalProofSearchTime;
                String convertedProofTime = buildTimeString(totalProofTime);
                String strTime = "";
                if (convertedProofTime == null)
                    strTime = String.format(MSG.LAUNCHER.TESTSET_INFO.TESTSET_PROOF_TIME_1,
                            buildSecondBasedString(totalProofTime));
                else
                    strTime = String.format(MSG.LAUNCHER.TESTSET_INFO.TESTSET_PROOF_TIME_2,
                            buildF3TimeString(totalProofTime), convertedProofTime);
                detailsStr.append(strTime);
                detailsStr.append("\n");
            }
            { // TOTAL TIME STRING
                long totaltime = testsetDetails.totalInitalNodeSetConstructionTime
                        + testsetDetails.totalProofSearchTime + testsetDetails.totalProblemParsingTime;
                String convertedTotalTime = buildTimeString(totaltime);
                String strTime = "";
                if (convertedTotalTime == null)
                    strTime = String.format(MSG.LAUNCHER.TESTSET_INFO.TESTSET_TOTAL_TIME_1,
                            buildSecondBasedString(totaltime));
                else
                    strTime = String.format(MSG.LAUNCHER.TESTSET_INFO.TESTSET_TOTAL_TIME_2,
                            buildF3TimeString(totaltime), convertedTotalTime);
                detailsStr.append(strTime);
            }
        }

        // WRITE FILE
        {
            testsetDetails.pw4TestsetFile.println(filePreamble.toString());
            testsetDetails.pw4TestsetFile.println(detailsStr.toString());
            StringBuffer toTest = new StringBuffer();
            toTest.append(MSG.LAUNCHER.TESTSET_INFO.TESTSET_LOGFILE_SEPARATOR);
            toTest.append("\n");
            toTest.append(MSG.LAUNCHER.TESTSET_INFO.PROBLEMS_PREAMBLE);
            toTest.append("\n");
            toTest.append(MSG.LAUNCHER.TESTSET_INFO.TESTSET_LOGFILE_ROW_SEPARATOR);
            testsetDetails.pw4TestsetFile.println(toTest.toString());
            // Copy from tmpfile
            try {
                BufferedReader br = new BufferedReader(new FileReader(testsetDetails.tempFile));
                String line;
                while ((line = br.readLine()) != null)
                    testsetDetails.pw4TestsetFile.println(line);
                br.close();
                testsetDetails.tempFile.delete();
            } catch (IOException e) {
                LOG.error(
                        String.format(MSG.LAUNCHER.TESTSET_INFO.TESTSET_LOGFILE_CANNOT_BE_OPENED, e.getMessage()));
                System.exit(1);
            }
        }
        testsetDetails.pw4TestsetFile.flush();
        testsetDetails.pw4TestsetFile.close();

        StringBuffer outPreamble = new StringBuffer();
        outPreamble.append(MSG.LAUNCHER.PROOF_SEARCH_INFO.INFO_SEPARATOR);
        outPreamble.append("\n");
        outPreamble.append(String.format(MSG.LAUNCHER.TESTSET_INFO.TESTSET_PROVER,
                testsetDetails.proverName.getDetailedName()));

        LOG.info(outPreamble.toString());
        LOG.info(detailsStr.toString());
        LOG.info(MSG.LAUNCHER.PROOF_SEARCH_INFO.INFO_SEPARATOR);
    }

    /*
     * Returns the string obtained replacing with spaces in name with underscore.
     */
    private String replaceSpacesWithUnderscore(String name) {
        return name.trim().replaceAll("\\s", "_");
    }

    /*
     * Returns the string obtained replacing with spaces in name with underscore.
     */
    private String fileNameFrom(String name, String prefix, String suffux) {
        return prefix + replaceSpacesWithUnderscore(name) + suffux;
    }

    private String buildTimeString(long miliSeconds) {
        int hrs = (int) TimeUnit.MILLISECONDS.toHours(miliSeconds);
        int min = (int) TimeUnit.MILLISECONDS.toMinutes(miliSeconds) % 60;
        int sec = (int) TimeUnit.MILLISECONDS.toSeconds(miliSeconds) % 60;
        int mil = (int) miliSeconds % 1000;

        if (hrs == 0 && min == 0 && sec == 0)
            return null;
        else
            return String.format("%02d:%02d:%02d + %d", hrs, min, sec, mil);
    }

    private File getLogDir() {
        File logDir = new File(currentConfiguration.logDirAbsolutePath);
        if (!logDir.exists()) {
            try {
                logDir.mkdir();
                return logDir;
            } catch (SecurityException e) {
                LOG.error(MSG.LAUNCHER.ERROR_MSG.LOG_DIR_CANNOT_BE_CREATED, logDir.getAbsolutePath(),
                        e.getMessage());
                return null;
            }
        } else {
            if (!logDir.isDirectory()) {
                LOG.error(MSG.LAUNCHER.ERROR_MSG.LOG_DIR_IS_NOT_A_DIR, logDir.getAbsolutePath());
                return null;
            }
        }
        return logDir;
    }

    /**
     * Save information on prover execution in the log file.
     * 
     * @param executionInfo execution info
     */
    private void log_generateFile(ProofSearchData proofSearchData) {
        String executionInfo = info_getPostProofSearchDetails(proofSearchData);
        File logDir = getLogDir();

        if (logDir == null) {
            LOG.error(MSG.LAUNCHER.ERROR_MSG.LOG_FILE_CANNOT_BE_GENERATED);
            return;
        }
        File file = new File(logDir, fileNameFrom(proofSearchData.problemDescription.getProblemName(),
                currentConfiguration.logFileNamePrefix, currentConfiguration.logFileNameSuffix));
        LOG.writeToFile(file, executionInfo);
        LOG.info(MSG.LAUNCHER.INFO.LOG_FILE_GENERATED, file.getAbsolutePath());
    }

    /**
     * Save information on prover execution in the log file.
     * 
     * @param executionInfo execution info
     */
    private void timeLog_generateFile(ProofSearchData proofSearchData) {
        //File file = new File(currentConfiguration.logTimeFileName);
        File file = new File(fileNameFrom(proofSearchData.problemDescription.getProblemName(),
                currentConfiguration.logTimeFileNamePrefix, currentConfiguration.logTimeFileNameSuffix));
        LOG.writeToFile(file, testset_buildLogFileSingleTestDescription(proofSearchData));
        LOG.info(MSG.LAUNCHER.INFO.LOG_TIME_FILE_GENERATED, file.getAbsolutePath());
    }

    private void trace_generateFile(ProofSearchData info) {
        LOG.infoNoLn(MSG.LAUNCHER.INFO.TRACE_GENERATION_BEGIN);
        try {
            PrintStream out;
            File file = new File(fileNameFrom(info.problemDescription.getProblemName(),
                    currentConfiguration.traceFileNamePrefix, currentConfiguration.traceFileNameSuffix));
            out = new PrintStream(file);
            info.trace.print(out);
            if (file != null)
                LOG.info(MSG.LAUNCHER.INFO.TRACE_GENERATION_END, file.getAbsolutePath());
        } catch (IOException e) {
            LOG.error(String.format(MSG.LAUNCHER.ERROR_MSG.IO_EXCEPTION, e.getMessage()));
            System.exit(1);
        }
    }

    static class TestsetDetails {

        ProverName proverName;
        File tempFile = null;
        File logFile = null;
        PrintWriter pw4TempFile = null;
        PrintWriter pw4TestsetFile = null;
        String testsetName = null;
        Date startTime = null;
        int numberOfTests = 0;
        int provableProblems = 0;
        int unprovableProblems = 0;
        int unknownProblems = 0;
        int succesfullProofSearch = 0;
        int unsuccesfulProofSearch = 0;
        int successfulTests = 0;
        int failedTests = 0;
        int uncheckedTests = 0;
        long totalProofSearchTime = 0;
        long totalProblemParsingTime = 0;
        long totalInitalNodeSetConstructionTime = 0;
    }

    /**
     * An object of this class describes the current configuration of the
     * launcher.
     * 
     * @author Mauro Ferrari
     * 
     */
    public static class LaunchConfiguration {

        AvailableProvers availableProvers = new AvailableProvers();
        AvailableReaders availableReaders = new AvailableReaders();
        boolean generatef3TimeStr = false;
        boolean generateJTabWbTimeStr = false;
        boolean generateLatexOfProof = false;
        boolean generateLatexOfCtrees = false;
        boolean generateLogFile = false;
        boolean generateLogTimeFile = false;;
        boolean readFromStandardInput = false;
        //boolean traceExecutionMode = false;
        boolean saveTrace = false;
        boolean verboseExecutionMode = false;
        boolean testsetmode = false;
        CommandLine commandLine;
        _ProblemReader stdinReader = null;
        ConfiguredProblemDescriptioReader fileReader;
        _InitialGoalBuilder initialNodeSetBuilder = null;
        _ProblemReader selectedReader = null;
        _SingleExecutionConfigurator singleExecutionConfigurator;
        ConfiguredTheoremProver selectedProver = null;
        ProverName selectedProverName = null;
        ExecutionMode engineExecutionMode = ExecutionMode.ENGINE_PLAIN;
        String logDirAbsolutePath = DEFAULT_LOG_DIR_NAME;
        String latexCtreesFileNamePrefix = Launcher.DEFAULT_LATEX_CTREE_FILE_NAME_PREFIX;
        String latexCtreesFileNameSuffix = Launcher.DEFAULT_LATEX_CTREE_FILE_NAME_SUFFIX;
        String latexProofFileNamePrefix = Launcher.DEFAULT_LATEX_PROOF_FILE_NAME_PREFIX;
        String latexProofFileNameSuffix = Launcher.DEFAULT_LATEX_PROOF_FILE_NAME_SUFFIX;
        String launcherWelcomeMessage = null;
        String launcherStdInputMessage = null;
        String launcherClassName = null;
        String logFileNamePrefix = Launcher.DEFAULT_LOG_FILE_NAME_PREFIX;
        String logFileNameSuffix = Launcher.DEFAULT_LOG_FILE_NAME_SUFFIX;
        String logTimeFileNamePrefix = Launcher.DEFAULT_LOG_TIME_FILE_NAME_PREFIX;
        String logTimeFileNameSuffix = Launcher.DEFAULT_LOG_TIME_FILE_NAME_SUFFIX;
        String testsetName = null;
        String testsetFilePrefix = Launcher.DEFAULT_TESTSET_FILE_PREFIX;
        String testsetFileSuffix = Launcher.DEFAULT_TESTSET_FILE_SUFFIX;
        String traceFileNamePrefix = Launcher.DEFAULT_TRACE_FILE_NAME_PREFIX;
        String traceFileNameSuffix = Launcher.DEFAULT_TRACE_FILE_NAME_SUFFIX;
        Options cmdLineOptions = new Options();

        /**
         * Returns true if trace execution mode is set.
         * 
         * @return the traceExecutionMode
         */
        public boolean isTraceExecutionMode() {
            return this.engineExecutionMode == ExecutionMode.ENGINE_TRACE;
        }

        /**
         * Returns the list of atomic options and arguments parsed according to the
         * specified options.
         * 
         * @return the list of atomic options and arguments
         */
        public CommandLine getCommandLine() {
            return this.commandLine;
        }

        /**
         * @return the selectedReader
         */
        public _ProblemReader getSelectedReader() {
            return this.selectedReader;
        }

        /**
         * @return the selectedProver
         */
        public ConfiguredTheoremProver getSelectedProver() {
            return this.selectedProver;
        }

        public void checkConfiguration() {
            if (verboseExecutionMode && this.engineExecutionMode == ExecutionMode.ENGINE_TRACE)
                throw new LauncherConfigurationException(
                        String.format(MSG.LAUNCHER.CONFIGURATION_EXCEPTIONS.INCONSISTENT_CONFIGURATION,
                                "verboseExecution", "generateTrace"));
        }

    }

}