from ....pipeline import engine as pe
from ....interfaces import freesurfer as fs
from ....interfaces import utility as niu
from .autorecon1 import create_AutoRecon1
from .autorecon2 import create_AutoRecon2
from .autorecon3 import create_AutoRecon3
from ....interfaces.freesurfer import AddXFormToHeader, Info
from ....interfaces.io import DataSink
from .utils import getdefaultconfig
from ....pipeline.engine.base import logger

def create_skullstripped_recon_flow(name="skullstripped_recon_all"):
    """Performs recon-all on voulmes that are already skull stripped.
    FreeSurfer failes to perform skullstrippig on some volumes (especially
    MP2RAGE). This can be avoided by doing skullstripping before runnig recon-all
    (using for example SPECTRE algorithm)

    Example
    -------
    >>> from nipype.workflows.smri.freesurfer import create_skullstripped_recon_flow
    >>> recon_flow = create_skullstripped_recon_flow()
    >>> recon_flow.inputs.inputspec.subject_id = 'subj1'
    >>> recon_flow.inputs.inputspec.T1_files = 'T1.nii.gz'
    >>> recon_flow.run()  # doctest: +SKIP


    Inputs::
           inputspec.T1_files : skullstripped T1_files (mandatory)
           inputspec.subject_id : freesurfer subject id (optional)
           inputspec.subjects_dir : freesurfer subjects directory (optional)

    Outputs::

           outputspec.subject_id : freesurfer subject id
           outputspec.subjects_dir : freesurfer subjects directory
    """
    wf = pe.Workflow(name=name)

    inputnode = pe.Node(niu.IdentityInterface(fields=['subject_id',
                                                      'subjects_dir',
                                                      'T1_files']),
                        name='inputspec')

    autorecon1 = pe.Node(fs.ReconAll(), name="autorecon1")
    autorecon1.plugin_args = {'submit_specs': 'request_memory = 2500'}
    autorecon1.inputs.directive = "autorecon1"
    autorecon1.inputs.args = "-noskullstrip"
    autorecon1._interface._can_resume = False

    wf.connect(inputnode, "T1_files", autorecon1, "T1_files")
    wf.connect(inputnode, "subjects_dir", autorecon1, "subjects_dir")
    wf.connect(inputnode, "subject_id", autorecon1, "subject_id")

    def link_masks(subjects_dir, subject_id):
        import os
        os.symlink(os.path.join(subjects_dir, subject_id, "mri", "T1.mgz"),
                   os.path.join(subjects_dir, subject_id, "mri", "brainmask.auto.mgz"))
        os.symlink(os.path.join(subjects_dir, subject_id, "mri", "brainmask.auto.mgz"),
                   os.path.join(subjects_dir, subject_id, "mri", "brainmask.mgz"))
        return subjects_dir, subject_id

    masks = pe.Node(niu.Function(input_names=['subjects_dir', 'subject_id'],
                                 output_names=['subjects_dir', 'subject_id'],
                                 function=link_masks), name="link_masks")

    wf.connect(autorecon1, "subjects_dir", masks, "subjects_dir")
    wf.connect(autorecon1, "subject_id", masks, "subject_id")

    autorecon_resume = pe.Node(fs.ReconAll(), name="autorecon_resume")
    autorecon_resume.plugin_args = {'submit_specs': 'request_memory = 2500'}
    autorecon_resume.inputs.args = "-no-isrunning"
    wf.connect(masks, "subjects_dir", autorecon_resume, "subjects_dir")
    wf.connect(masks, "subject_id", autorecon_resume, "subject_id")

    outputnode = pe.Node(niu.IdentityInterface(fields=['subject_id',
                                                       'subjects_dir']),
                         name='outputspec')

    wf.connect(autorecon_resume, "subjects_dir", outputnode, "subjects_dir")
    wf.connect(autorecon_resume, "subject_id", outputnode, "subject_id")
    return wf

