The main function.

    These are the steps performed for the data clean up:

    1. Prints the version number.
    2. Reads the configuration file (:py:func:`read_config_file`).
    3. Creates a new directory with ``data_clean_up`` as prefix and the date
       and time as suffix.
    4. Check the input file type (``bfile``, ``tfile`` or ``file``).
    5. Creates an intermediate directory with the section as prefix and the
       script name as suffix (inside the previous directory).
    6. Runs the required script in order (according to the configuration file
       section).

    .. note::
        The main function is not responsible to check if the required files
        exist. This should be done in the ``run`` functions.

def main():
    """The main function.

    These are the steps performed for the data clean up:

    1. Prints the version number.
    2. Reads the configuration file (:py:func:`read_config_file`).
    3. Creates a new directory with ``data_clean_up`` as prefix and the date
       and time as suffix.
    4. Check the input file type (``bfile``, ``tfile`` or ``file``).
    5. Creates an intermediate directory with the section as prefix and the
       script name as suffix (inside the previous directory).
    6. Runs the required script in order (according to the configuration file
       section).

    .. note::
        The main function is not responsible to check if the required files
        exist. This should be done in the ``run`` functions.

    """
    # Getting and checking the options
    args = parse_args()
    check_args(args)

    # The directory name
    dirname = "data_clean_up."
    dirname += datetime.datetime.today().strftime("%Y-%m-%d_%H.%M.%S")
    while os.path.isdir(dirname):
        time.sleep(1)
        dirname = "data_clean_up."
        dirname += datetime.datetime.today().strftime("%Y-%m-%d_%H.%M.%S")

    # Creating the output directory
    os.mkdir(dirname)

    # Configuring the root logger
    add_file_handler_to_root(os.path.join(dirname, "pyGenClean.log"))

    logger.info("pyGenClean version {}".format(__version__))
    plink_version = get_plink_version()
    logger.info("Using Plink version {}".format(plink_version))

    # Reading the configuration file
    logger.info("Reading configuration file [ {} ]".format(args.conf))
    order, conf = read_config_file(args.conf)

    # Executing the data clean up
    current_in = None
    current_in_type = None
    suffixes = None
    if args.tfile is not None:
        current_in = args.tfile
        current_in_type = "tfile"
        suffixes = (".tped", ".tfam")
    elif args.bfile is not None:
        current_in = args.bfile
        current_in_type = "bfile"
        suffixes = (".bed", ".bim", ".fam")
    else:
        current_in = args.file
        current_in_type = "file"
        suffixes = (".ped", ".map")

    # Creating the excluded files
    try:
        with open(os.path.join(dirname, "excluded_markers.txt"), "w") as o_f:
            pass
        with open(os.path.join(dirname, "excluded_samples.txt"), "w") as o_f:
            pass
        with open(os.path.join(dirname, "initial_files.txt"), "w") as o_file:
            for s in suffixes:
                print >>o_file, current_in + s

    except IOError:
        msg = "{}: cannot write summary".format(dirname)
        raise ProgramError(msg)

    # Counting the number of markers and samples in the datafile
    logger.info("Counting initial number of samples and markers")
    nb_markers, nb_samples = count_markers_samples(current_in,
                                                   current_in_type)
    logger.info("  - {:,d} samples".format(nb_samples))
    logger.info("  - {:,d} markers".format(nb_markers))

    # Creating the result summary file containing the initial numbers
    try:
        with open(os.path.join(dirname, "results_summary.txt"), "w") as o_file:
            print >>o_file, "# initial"
            print >>o_file, ("Initial number of markers\t"
                             "{:,d}".format(nb_markers))
            print >>o_file, ("Initial number of samples\t"
                             "{:,d}".format(nb_samples))
            print >>o_file, "---"
    except IOError:
        msg = "{}: cannot write summary".format(dirname)
        raise ProgramError(msg)

    latex_summaries = []
    steps = []
    descriptions = []
    long_descriptions = []
    graphic_paths = set()
    for number in order:
        # Getting the script name and its options
        script_name, options = conf[number]

        # Getting the output prefix
        output_prefix = os.path.join(dirname,
                                     "{}_{}".format(number, script_name))

        # Getting the function to use
        function_to_use = available_functions[script_name]

        # Executing the function
        logger.info("Running {} {}".format(number, script_name))
        logger.info("  - Using {} as prefix for input "
                    "files".format(current_in))
        logger.info("  - Results will be in [ {} ]".format(output_prefix))

        # Executing the function
        step_results = function_to_use(
            in_prefix=current_in,
            in_type=current_in_type,
            out_prefix=output_prefix,
            base_dir=dirname,
            options=options,
        )

        # Updating the input files and input file types
        current_in = step_results.next_file
        current_in_type = step_results.next_file_type

        # Saving what's necessary for the LaTeX report
        latex_summaries.append(step_results.latex_summary)
        steps.append(script_name)
        descriptions.append(step_results.description)
        long_descriptions.append(step_results.long_description)
        if step_results.graph_path is not None:
            graphic_paths.update(step_results.graph_path)

    # Counting the final number of samples and markers
    logger.info("Counting final number of samples and markers")
    nb_markers, nb_samples = count_markers_samples(current_in,
                                                   current_in_type)
    logger.info("  - {:,d} samples".format(nb_samples))
    logger.info("  - {:,d} markers".format(nb_markers))

    # Getting the final suffixes
    suffixes = None
    if current_in_type == "tfile":
        suffixes = ((".tped", nb_markers), (".tfam", nb_samples))
    elif current_in_type == "bfile":
        suffixes = ((".bed", None), (".bim", nb_markers), (".fam", nb_samples))
    else:
        suffixes = ((".ped", nb_samples), (".map", nb_markers))

    with open(os.path.join(dirname, "final_files.txt"), "w") as o_file:
        for s, nb in suffixes:
            if nb:
                print >>o_file, current_in + s + "\t{:,d}".format(nb)
            else:
                print >>o_file, current_in + s

    # Generating the graphics paths file
    graphic_paths_fn = None
    if len(graphic_paths) > 0:
        try:
            graphic_paths_fn = os.path.join(dirname, "graphic_paths.txt")
            with open(graphic_paths_fn, "w") as o_file:
                for path in sorted(graphic_paths):
                    print >>o_file, path
        except IOError:
            msg = "{}: cannot write summary".format(dirname)
            raise ProgramError(msg)

    # We create the automatic report
    logger.info("Generating automatic report")
    report_name = os.path.join(dirname, "automatic_report.tex")
    auto_report.create_report(
        dirname,
        report_name,
        project_name=args.report_number,
        steps=steps,
        descriptions=descriptions,
        graphic_paths_fn=graphic_paths_fn,
        long_descriptions=long_descriptions,
        summaries=latex_summaries,
        background=args.report_background,
        summary_fn=os.path.join(dirname, "results_summary.txt"),
        report_title=args.report_title,
        report_author=args.report_author,
        initial_files=os.path.join(dirname, "initial_files.txt"),
        final_files=os.path.join(dirname, "final_files.txt"),
        final_nb_markers="{:,d}".format(nb_markers),
        final_nb_samples="{:,d}".format(nb_samples),
        plink_version=plink_version,
    )