# (c) 2015-2023 Acellera Ltd http://www.acellera.com
# All Rights Reserved
# Distributed under HTMD Software License Agreement
# No redistribution in whole or part
#
{% for version in app_info %}
class _{{ app_name }}_{{version}}:
    """
    .. automethod:: __call__
    """
    _name = "{{ app_name }}"
    __manifest__ = {{ app_info[version]['manifest'] }}
    {% if 'resources' in app_info[version]['manifest'] %}
    _execution_resources = {{ app_info[version]['manifest']['resources'] }}
    {% else %}
    _execution_resources = None
    {% endif %}

    def __init__(self):
        self.files = _get_app_files(os.path.join("{{ app_info[version]['appdir'] }}", "files"), "{{ app_name }}", "{{version}}")
        {% if ('datasets' in app_info[version]['manifest']) or ('artifacts' in app_info[version]['manifest']) %}
        self.datasets = _Artifacts({{ app_info[version]['manifest'] }}, self.files)
        self.artifacts = self.datasets
        {% endif %}
        {% if 'tests' in app_info[version] %}
        self.tests = _Tests({{ app_info[version]['tests'] }}, self)
        {% endif %}
        pass

    def __call__(
        self,
        {% for arg in app_info[version]['main_function']['args'] %}{{ arg }}
        {% endfor %}
    ):
        """
        {% for doc in app_info[version]['main_function']['docs'] %}{{ doc }}
        {% endfor %}
        Returns
        -------
        exec_dir : ExecutableDirectory
            Returns an executable directory with the setup for the run
        """
        {% if app_info[version]['main_function']['args']|length > 0 %}
        args = locals()
        del args["self"]
        return self.main(**args)
        {% else %}
        raise NotImplementedError(f"Main function not implemented. See other methods: {{ app_info[version]['functions']|map(attribute='name')|list }}")
        {% endif %}

    {% for func in app_info[version]['functions'] %}
    def {{ func['name'] }}(
        self,
        {% for arg in func['args'] %}{{ arg }}
        {% endfor %}
    ):
        """
        {% for doc in func['docs'] %}{{ doc }}
        {% endfor %}
        Returns
        -------
        exec_dir : ExecutableDirectory
            Returns an executable directory with the setup for the run
        """
        args = locals() # Should be first line in the function
        del args["self"]

        from datetime import datetime
        import uuid
        assert "outdir" in args or "execdir" in args, "Functions must accept either 'outdir' or 'execdir'"

        if "outdir" in args:
            outdir = args["outdir"]
            args["outdir"] = "."
        else:
            if isinstance(args["execdir"], _File):
                args["execdir"] = args["execdir"].path
            outdir = args["execdir"]
            args["execdir"] = "."

        if "scratchdir" in args:
            if args["scratchdir"] is None:
                args["scratchdir"] = "./scratch/"
            os.makedirs(args["scratchdir"], exist_ok=True)

        now = datetime.now()
        identifier = f"_{now.strftime(r'%d_%m_%Y_%H_%M')}_{uuid.uuid4().hex[:8]}"
        inputsdir = os.path.join(outdir, f"run{identifier}")
        {% if app_info[version]['new_mode'] %}
        _write_inputs(outdir, inputsdir, args, self.__manifest__['functions'][{{loop.index0}}], "{{func['function']}}")
        {% else %}
        _write_inputs(outdir, inputsdir, args, self.__manifest__['functions'][{{loop.index0}}])
        {% endif %}

        {% if app_info[version]['run.sh'] %}
        
        target_run_sh = os.path.join(outdir, f"run{identifier}.sh")
        shutil.copy("{{ app_info[version]['run.sh'] }}", target_run_sh)
        st = os.stat(target_run_sh)
        os.chmod(target_run_sh, st.st_mode | stat.S_IEXEC)
        {%endif %}

        return ExecutableDirectory(outdir, runsh=os.path.basename(target_run_sh), _execution_resources=self._execution_resources)
    {% endfor %}

{% endfor %}

global {{ app_name }}

class {{ app_name }}(_{{ app_name }}_{{latest}}): 
    _name = "{{ app_name }}"

    """
    .. automethod:: __call__
    """   
    def __init__(self):
        super().__init__()
        {% for version in app_info %}
        global _{{ app_name }}_{{version}}
        self.{{ version }} = _{{ app_name }}_{{version}}()
        {% endfor %}

_class_obj = {{ app_name }}()
{{ app_name }} = _class_obj

_app_list.append({{ app_name }})
