#!/Users/boydb1/anaconda/bin/python
# -*- coding: utf-8 -*-

"""
    Title: GenerateModuleTemplate
    Author: Benjamin Yvernault
    contact: b.yvernault@ucl.ac.uk
    Purpose:
        Generate your module.py following the template for module describe in this file.
"""

__author__ = 'Benjamin Yvernault'
__email__ = 'b.yvernault@ucl.ac.uk'
__purpose__ = "Generate your module.py following the template for module describe in this file."
__version__ = '1.0.0'
__modifications__ = '24 August 2015 - Original write'

import os
import re
from datetime import datetime

DEFAULT_TEMPLATE = """'''
    Author:         {author}
    contact:        {email_addr}
    Module name:    Module_{name}
    Creation date:  {now}
    Purpose:        {purpose}
'''

__author__ = "{author}"
__email__ = "{email_addr}"
__purpose__ = "{purpose}"
__module_name__ = "Module_{name}"
__modifications__ = "{now} - Original write"

# Python packages import
import os
import logging
from dax import XnatUtils, ScanModule, SessionModule

# set-up logger for printing statements
LOGGER = logging.getLogger('dax')

# Default values for arguments:
# EDIT PARAMETERS FOR YOUR MODULE CASE
DEFAULT_TPM_PATH = '/tmp/{name}_temp/'
DEFAULT_MODULE_NAME = '{name}'
DEFAULT_TEXT_REPORT = 'ERROR/WARNING for {name} :\\n'
"""

SCAN_LEVEL_TEMPLATE = DEFAULT_TEMPLATE+"""
class Module_{name}(ScanModule):
    '''
    Module class for {name} that runs on a scan

    :param mod_name: module name
    :param directory: temp directory for the module temporary files
    :param email: email address to send error/warning to
    :param text_report: title for the report
    #
    # ADD MORE PARAMETERS AS NEEDED HERE
    #
    '''
    def __init__(self, mod_name=DEFAULT_MODULE_NAME, directory=DEFAULT_TPM_PATH, email=None,
                 text_report=DEFAULT_TEXT_REPORT):
        super(Module_{name}, self).__init__(mod_name, directory, email, text_report=text_report)
        #
        # ADD MORE PARAMETERS AS NEEDED HERE LIKE self.param = param
        #

    def prerun(self, settings_filename=''):
        '''
        prerun function overridden from base-class
        method that runs at the beginning, before looping over the sessions for the project

        :param settings_filename: settings file name to set the temporary folder
        '''
        # make temporary directory using the settings filename
        self.make_dir(settings_filename)

        #
        # ADD CODE HERE IF YOU NEED TO EXECUTE SOMETHING BEFORE THE LOOP
        #

    def afterrun(self, xnat, project):
        '''
        afterrun function overridden from base-class
        method that runs at the end, after looping over the sessions for the project

        :param xnat: interface to xnat object (XnatUtils.get_interface())
        :param project: project ID/label on XNAT
        '''
        #
        # ADD CODE HERE IF YOU NEED TO EXECUTE SOMETHING AFTER THE LOOP
        #

        # send report
        if self.send_an_email:
            self.send_report()

        # clean the directory created
        try:
            os.rmdir(self.directory)
        except:
            LOGGER.warn('{name} -- afterrun -- '+self.directory+' not empty. Could not delete it.')

    def needs_run(self, cscan, xnat):
        '''
        needs_run function overridden from base-class
        method that runs before each loop step to check if we need to run on this scan

        :param cscan: CacheScan object from XnatUtils
        :param xnat: interface to xnat object (XnatUtils.get_interface())
        :return: boolean, True if needs to run
        '''
        #
        # CODE TO CHECK IF THE MODULE NEEDS TO RUN FOR THE SCAN DEFINE BY CSCAN
        #
        # EXAMPLE: CHECK IF NIFTI EXISTS AND IF THERE IS A DICOM FOR DCM2NII
        # # Variables:
        # scan_info = cscan.info()
        #
        # # Check output
        # if XnatUtils.has_resource(cscan, 'NIFTI'):
        #     LOGGER.debug('Has NIFTI')
        #     return False
        # # Check input
        # if not XnatUtils.has_resource(cscan, 'DICOM'):
        #     LOGGER.debug('no DICOM resource')
        #     return False

        return True

    def run(self, scan_info, scan_obj):
        '''
        run method: {purpose}
          lines of code that will be executed for the scan

        :param scan_info: python dictionary with information on the scan (see output of XnatUtils.list_scans)
        :param scan_obj: pyxnat Scan object
        '''
        #
        # CODE TO EXECUTE ON THE SCAN (E.G: GENERATE NIFTI/PREVIEW)
        #

        # clean temporary folder
        self.clean_directory()
"""