def create_reconall_workflow(name="ReconAll", plugin_args=None):
    """Creates the ReconAll workflow in Nipype. This workflow is designed to
    run the same commands as FreeSurfer's reconall script but with the added
    features that a Nipype workflow provides. Before running this workflow, it
    is necessary to have the FREESURFER_HOME environmental variable set to the
    directory containing the version of FreeSurfer to be used in this workflow.

    Example
    -------
    >>> from nipype.workflows.smri.freesurfer import create_reconall_workflow
    >>> recon_all = create_reconall_workflow()
    >>> recon_all.inputs.inputspec.subject_id = 'subj1'
    >>> recon_all.inputs.inputspec.subjects_dir = '.'
    >>> recon_all.inputs.inputspec.T1_files = 'T1.nii.gz'
    >>> recon_flow.run()  # doctest: +SKIP


    Inputs::
           inputspec.subjects_dir : subjects directory (mandatory)
           inputspec.subject_id : name of subject (mandatory)
           inputspec.T1_files : T1 files (mandatory)
           inputspec.T2_file : T2 file (optional)
           inputspec.FLAIR_file : FLAIR file (optional)
           inputspec.cw256 : Conform inputs to 256 FOV (optional)
           inputspec.num_threads: Number of threads on nodes that utilize OpenMP (default=1)
           plugin_args : Dictionary of plugin args to set to nodes that utilize OpenMP (optional)
    Outpus::
           postdatasink_outputspec.subject_id : name of the datasinked output folder in the subjects directory

    Note:
    The input subject_id is not passed to the commands in the workflow. Commands
    that require subject_id are reading implicit inputs from
    {SUBJECTS_DIR}/{subject_id}. For those commands the subject_id is set to the
    default value and SUBJECTS_DIR is set to the node directory. The implicit
    inputs are then copied to the node directory in order to mimic a SUBJECTS_DIR
    structure. For example, if the command implicitly reads in brainmask.mgz, the
    interface would copy that input file to
    {node_dir}/{subject_id}/mri/brainmask.mgz and set SUBJECTS_DIR to node_dir.
    The workflow only uses the input subject_id to datasink the outputs to
    {subjects_dir}/{subject_id}.
    """
    reconall = pe.Workflow(name=name)

    inputspec = pe.Node(niu.IdentityInterface(fields=['subject_id',
                                                      'subjects_dir',
                                                      'T1_files',
                                                      'T2_file',
                                                      'FLAIR_file',
                                                      'num_threads',
                                                      'cw256',
                                                      'reg_template',
                                                      'reg_template_withskull',
                                                      'lh_atlas',
                                                      'rh_atlas',
                                                      'lh_classifier1',
                                                      'rh_classifier1',
                                                      'lh_classifier2',
                                                      'rh_classifier2',
                                                      'lh_classifier3',
                                                      'rh_classifier3',
                                                      'lookup_table',
                                                      'wm_lookup_table',
                                                      'src_subject_id',
                                                      'src_subject_dir',
                                                      'color_table',
                                                      'awk_file']),
                        run_without_submitting=True,
                        name='inputspec')

    # check freesurfer version and set parameters
    fs_version_full = Info.version()
    if fs_version_full and ('v6.0' in fs_version_full or
                                    'dev' in fs_version_full):
        # assuming that dev is 6.0
        fsvernum = 6.0
        fs_version = 'v6.0'
        th3 = True
        shrink = 2
        distance = 200 # 3T should be 50
        stop = 0.0001
        exvivo = True
        entorhinal = True
        rb_date = "2014-08-21"
    else:
        # 5.3 is default
        fsvernum = 5.3
        if fs_version_full:
            if 'v5.3' in fs_version_full:
                fs_version = 'v5.3'
            else:
                fs_version = fs_version_full.split('-')[-1]
                logger.info(("Warning: Workflow may not work properly if "
                             "FREESURFER_HOME environmental variable is not "
                             "set or if you are using an older version of "
                             "FreeSurfer"))
        else:
            fs_version = 5.3 # assume version 5.3
        th3 = False
        shrink = None
        distance = 50
        stop = None
        exvivo = False
        entorhinal = False
        rb_date = "2008-03-26"

    logger.info("FreeSurfer Version: {0}".format(fs_version))

    def setconfig(reg_template=None,
                  reg_template_withskull=None,
                  lh_atlas=None,
                  rh_atlas=None,
                  lh_classifier1=None,
                  rh_classifier1=None,
                  lh_classifier2=None,
                  rh_classifier2=None,
                  lh_classifier3=None,
                  rh_classifier3=None,
                  src_subject_id=None,
                  src_subject_dir=None,
                  color_table=None,
                  lookup_table=None,
                  wm_lookup_table=None,
                  awk_file=None,
                  rb_date=None):
        """Set optional configurations to the default"""
        from nipype.workflows.smri.freesurfer.utils import getdefaultconfig
        def checkarg(arg, default):
            """Returns the value if defined; otherwise default"""
            if arg:
                return arg
            else:
                return default
        defaultconfig = getdefaultconfig(exitonfail=True, rb_date=rb_date)
        # set the default template and classifier files
        reg_template = checkarg(reg_template, defaultconfig['registration_template'])
        reg_template_withskull = checkarg(reg_template_withskull,
                                          defaultconfig['registration_template_withskull'])
        lh_atlas = checkarg(lh_atlas, defaultconfig['lh_atlas'])
        rh_atlas = checkarg(rh_atlas, defaultconfig['rh_atlas'])
        lh_classifier1 = checkarg(lh_classifier1, defaultconfig['lh_classifier'])
        rh_classifier1 = checkarg(rh_classifier1, defaultconfig['rh_classifier'])
        lh_classifier2 = checkarg(lh_classifier2, defaultconfig['lh_classifier2'])
        rh_classifier2 = checkarg(rh_classifier2, defaultconfig['rh_classifier2'])
        lh_classifier3 = checkarg(lh_classifier3, defaultconfig['lh_classifier3'])
        rh_classifier3 = checkarg(rh_classifier3, defaultconfig['rh_classifier3'])
        src_subject_id = checkarg(src_subject_id, defaultconfig['src_subject_id'])
        src_subject_dir = checkarg(src_subject_dir, defaultconfig['src_subject_dir'])
        color_table = checkarg(color_table, defaultconfig['AvgColorTable'])
        lookup_table = checkarg(lookup_table, defaultconfig['LookUpTable'])
        wm_lookup_table = checkarg(wm_lookup_table, defaultconfig['WMLookUpTable'])
        awk_file = checkarg(awk_file, defaultconfig['awk_file'])
        return reg_template, reg_template_withskull, lh_atlas, rh_atlas, \
            lh_classifier1, rh_classifier1, lh_classifier2, rh_classifier2, \
            lh_classifier3, rh_classifier3, src_subject_id, src_subject_dir, \
            color_table, lookup_table, wm_lookup_table, awk_file

    # list of params to check
    params = ['reg_template',
              'reg_template_withskull',
              'lh_atlas',
              'rh_atlas',
              'lh_classifier1',
              'rh_classifier1',
              'lh_classifier2',
              'rh_classifier2',
              'lh_classifier3',
              'rh_classifier3',
              'src_subject_id',
              'src_subject_dir',
              'color_table',
              'lookup_table',
              'wm_lookup_table',
              'awk_file']

    config_node = pe.Node(niu.Function(params + ['rb_date'],
                                       params,
                                       setconfig),
                          name="config")

    config_node.inputs.rb_date = rb_date

    for param in params:
        reconall.connect(inputspec, param, config_node, param)

    # create AutoRecon1
    ar1_wf, ar1_outputs = create_AutoRecon1(plugin_args=plugin_args, stop=stop,
                                            distance=distance, shrink=shrink,
                                            fsvernum=fsvernum)
    # connect inputs for AutoRecon1
    reconall.connect([(inputspec, ar1_wf, [('T1_files', 'inputspec.T1_files'),
                                           ('T2_file', 'inputspec.T2_file'),
                                           ('FLAIR_file', 'inputspec.FLAIR_file'),
                                           ('num_threads', 'inputspec.num_threads'),
                                           ('cw256', 'inputspec.cw256')]),
                      (config_node, ar1_wf, [('reg_template_withskull',
                                              'inputspec.reg_template_withskull'),
                                             ('awk_file', 'inputspec.awk_file')])])
    # create AutoRecon2
    ar2_wf, ar2_outputs = create_AutoRecon2(plugin_args=plugin_args, fsvernum=fsvernum,
                                            stop=stop, shrink=shrink, distance=distance)
    # connect inputs for AutoRecon2
    reconall.connect([(inputspec, ar2_wf, [('num_threads', 'inputspec.num_threads')]),
                      (config_node, ar2_wf, [('reg_template_withskull',
                                              'inputspec.reg_template_withskull'),
                                             ('reg_template', 'inputspec.reg_template')]),
                      (ar1_wf, ar2_wf, [('outputspec.brainmask', 'inputspec.brainmask'),
                                        ('outputspec.talairach', 'inputspec.transform'),
                                        ('outputspec.orig', 'inputspec.orig')])])

    if fsvernum < 6:
        reconall.connect([(ar1_wf, ar2_wf, [('outputspec.nu', 'inputspec.nu')])])

    # create AutoRecon3
    ar3_wf, ar3_outputs = create_AutoRecon3(plugin_args=plugin_args, th3=th3,
                                            exvivo=exvivo, entorhinal=entorhinal,
                                            fsvernum=fsvernum)
    # connect inputs for AutoRecon3
    reconall.connect([(config_node, ar3_wf, [('lh_atlas', 'inputspec.lh_atlas'),
                                             ('rh_atlas', 'inputspec.rh_atlas'),
                                             ('lh_classifier1', 'inputspec.lh_classifier1'),
                                             ('rh_classifier1', 'inputspec.rh_classifier1'),
                                             ('lh_classifier2', 'inputspec.lh_classifier2'),
                                             ('rh_classifier2', 'inputspec.rh_classifier2'),
                                             ('lh_classifier3', 'inputspec.lh_classifier3'),
                                             ('rh_classifier3', 'inputspec.rh_classifier3'),
                                             ('lookup_table', 'inputspec.lookup_table'),
                                             ('wm_lookup_table', 'inputspec.wm_lookup_table'),
                                             ('src_subject_dir', 'inputspec.src_subject_dir'),
                                             ('src_subject_id', 'inputspec.src_subject_id'),
                                             ('color_table', 'inputspec.color_table')]),
                      (ar1_wf, ar3_wf, [('outputspec.brainmask', 'inputspec.brainmask'),
                                        ('outputspec.talairach', 'inputspec.transform'),
                                        ('outputspec.orig', 'inputspec.orig_mgz'),
                                        ('outputspec.rawavg', 'inputspec.rawavg')]),
                      (ar2_wf, ar3_wf, [('outputspec.aseg_presurf', 'inputspec.aseg_presurf'),
                                        ('outputspec.brain_finalsurfs', 'inputspec.brain_finalsurfs'),
                                        ('outputspec.wm', 'inputspec.wm'),
                                        ('outputspec.filled', 'inputspec.filled'),
                                        ('outputspec.norm', 'inputspec.norm')])])
    for hemi in ('lh', 'rh'):
        reconall.connect([(ar2_wf, ar3_wf, [('outputspec.{0}_inflated'.format(hemi),
                                             'inputspec.{0}_inflated'.format(hemi)),
                                            ('outputspec.{0}_smoothwm'.format(hemi),
                                             'inputspec.{0}_smoothwm'.format(hemi)),
                                            ('outputspec.{0}_white'.format(hemi),
                                             'inputspec.{0}_white'.format(hemi)),
                                            ('outputspec.{0}_cortex'.format(hemi),
                                             'inputspec.{0}_cortex_label'.format(hemi)),
                                            ('outputspec.{0}_area'.format(hemi),
                                             'inputspec.{0}_area'.format(hemi)),
                                            ('outputspec.{0}_curv'.format(hemi),
                                             'inputspec.{0}_curv'.format(hemi)),
                                            ('outputspec.{0}_sulc'.format(hemi),
                                             'inputspec.{0}_sulc'.format(hemi)),
                                            ('outputspec.{0}_orig_nofix'.format(hemi),
                                             'inputspec.{0}_orig_nofix'.format(hemi)),
                                            ('outputspec.{0}_orig'.format(hemi),
                                             'inputspec.{0}_orig'.format(hemi)),
                                            ('outputspec.{0}_white_H'.format(hemi),
                                             'inputspec.{0}_white_H'.format(hemi)),
                                            ('outputspec.{0}_white_K'.format(hemi),
                                             'inputspec.{0}_white_K'.format(hemi))])])


    # Add more outputs to outputspec
    outputs = ar1_outputs + ar2_outputs + ar3_outputs
    outputspec = pe.Node(niu.IdentityInterface(fields=outputs, mandatory_inputs=True),
                         name="outputspec")

    for outfields, wf in [(ar1_outputs, ar1_wf),
                          (ar2_outputs, ar2_wf),
                          (ar3_outputs, ar3_wf)]:
        for field in outfields:
            reconall.connect([(wf, outputspec, [('outputspec.' + field, field)])])

    # PreDataSink: Switch Transforms to datasinked transfrom
    # The transforms in the header files of orig.mgz, orig_nu.mgz, and nu.mgz
    # are all reference a transform in the cache directory. We need to rewrite the
    # headers to reference the datasinked transform

    # get the filepath to where the transform will be datasinked
    def getDSTransformPath(subjects_dir, subject_id):
        import os
        transform = os.path.join(subjects_dir, subject_id, 'mri', 'transforms',
                                  'talairach.xfm')
        return transform
    dstransform = pe.Node(niu.Function(['subjects_dir', 'subject_id'],
                                   ['transform'],
                                   getDSTransformPath),
                          name="PreDataSink_GetTransformPath")
    reconall.connect([(inputspec, dstransform, [('subjects_dir', 'subjects_dir'),
                                                ('subject_id', 'subject_id')])])
    # add the data sink transfrom location to the headers
    predatasink_orig = pe.Node(AddXFormToHeader(), name="PreDataSink_Orig")
    predatasink_orig.inputs.copy_name = True
    predatasink_orig.inputs.out_file = 'orig.mgz'
    reconall.connect([(outputspec, predatasink_orig, [('orig', 'in_file')]),
                      (dstransform, predatasink_orig, [('transform', 'transform')])])
    predatasink_orig_nu = pe.Node(AddXFormToHeader(), name="PreDataSink_Orig_Nu")
    predatasink_orig_nu.inputs.copy_name = True
    predatasink_orig_nu.inputs.out_file = 'orig_nu.mgz'
    reconall.connect([(outputspec, predatasink_orig_nu, [('orig_nu', 'in_file')]),
                      (dstransform, predatasink_orig_nu, [('transform', 'transform')])])
    predatasink_nu = pe.Node(AddXFormToHeader(), name="PreDataSink_Nu")
    predatasink_nu.inputs.copy_name = True
    predatasink_nu.inputs.out_file = 'nu.mgz'
    reconall.connect([(outputspec, predatasink_nu, [('nu', 'in_file')]),
                      (dstransform, predatasink_nu, [('transform', 'transform')])])


    # Datasink outputs
    datasink = pe.Node(DataSink(), name="DataSink")
    datasink.inputs.parameterization = False

    reconall.connect([(inputspec, datasink, [('subjects_dir', 'base_directory'),
                                             ('subject_id', 'container')])])

    # assign datasink inputs
    reconall.connect([(predatasink_orig, datasink, [('out_file', 'mri.@orig')]),
                      (predatasink_orig_nu, datasink, [('out_file', 'mri.@orig_nu')]),
                      (predatasink_nu, datasink, [('out_file', 'mri.@nu')]),
                      (outputspec, datasink, [('origvols', 'mri.orig'),
                                              ('t2_raw', 'mri.orig.@t2raw'),
                                              ('flair', 'mri.orig.@flair'),
                                              ('rawavg', 'mri.@rawavg'),
                                              ('talairach_auto', 'mri.transforms.@tal_auto'),
                                              ('talairach', 'mri.transforms.@tal'),
                                              ('t1', 'mri.@t1'),
                                              ('brainmask_auto', 'mri.@brainmask_auto'),
                                              ('brainmask', 'mri.@brainmask'),
                                              ('braintemplate', 'mri.@braintemplate'),
                                              ('tal_lta', 'mri.transforms.@tal_lta'),
                                              ('norm', 'mri.@norm'),
                                              ('ctrl_pts', 'mri.@ctrl_pts'),
                                              ('tal_m3z', 'mri.transforms.@tal_m3z'),
                                              ('nu_noneck', 'mri.@nu_noneck'),
                                              ('talskull2', 'mri.transforms.@talskull2'),
                                              ('aseg_noCC', 'mri.@aseg_noCC'),
                                              ('cc_up', 'mri.transforms.@cc_up'),
                                              ('aseg_auto', 'mri.@aseg_auto'),
                                              ('aseg_presurf', 'mri.@aseg_presuf'),
                                              ('brain', 'mri.@brain'),
                                              ('brain_finalsurfs', 'mri.@brain_finalsurfs'),
                                              ('wm_seg', 'mri.@wm_seg'),
                                              ('wm_aseg', 'mri.@wm_aseg'),
                                              ('wm', 'mri.@wm'),
                                              ('filled', 'mri.@filled'),
                                              ('ponscc_log', 'mri.@ponscc_log'),
                                              ('lh_orig_nofix', 'surf.@lh_orig_nofix'),
                                              ('lh_orig', 'surf.@lh_orig'),
                                              ('lh_smoothwm_nofix', 'surf.@lh_smoothwm_nofix'),
                                              ('lh_inflated_nofix', 'surf.@lh_inflated_nofix'),
                                              ('lh_qsphere_nofix', 'surf.@lh_qsphere_nofix'),
                                              ('lh_white', 'surf.@lh_white'),
                                              ('lh_curv', 'surf.@lh_curv'),
                                              ('lh_area', 'surf.@lh_area'),
                                              ('lh_cortex', 'label.@lh_cortex'),
                                              ('lh_smoothwm', 'surf.@lh_smoothwm'),
                                              ('lh_sulc', 'surf.@lh_sulc'),
                                              ('lh_inflated', 'surf.@lh_inflated'),
                                              ('lh_white_H', 'surf.@lh_white_H'),
                                              ('lh_white_K', 'surf.@lh_white_K'),
                                              ('lh_inflated_H', 'surf.@lh_inflated_H'),
                                              ('lh_inflated_K', 'surf.@lh_inflated_K'),
                                              ('lh_curv_stats', 'stats.@lh_curv_stats'),
                                              ('rh_orig_nofix', 'surf.@rh_orig_nofix'),
                                              ('rh_orig', 'surf.@rh_orig'),
                                              ('rh_smoothwm_nofix', 'surf.@rh_smoothwm_nofix'),
                                              ('rh_inflated_nofix', 'surf.@rh_inflated_nofix'),
                                              ('rh_qsphere_nofix', 'surf.@rh_qsphere_nofix'),
                                              ('rh_white', 'surf.@rh_white'),
                                              ('rh_curv', 'surf.@rh_curv'),
                                              ('rh_area', 'surf.@rh_area'),
                                              ('rh_cortex', 'label.@rh_cortex'),
                                              ('rh_smoothwm', 'surf.@rh_smoothwm'),
                                              ('rh_sulc', 'surf.@rh_sulc'),
                                              ('rh_inflated', 'surf.@rh_inflated'),
                                              ('rh_white_H', 'surf.@rh_white_H'),
                                              ('rh_white_K', 'surf.@rh_white_K'),
                                              ('rh_inflated_H', 'surf.@rh_inflated_H'),
                                              ('rh_inflated_K', 'surf.@rh_inflated_K'),
                                              ('rh_curv_stats', 'stats.@rh_curv_stats'),
                                              ('lh_aparc_annot_ctab', 'label.@aparc_annot_ctab'),
                                              ('aseg', 'mri.@aseg'),
                                              ('wmparc', 'mri.@wmparc'),
                                              ('wmparc_stats', 'stats.@wmparc_stats'),
                                              ('aseg_stats', 'stats.@aseg_stats'),
                                              ('aparc_a2009s_aseg', 'mri.@aparc_a2009s_aseg'),
                                              ('aparc_aseg', 'mri.@aparc_aseg'),
                                              ('aseg_presurf_hypos', 'mri.@aseg_presurf_hypos'),
                                              ('ribbon', 'mri.@ribbon'),
                                              ('rh_ribbon', 'mri.@rh_ribbon'),
                                              ('lh_ribbon', 'mri.@lh_ribbon'),
                                              ('lh_sphere', 'surf.@lh_sphere'),
                                              ('rh_sphere', 'surf.@rh_sphere'),
                                              ('lh_sphere_reg', 'surf.@lh_sphere_reg'),
                                              ('rh_sphere_reg', 'surf.@rh_sphere_reg'),
                                              ('lh_jacobian_white', 'surf.@lh_jacobian_white'),
                                              ('rh_jacobian_white', 'surf.@rh_jacobian_white'),
                                              ('lh_avg_curv', 'surf.@lh_avg_curv'),
                                              ('rh_avg_curv', 'surf.@rh_avg_curv'),
                                              ('lh_aparc_annot', 'label.@lh_aparc_annot'),
                                              ('rh_aparc_annot', 'label.@rh_aparc_annot'),
                                              ('lh_area_pial', 'surf.@lh_area_pial'),
                                              ('rh_area_pial', 'surf.@rh_area_pial'),
                                              ('lh_curv_pial', 'surf.@lh_curv_pial'),
                                              ('rh_curv_pial', 'surf.@rh_curv_pial'),
                                              ('lh_pial', 'surf.@lh_pial'),
                                              ('rh_pial', 'surf.@rh_pial'),
                                              ('lh_thickness_pial', 'surf.@lh_thickness_pial'),
                                              ('rh_thickness_pial', 'surf.@rh_thickness_pial'),
                                              ('lh_area_mid', 'surf.@lh_area_mid'),
                                              ('rh_area_mid', 'surf.@rh_area_mid'),
                                              ('lh_volume', 'surf.@lh_volume'),
                                              ('rh_volume', 'surf.@rh_volume'),
                                              ('lh_aparc_annot_ctab', 'label.@lh_aparc_annot_ctab'),
                                              ('rh_aparc_annot_ctab', 'label.@rh_aparc_annot_ctab'),
                                              ('lh_aparc_stats', 'stats.@lh_aparc_stats'),
                                              ('rh_aparc_stats', 'stats.@rh_aparc_stats'),
                                              ('lh_aparc_pial_stats', 'stats.@lh_aparc_pial_stats'),
                                              ('rh_aparc_pial_stats', 'stats.@rh_aparc_pial_stats'),
                                              ('lh_aparc_a2009s_annot', 'label.@lh_aparc_a2009s_annot'),
                                              ('rh_aparc_a2009s_annot', 'label.@rh_aparc_a2009s_annot'),
                                              ('lh_aparc_a2009s_annot_ctab',
                                               'label.@lh_aparc_a2009s_annot_ctab'),
                                              ('rh_aparc_a2009s_annot_ctab',
                                               'label.@rh_aparc_a2009s_annot_ctab'),
                                              ('lh_aparc_a2009s_annot_stats',
                                               'stats.@lh_aparc_a2009s_annot_stats'),
                                              ('rh_aparc_a2009s_annot_stats',
                                               'stats.@rh_aparc_a2009s_annot_stats'),
                                              ('lh_aparc_DKTatlas40_annot',
                                               'label.@lh_aparc_DKTatlas40_annot'),
                                              ('rh_aparc_DKTatlas40_annot',
                                               'label.@rh_aparc_DKTatlas40_annot'),
                                              ('lh_aparc_DKTatlas40_annot_ctab',
                                               'label.@lh_aparc_DKTatlas40_annot_ctab'),
                                              ('rh_aparc_DKTatlas40_annot_ctab',
                                               'label.@rh_aparc_DKTatlas40_annot_ctab'),
                                              ('lh_aparc_DKTatlas40_annot_stats',
                                               'stats.@lh_aparc_DKTatlas40_annot_stats'),
                                              ('rh_aparc_DKTatlas40_annot_stats',
                                               'stats.@rh_aparc_DKTatlas40_annot_stats'),
                                              ('lh_wg_pct_mgh', 'surf.@lh_wg_pct_mgh'),
                                              ('rh_wg_pct_mgh', 'surf.@rh_wg_pct_mgh'),
                                              ('lh_wg_pct_stats', 'stats.@lh_wg_pct_stats'),
                                              ('rh_wg_pct_stats', 'stats.@rh_wg_pct_stats'),
                                              ('lh_pctsurfcon_log', 'log.@lh_pctsurfcon_log'),
                                              ('rh_pctsurfcon_log', 'log.@rh_pctsurfcon_log'),
                                              ('lh_BAMaps_stats', 'stats.@lh_BAMaps_stats'),
                                              ('lh_color', 'label.@lh_color'),
                                              ('lh_thresh_BAMaps_stats', 'stats.@lh_thresh_BAMaps_stats'),
                                              ('lh_thresh_color', 'label.@lh_thresh_color'),
                                              ('rh_BAMaps_stats', 'stats.@rh_BAMaps_stats'),
                                              ('rh_color', 'label.@rh_color'),
                                              ('rh_thresh_BAMaps_stats', 'stats.@rh_thresh_BAMaps_stats'),
                                              ('rh_thresh_color', 'label.@rh_thresh_color'),
                                              ('lh_BAMaps_labels', 'label.@lh_BAMaps_labels'),
                                              ('lh_thresh_BAMaps_labels', 'label.@lh_thresh_BAMaps_labels'),
                                              ('rh_BAMaps_labels', 'label.@rh_BAMaps_labels'),
                                              ('rh_thresh_BAMaps_labels', 'label.@rh_thresh_BAMaps_labels'),
                                              ('lh_BAMaps_annotation',
                                               'label.@lh_BAMaps_annotation'),
                                              ('lh_thresh_BAMaps_annotation',
                                               'label.@lh_thresh_BAMaps_annotation'),
                                              ('rh_BAMaps_annotation',
                                               'label.@rh_BAMaps_annotation'),
                                              ('rh_thresh_BAMaps_annotation',
                                               'label.@rh_thresh_BAMaps_annotation'),
                                          ]),
                      ])

    # compeltion node
    # since recon-all outputs so many files a completion node is added
    # that will output the subject_id once the workflow has completed
    def completemethod(datasinked_files, subject_id):
        print("recon-all has finished executing for subject: {0}".format(subject_id))
        return subject_id

    completion = pe.Node(niu.Function(['datasinked_files', 'subject_id'],
                                      ['subject_id'],
                                      completemethod),
                         name="Completion")

    # create a special identity interface for outputing the subject_id

    postds_outputspec = pe.Node(niu.IdentityInterface(['subject_id']),
                                name="postdatasink_outputspec")

    reconall.connect([(datasink, completion, [('out_file', 'datasinked_files')]),
                      (inputspec, completion, [('subject_id', 'subject_id')]),
                      (completion, postds_outputspec, [('subject_id', 'subject_id')])])

    return reconall




