#!/usr/bin/env python
"""
Runs the QIN pipeline.
"""

import sys
import os
import shutil
import imp
import argparse
from qipipe.helpers import command

NIPYPE_LOG_DIR_ENV_VAR = 'NIPYPE_LOG_DIR'
"""The environment variable used by Nipype to set the log directory."""


def main(argv=sys.argv):
    # Parse the command line arguments.
    inputs, opts = _parse_arguments()
    # Break out the logging options.
    log_opts = {k: opts.pop(k) for k in ['log', 'log_level'] if k in opts}
    # Configure the logger.
    command.configure_log(**log_opts)
    # The log file option.
    log_file_opt = opts.get('log')
    # Set the Nipype log directory environment variable before importing
    # any nipype module. The code below works around the following Nipype
    # bug:
    # * Nipype requires a log directory. If the Nipype log directory is
    #   set to /dev/null, then Nipype raises an error. The work-around
    #   is to set the NIPYPE_LOG_DIR environment variable to a new temp
    #   directory.
    #
    # The temp log directory that stands in for a /dev/null log file
    # option.
    temp_log_dir = None
    if log_file_opt:
        log_file = os.path.abspath(log_file_opt)
        if log_file == '/dev/null':
            # Work around the Nipype bug described above.
            temp_log_dir = log_dir = tempfile.mkdtemp(prefix='qipipe_')
        else:
            log_dir = os.path.dirname(log_file)
        # Make the log file parent directory, if necessary.
        if not os.path.exists(log_dir):
            os.makedirs(log_dir)
        # Set the Nipype log directory environment variable.
        os.environ[NIPYPE_LOG_DIR_ENV_VAR] = log_dir

    # Import the qipipe pipeline module after configuring the logger
    # above, since importing any nipype module writes to the log.
    from qipipe.pipeline import qipipeline as qip

    # Run the QIN workflow.
    try:
        qip.run(*inputs, **opts)
    finally:
        # Clean up.
        if temp_log_dir:
            shutil.rmtree(temp_log_dir)

    return 0


def _parse_arguments():
    """
    Parses the command line arguments.

    :return: the (inputs, options) tuple, where inputs is the non-option
        arguments and options is an {option: value} dictionary
    """
    parser = argparse.ArgumentParser()

    # The general options.
    command.add_options(parser)

    # The actions.
    parser.add_argument('--stage', dest='actions', action='append_const',
                        const='stage', help='stage the input DICOM files')
    parser.add_argument('--roi', dest='actions', action='append_const',
                        const='roi', help='generate the ROI mask files')
    parser.add_argument('--register', dest='actions', action='append_const',
                        const='register', help='register the scans')
    parser.add_argument('--model', dest='actions', action='append_const',
                        const='model', help='model the realigned images')

    # Prepare but don't run the pipeline.
    parser.add_argument('--dry-run', action='store_true',
                        help='prepare but do not run the pipeline')

    # The staging options.
    parser.add_argument('-p', '--project',
                        help='the QIN project name, required for staging')
    parser.add_argument('-c', '--collection',
                        help='the collection to stage, required for staging')
    parser.add_argument('--scan', help='the optional staging scan number',
                        type=int, metavar='SCAN')
    parser.add_argument('--resume', action='store_true',
                        help='resume staging on existing sessions'
                             ' (default False)')

    # The output and work options.
    parser.add_argument('-o', '--output',
                        help='the destination directory'
                             ' (default current directory)',
                        metavar='DIR', dest='dest')
    parser.add_argument('-w', '--work',
                        help='the work directory'
                             ' (default a new temp directory)',
                        metavar='DIR', dest='base_dir')

    # The registration options.
    parser.add_argument('--registration-resource',
                        help='the XNAT registration resource label',
                        metavar='RESOURCE')
    parser.add_argument('--registration-technique',
                        help="the XNAT registration technique"
                             " (default ants)",
                        metavar='TECHNIQUE')
    parser.add_argument('--recursive-registration',
                        help="perform step-wise iterative"
                             " recursive registration",
                        action='store_true')

    # The modeling options.
    parser.add_argument('--modeling-resource',
                        help='the XNAT modeling resource name',
                        metavar='RESOURCE')
    parser.add_argument('--modeling-technique',
                        help='the XNAT modeling technique',
                        metavar='TECHNIQUE')

    # The application extention option.
    parser.add_argument('--shim', help='the application extension',
                        metavar='MODULE')

    # The input directories or XNAT labels to process.
    parser.add_argument('input', nargs='+',
                        help='the input subject directory or XNAT object path'
                             ' to process')

    args = vars(parser.parse_args())
    nonempty_args = dict((k, v) for k, v in args.iteritems() if v != None)

    return nonempty_args.pop('input'), nonempty_args


if __name__ == '__main__':
    sys.exit(main())