SESSION_LEVEL_TEMPLATE = DEFAULT_TEMPLATE+"""
# Resource name set on session to know that the module ran
RESOURCE_FLAG_NAME = 'Module_{name}'

class Module_{name}(SessionModule):
    '''
    Module class for {name} that runs on a session

    :param mod_name: module name
    :param directory: temp directory for the module temporary files
    :param email: email address to send error/warning to
    :param text_report: title for the report
    #
    # ADD MORE PARAMETERS AS NEEDED HERE
    #
    '''
    def __init__(self, mod_name=DEFAULT_MODULE_NAME, directory=DEFAULT_TPM_PATH, email=None,
                 text_report=DEFAULT_TEXT_REPORT):
        super(Module_{name}, self).__init__(mod_name, directory, email, text_report=text_report)
        #
        # ADD MORE PARAMETERS AS NEEDED HERE LIKE self.param = param
        #

    def prerun(self, settings_filename=''):
        '''
        prerun function overridden from base-class
        method that runs at the beginning, before looping over the sessions for the project

        :param settings_filename: settings file name to set the temporary folder
        '''
        # make temporary directory using the settings filename
        self.make_dir(settings_filename)

        #
        # ADD CODE HERE IF YOU NEED TO EXECUTE SOMETHING BEFORE THE LOOP
        #

    def afterrun(self, xnat, project):
        '''
        afterrun function overridden from base-class
        method that runs at the end, after looping over the sessions for the project

        :param xnat: interface to xnat object (XnatUtils.get_interface())
        :param project: project ID/label on XNAT
        '''
        #
        # ADD CODE HERE IF YOU NEED TO EXECUTE SOMETHING AFTER THE LOOP
        #

        # send report
        if self.send_an_email:
            self.send_report()

        # clean the directory created
        try:
            os.rmdir(self.directory)
        except:
            LOGGER.warn('{name} -- afterrun -- '+self.directory+' not empty. Could not delete it.')

    def needs_run(self, csess, xnat):
        '''
        needs_run function overridden from base-class
        method that runs before each loop step to check if we need to run on this session

        :param csess: CacheSession object from XnatUtils
        :param xnat: interface to xnat object (XnatUtils.get_interface())
        :return: boolean, True if needs to run
        '''
        #
        # CODE TO CHECK IF THE MODULE NEEDS TO RUN FOR THE SESSION DEFINE BY CSESS
        # FOR SESSION MODULE, SET A RESOURCE ON SESSION WITH FLAG NAME
        #
        return self.has_flag_resource(csess, RESOURCE_FLAG_NAME)

    def run(self, session_info, session_obj):
        '''
        run method: {purpose}
          lines of code that will be executed for the session

        :param session_info: python dictionary with information on the session (see output of XnatUtils.list_sessions)
        :param session_obj: pyxnat Session object
        '''
        #
        # CODE TO EXECUTE ON THE SESSION (E.G: SET SCAN TYPE)
        #

        # clean temporary folder
        self.clean_directory()

        # create the flag resource on the session
        session_obj.resource(RESOURCE_FLAG_NAME).create()
"""

def write_module(module_fpath, templates, args):
    """
    Write the Module.py with the proper template

    :param module_fpath: path where the module script will be saved
    :param templates: template to use (scan or session)
    :param args: arguments parser
    """
    module_code = templates.format(author=args.author,
                                   email_addr=args.email,
                                   name=args.name,
                                   now=str(datetime.now()),
                                   purpose=args.purpose)
    f_obj = open(module_fpath, "w")
    f_obj.writelines(module_code)
    f_obj.close()

def parse_args():
    """
    Parser for arguments
    """
    from argparse import ArgumentParser
    usage = "Generate a module.py file from the template for dax in a new file."
    argp = ArgumentParser(prog='GenerateModuleTemplate', description=usage)
    argp.add_argument('-n', dest='name', help='Name for module. E.G: dcm2nii.', required=True)
    argp.add_argument('-a', dest='author', help='Author name.', required=True)
    argp.add_argument('-e', dest='email', help='Author email address.', required=True)
    argp.add_argument('-p', dest='purpose', help='Module purpose.', required=True)
    argp.add_argument('--onScan', dest='on_scan', action='store_true', help='Use Scan type Spider.')
    argp.add_argument('-d', dest='directory',
                      help='Directory where the module file will be generated. Default: current directory.', default=None)
    return argp.parse_args()

if __name__ == '__main__':
    ARGS = parse_args()

    ## Get a proper name from the input
    # remove .py if present at the end of the file
    if ARGS.name.endswith('.py'):
        ARGS.name = ARGS.name[:-3]
    # remove settings if present in name
    if "module" in ARGS.name.lower():
        module_search = re.compile(re.escape('module'), re.IGNORECASE)
        ARGS.name = module_search.sub('', ARGS.name)
    # remove any particular character and change it by an underscore
    ARGS.name = re.sub('[^a-zA-Z0-9]', '_', ARGS.name)
    if ARGS.name[-1] == '_':
        ARGS.name = ARGS.name[:-1]

    MODULE_NAME = """Module_{name}.py""".format(name=ARGS.name)
    if ARGS.directory and os.path.exists(ARGS.directory):
        MODULE_FPATH = os.path.join(ARGS.directory, MODULE_NAME)
    else:
        MODULE_FPATH = os.path.join(os.getcwd(), MODULE_NAME)
    if ARGS.on_scan:
        print "Generating file %s for scan module %s ..." % (MODULE_FPATH, ARGS.name)
        write_module(MODULE_FPATH, SCAN_LEVEL_TEMPLATE, ARGS)
    else:
        print "Generating file %s for session module %s ..." % (MODULE_FPATH, ARGS.name)
        write_module(MODULE_FPATH, SESSION_LEVEL_TEMPLATE, ARGS)
