#! /usr/bin/env python


from __future__ import print_function
import six
import sys
import os
from glob import glob
import time
import argparse
from six.moves import configparser
try:
    from mothulity import __version__
except ImportError:
    __version__ = "development"
try:
    import mothulity.utilities as mut
except ImportError:
    import utilities as mut

def main():
    parser = argparse.ArgumentParser(
        prog="mothulity",
        usage="mothulity [OPTION]",
        description="creates slurm-suitable mothur script."
    )
    databases = parser.add_argument_group("databases options")
    slurm = parser.add_argument_group("slurm options")
    mothur = parser.add_argument_group("mothur options")
    settings = parser.add_argument_group("configuration settings")
    advanced = parser.add_argument_group("advanced options")

    parser.add_argument(
        "-v",
        "--version",
        action="version",
        version=__version__
    )
    parser.add_argument(
        action="store",
        dest="files_directory",
        metavar="path/to/files",
        default=".",
        nargs="?",
        help="""
        input directory path. Used as working directory for the job.
        Default CWD.
        """
    )
    parser.add_argument(
        "-n",
        "--job-name",
        action="store",
        dest="job_name",
        metavar="",
        default="mothur.job",
        help="""
        job name. Used for naming scripts, queued job and html output. Default
        <mothur.job>.
        """
    )
    parser.add_argument(
        "-d",
        "--output-dir",
        action="store",
        dest="output_dir",
        metavar=".",
        default=".",
        help="""
        output directory path for the script. It is NOT output directory for
        actual job.
        """
    )
    parser.add_argument(
        "-r",
        "--run",
        action="store",
        dest="run",
        metavar="",
        default=None,
        help="""
        shell call. Runs the mothur script immediately in current directory,
        eg -r sh for regular bash or -r sbatch for slurm.
        """
    )
    parser.add_argument(
        "-a",
        "--analysis-only",
        action="store_true",
        dest="analysis_only",
        default=False,
        help="""
        outputs just the part involved in statistical analysis and drawing.
        """
    )
    parser.add_argument(
        "--render-html",
        action="store_true",
        dest="render_html",
        default=False,
        help="""
        path/to/html-template-file. Passes args into fancy html.
        """
    )
    parser.add_argument(
        "--notify-email",
        action="store",
        dest="notify_email",
        metavar="",
        default=None,
        help="""
        email address you want to notify when job is done.
        """
    )
    parser.add_argument(
        "--dry-run",
        action="store_true",
        dest="dry_run",
        default=False,
        help="""
        prevents mothur script execution. Default <False>.
        """
    )
    parser.add_argument(
        "--processors",
        action="store",
        dest="processors",
        metavar="",
        default=None,
        help="""
        number of processors to use. Overrides any other source of this setting.
        """
    )
    databases.add_argument(
        "--set-align-database-path",
        action="store",
        dest="set_align_database_path",
        metavar="",
        default=None,
        help="""
        Set persistent path to align database.
        """
    )
    databases.add_argument(
        "--set-taxonomy-database-path",
        action="store",
        dest="set_taxonomy_database_path",
        metavar="",
        default=None,
        help="""
        Set persistent path to taxonomy database.
        """
    )
    slurm.add_argument(
        "--list-slurm-settings",
        action="store_true",
        dest="list_slurm_settings",
        default=False,
        help="""
        list SLURM MD settings defined in the config file.
        """
    )
    slurm.add_argument(
        "--add-slurm-setting",
        action='store',
        dest="add_slurm_setting",
        metavar="",
        default=False,
        help="""
        set persistent SLURM setting. If the setting exists it is OVERWRITTEN.
        Format:
            "name=<string>
             partition=<string>
             nodes=<integer>
             ntasks_per_node=<integer>
             node_list=<integer>
             processors=<integer>".
        For instance:
            "name=small
             partition=short
             nodes=1
             ntasks_per_node=1
             node_list=n42
             processors=12".
        """
    )
    slurm.add_argument(
    "--use-slurm-setting",
    action="store",
    dest="use_slurm_setting",
    metavar="",
    help="""
    use previously set SLURM setting (with --add-slurm-setting).
    """
    )
    mothur.add_argument(
        "--max-ambig",
        action="store",
        dest="max_ambig",
        metavar="",
        default=0,
        help="""
        maximum number of ambiguous bases allowed.screen.seqs param.
        Default <0>.
        """
    )
    mothur.add_argument(
        "--max-homop",
        action="store",
        dest="max_homop",
        metavar="",
        default=8,
        help="""
        maximum number of homopolymers allowed. screen.seqs param. Default <8>.
        """
    )
    mothur.add_argument(
        "--min-length",
        action="store",
        dest="min_length",
        metavar="",
        default=None,
        help="""
        minimum length of read allowed. screen.seqs param. Default <400>.
        """
    )
    mothur.add_argument(
        "--max-length",
        action="store",
        dest="max_length",
        metavar="",
        default=None,
        help="""
        minimum length of read allowed. screen.seqs param. Default <500>.
        """
    )
    mothur.add_argument(
        "--min-overlap",
        action="store",
        dest="min_overlap",
        metavar="",
        default=25,
        help="""
        minimum number of bases overlap in contig. screen.seqs param.
        Default <25>.
        """
    )
    mothur.add_argument(
        "--screen-criteria",
        action="store",
        dest="screen_criteria",
        metavar="",
        default=95,
        help="""
        trim start and end of read to fit this percentage of all reads.
        screen.seqs param. Default <95>.
        """
    )
    mothur.add_argument(
        "--chop-length",
        action="store",
        dest="chop_length",
        metavar="",
        default=250,
        help="""
        cut all the reads to this length. Keeps front of the sequences.
        chop.seqs argument. Default <250>.
        """
    )
    mothur.add_argument(
        "--precluster-diffs",
        action="store",
        dest="precluster_diffs",
        metavar="",
        default=2,
        help="""
        number of differences between reads treated as insignificant.
        screen.seqs param. Default <2>.
        """
    )
    mothur.add_argument(
        "--chimera-dereplicate",
        action="store",
        dest="chimera_dereplicate",
        metavar="",
        default="T",
        help="""
        checking for chimeras by group. chimera.vsearch param.
        Default <T>.
        """
    )
    mothur.add_argument(
        "--classify-seqs-cutoff",
        action="store",
        dest="classify_seqs_cutoff",
        metavar="",
        default=80,
        help="""
        bootstrap value for taxonomic assignment. classify.seqs param.
        Default <80>.
        """
    )
    mothur.add_argument(
        "--classify-ITS",
        action="store_true",
        dest="classify_ITS",
        default=False,
        help="""
        removes align.seqs step and modifies classify.seqs with <method=knn>,
        <search=blast>, <match=2>, <mismatch=-2>, <gapopen=-2>, <gapextend=-1>,
        <numwanted=1> Default <False>.
        """
    )
    mothur.add_argument(
        "--align-database",
        action="store",
        dest="align_database",
        metavar="",
        default=None,
        help="""
        path/to/align-database. Used by align.seqs command as <reference>
        argument. Default <~/db/Silva.nr_v119/silva.nr_v119.align>.
        """
    )
    mothur.add_argument(
        "--taxonomy-database",
        action="store",
        dest="taxonomy_database",
        metavar="",
        default=None,
        help="""
        path/to/taxonomy-database. Used by classify.seqs as <taxonomy> argument.
        Default <~/db/Silva.nr_v119/silva.nr_v119.tax>.
        """
    )
    mothur.add_argument(
        "--alignment-region",
        action="store",
        dest="alignment_region",
        metavar="",
        default=False,
        help="""
        Cuts choosen alignment database to desired region.
        Available options: v3, v4, v3v4, <start-end>.
        In case of passing start-end posittion instead of region name,
        coordinates must be separate by '-'.
        In order to determine the coordinates perfectly matching used primers
        it is strongly recommended to follow PD Schloss guide
        (available on mothur blog:
        http://blog.mothur.org/2016/07/07/Customization-for-your-region/).
        """
    )
    mothur.add_argument(
        "--cluster-cutoff",
        action="store",
        dest="cluster_cutoff",
        metavar="",
        default=0.03,
        help="""
        cutoff value. Smaller == faster cluster param. Default <0.03>.
        """
    )
    mothur.add_argument(
        "--cluster-method",
        action="store",
        dest="cluster_method",
        metavar="",
        default="agc",
        help="""
        Clustering method. Available options are: opticlust <opti>, average
        neighbor <average>, furthest neighbor <furthest>,
        nearest neighbor <nearest>, Vsearch agc <agc>, Vsearch dgc <dgc>.
        For detailed info visit https://www.mothur.org/wiki/Cluster.split.
        Default <agc>.
        """
    )
    mothur.add_argument(
        "--full-ram-load",
        action="store_true",
        dest="full_ram_load",
        default=False,
        help="""
        Replaces ram-saving <cluster.split> command with no-compromise
        <cluster> command.
        """
    )
    mothur.add_argument(
        "--label",
        action="store",
        dest="label",
        metavar="",
        default=0.03,
        help="""
        label argument for number of commands for OTU analysis approach.
        Default <0.03>.
        """
    )
    mothur.add_argument(
        "--remove-rare-nseq",
        action="store",
        dest="remove_rare_nseq",
        metavar="",
        default=2,
        help="""
        Removes OTUs with total abundance less than or equal to nseqs.
        --remove-rare-nseq 1 removes all singletons,
        --remove-rare-nseq 0 prevents software from removing any OTU despite its rarity.
        Default <2>.
        """
    )
    mothur.add_argument(
        "--keep-all",
        action="store_true",
        dest="keep_all",
        default=False,
        help="""
        Keeps all groups, even if they can distort analysis due to small size
        during subsampling.
        """
    )
    settings.add_argument(
        "--set-main-config-path",
        action="store",
        dest="set_main_config_path",
        metavar="",
        default=None,
        help="""
        Set temporary path to config file.
        """
    )
    settings.add_argument(
        "--set-slurm-config-path",
        action="store",
        dest="set_slurm_config_path",
        metavar="",
        default=None,
        help="""
        Set temporary path to SLURM config file.
        """
    )
    advanced.add_argument(
        "--exclude-krona",
        action="store_true",
        dest="exclude_krona",
        default=False,
        help="""
        Do not include krona pie chart into final html. Krona can be included
        only as an iframe.
        """
    )

    if len(sys.argv)==1:
        parser.print_help()
        parser.exit()

    try:
        args = parser.parse_args()
    except SystemExit as error:
        if error.code == 2:
            parser.print_help()
        parser.exit()

# Define variables that can overridden by CLI, config or other function and should cause exit if None in a proper place in the decision tree.
    align_database_abs = None
    taxonomy_database_abs = None
    slurm_setting = None
    junk_grps = 0
    sampl_num = None
    krona_html = None
    sum_html = None
    raref_html = None
    nmds_jc_html = None
    nmds_th_html = None
# Read-in config file. CLI overrides default directory.
    if args.set_main_config_path:
        if os.path.isfile(args.set_main_config_path):
            mothu_config_path_abs = os.path.abspath(args.set_main_config_path)
            print("Using {} as config file.".format(mothu_config_path_abs))
            time.sleep(2)
        else:
            print("Failed to find or open {} config file. Using default.".format(args.set_main_config_path))
            time.sleep(2)
            mothu_config_path_abs = mut.get_dir_path("../config/mothulity.config")
    if args.set_slurm_config_path:
        if os.path.isfile(args.set_slurm_config_path):
            slurm_config_path_abs = os.path.abspath(args.set_slurm_config_path)
            print("Using {} as config file.".format(slurm_config_path_abs))
            time.sleep(2)
        else:
            print("Failed to find or open {} config file. Using default.".format(args.set_slurm_config_path))
            time.sleep(2)
            slurm_config_path_abs = mut.get_dir_path("../config/mothulity.config")
    else:
        mothu_config_path_abs = mut.get_dir_path("../config/mothulity.config")
        slurm_config_path_abs = mut.get_dir_path("../config/slurm.config")
    mothu_config = configparser.ConfigParser()
    mothu_config.read(mothu_config_path_abs)
    slurm_config = configparser.ConfigParser()
    slurm_config.read(slurm_config_path_abs)
# List SLURM MD settings from the config file.
    if args.list_slurm_settings:
        if len(slurm_config.sections()) == 0:
            print("No SLURM settings defined.")
            exit()
        for section in slurm_config.sections():
            print(section, end="\n-------\n")
            for k, v in slurm_config.items(section):
                print(k, v, sep=': ')
        exit()
# Set config file options.
    if any((args.set_align_database_path, args.set_taxonomy_database_path)):
        if "databases" not in mothu_config.sections(): mothu_config.add_section("databases")
        if args.set_align_database_path:
            mothu_config.set("databases", "align", os.path.abspath(args.set_align_database_path))
            with open(mothu_config_path_abs, "w") as fout: mothu_config.write(fout)
        if args.set_taxonomy_database_path:
            mothu_config.set("databases", "taxonomy", os.path.abspath(args.set_taxonomy_database_path))
            with open(mothu_config_path_abs, "w") as fout: mothu_config.write(fout)
        exit()
    if args.add_slurm_setting:
        slurm_setting = dict(
            i.split("=")
            if '=' in i
            else (i, '')
            for i in args.add_slurm_setting.split()
            )
        section = slurm_setting['name']
        slurm_setting.pop('name')
        slurm_config.add_section(section)
        for k, v in slurm_setting.items(): slurm_config.set(section, k, v)
        with open(slurm_config_path_abs, "w") as fout: slurm_config.write(fout)
        exit()
# Read options from config file and wrap them up into proper variables
# If config file is the only source of the variable content and it is not found - quit from here.
    try:
        preproc_template = mothu_config.get("templates", "preproc")
        analysis_template = mothu_config.get("templates", "analysis")
        output_template = mothu_config.get("templates", "output")
    except Exception as e:
        print("Templates not found in config file! Quitting...")
        time.sleep(2)
        exit()
    try:
        align_database_abs = mothu_config.get("databases", "align")
    except Exception as e:
        print("Align database path not found in config file.")
        time.sleep(2)
    try:
        taxonomy_database_abs = mothu_config.get("databases", "taxonomy")
    except Exception as e:
        print("Taxonomy database path not found in config file.")
        time.sleep(2)
    try:
        datatables_css = mothu_config.get("css", "datatables")
        w3_css = mothu_config.get("css", "w3")
    except Exception as e:
        print("CSS links not found in config file! Output will not display properly!")
        time.sleep(2)
    try:
        datatables_js = mut.get_dir_path("../js/{}".format(mothu_config.get("js", "datatables")))
        slideshow_js = mut.get_dir_path("../js/{}".format(mothu_config.get("js", "slideshow")))
    except Exception as e:
        print("Javascript links not found in config file. Output will not display properly!")
        time.sleep(2)
    if args.use_slurm_setting:
        try:
            slurm_setting = {
                    k: v
                    for k, v in slurm_config.items(args.use_slurm_setting)
            }
        except Exception as e:
            print("SLURM setting not found in config file! Quitting...")
            time.sleep(2)
            exit()
# Override databases paths from config file with CLI args if specified.
    if args.align_database:
        align_database_abs = os.path.abspath(os.path.expanduser(args.align_database))
    if args.taxonomy_database:
        taxonomy_database_abs = os.path.abspath(os.path.expanduser(args.taxonomy_database))
# Make sure essential variables that can be overriden by CLI are defined.
# Unless args.analysis_only or args.render_html are True - quit from here.
    if not args.analysis_only and not args.render_html:
        if not align_database_abs:
            print("No align database path defined in config nor command-line. Quitting...")
            exit()
        if not taxonomy_database_abs:
            print("No taxonomy database path defined in config nor command-line. Quitting...")
            exit()
    processors = mut.determine_cpus()
    if slurm_setting:
        if slurm_setting['processors']: processors = slurm_setting.pop('processors')
    if args.processors: processors = args.processors
# Validate if input and output directories exist and do not contain dashes. Then make them absolute paths. If dashes - quit from here.
    if os.path.exists(args.files_directory):
        files_directory_abs = "{}/".format(os.path.abspath(args.files_directory))
        if "-" in files_directory_abs:
            print("Mothur does not accept dashes in the paths. Please rename:\n{}".format(files_directory_abs))
            exit()
    else:
        print("Input directory not found. Quitting...")
        exit()
    if os.path.exists(args.output_dir):
        output_dir_abs = "{}/".format(os.path.abspath(args.output_dir))
        if "-" in output_dir_abs:
            print("Mothur does not accept dashes in the paths. Please rename:\n{}".format(output_dir_abs))
            exit()
    else:
        print("Output directory not found. Quitting...")
        exit()
# Read file globs from specified directories.
    shared_files_list = glob("{}{}".format(files_directory_abs,
                                           mothu_config.get("file_globs",
                                                      "shared")))
    tax_sum_files_list = glob("{}{}".format(files_directory_abs,
                                            mothu_config.get("file_globs",
                                                       "tax_sum")))
    design_files_list = glob("{}{}".format(files_directory_abs,
                                           mothu_config.get("file_globs",
                                                      "design")))
# Make decision what to do based on file globs.
    if len(shared_files_list) > 1:
        if args.render_html is True:
            pass
        else:
            print("More than 1 shared files found. Quitting...")
            time.sleep(2)
            exit()
    elif len(shared_files_list) == 1:
        shared_file = shared_files_list[0]
        print("Found {} shared file".format(shared_file))
        if len(tax_sum_files_list) != 1:
            print("WARNING!!! No proper tax.summary file found. The analysis will be incomplete.")
            time.sleep(2)
            tax_sum_file = None
        else:
            tax_sum_file = tax_sum_files_list[0]
            print("Found {} tax.summary file".format(tax_sum_file))
        if len(design_files_list) != 0:
            if len(design_files_list) > 1:
                print("More than 1 design files found. Will skip this part of analysis.")
                time.sleep(2)
                design_file = None
            else:
                design_file = design_files_list[0]
        else:
            design_file = None
        if any([args.analysis_only, args.render_html]) is True:
            shared_info = mut.read_info_shared(shared_file)
            print("Found {} shared file".format(shared_file))
            time.sleep(2)
        elif any([args.analysis_only, args.render_html]) is False:
            print("Found shared file but you do not want to run the analysis on it. Running preprocessing would overwrite it. Quitting...")
            time.sleep(2)
            exit()
    elif len(shared_files_list) == 0:
        if any([args.analysis_only, args.render_html]) is True:
            print("No shared file found. Quitting...")
            time.sleep(2)
            exit()
        else:
            if os.path.isfile(align_database_abs) is False:
                print("No align database found in {}. Quitting...".format(align_database_abs))
                time.sleep(2)
                exit()
            if os.path.isfile(taxonomy_database_abs) is False:
                print("No taxonomy database found in {}. Quitting...".format(taxonomy_database_abs))
                time.sleep(2)
                exit()
            shared_file = None
            tax_sum_file = None
            design_file = None
    else:
        "I don't know what you what me to do!!! There are no files I can recognize in here!"
        time.sleep(2)
        exit()
# Set up alignment region cutting (if option was specified).
# Note that task must be done after original align_database_abs path check.
    if args.alignment_region:
        region = args.alignment_region.split("-")
        region_pos = False
        if len(region) == 2:
            try:
                if int(region[0]) < int(region[1]):
                    region_pos = region
                else:
                    print("Error: DB cut start position higher then the end one.")
            except:
                print("Error: DB alignment region coordinates contain both '-' and charaters different then numbers.")
        elif len(region) > 2:
            print("Wrong alignment customization specification: {}.".format(args.alignment_region))
        else: # len(region) == 1 case
            region_pos = mut.define_region_pos(args.alignment_region)
        if region_pos is False:
            print("Type proper region name/coordinates for db cutting or use already existing database.")
            time.sleep(2)
            exit()
        org_db_abs = align_database_abs
        cutted_db_tmp, align_database_abs = mut.dbcut_get_db_names(align_database_abs, args.alignment_region)
        region_start = region_pos[0]
        region_end = region_pos[1]
        dbcut_settings = {"cut_out": cutted_db_tmp, "org_db": org_db_abs, "region_start": region_start, "region_end": region_end}
        print("\nAlignment region custamization will be executed with",
        "the following parameters: \n",
        "original database: {},\n".format(org_db_abs),
        "region coordinates: {}-{}".format(region_start, region_end, cutted_db_tmp))
    else:
        dbcut_settings = False
# Get current time and create logfile.
    run_time_sig = "{}{}{}{}{}{}".format(time.localtime().tm_year,
                                         time.localtime().tm_mon,
                                         time.localtime().tm_mday,
                                         time.localtime().tm_hour,
                                         time.localtime().tm_min,
                                         time.localtime().tm_sec)
    logfile_name = "{}.{}.{}".format(files_directory_abs,
                                     args.job_name,
                                     run_time_sig)

    with open(logfile_name, "a") as fin:
        fin.write("{} was called with these arguments:\n\n".format(sys.argv[0]))
        for k, v in vars(args).items():
            if v is not None:
                fin.write("--{}: {}\n".format(k, v))
# Load preproc_template if args.analysis_only and args.render_html are False.
# Label must be from args.label.
# Rest of the variables must explicitly set to None or zero.
    if all([args.analysis_only, args.render_html]) is False:
        loaded_template = mut.load_template_file(preproc_template,
                                             searchpath=mut.get_dir_path("../templates"))
        label = args.label
        with open(logfile_name, "a") as fin:
            fin.write("\nTemplate used:\n\n{}".format(loaded_template))
# Load analysis_template if args.analysis_only is True.
# Label, number of samples and junk groups must be read from shared file.
    if args.analysis_only is True:
        loaded_template = mut.load_template_file(analysis_template,
                                             searchpath=mut.get_dir_path("../templates"))
        sampl_num = shared_info["samples_number"]
        label = shared_info["label"]
        junk_grps = shared_info["junk_grps"]
        print("Detected {} groups with {} label".format(sampl_num, label))
        time.sleep(2)
        if len(junk_grps) > 0:
            print("{} can distort the analysis due to size too small".format(junk_grps))
            time.sleep(2)
            if args.keep_all is True:
                print("All groups will be kept due to --keep-all argument")
                time.sleep(2)
                junk_grps = 0
            else:
                print("{} will be removed".format(junk_grps))
                time.sleep(2)
        with open(logfile_name, "a") as fin:
            fin.write("\nTemplate used:\n\n{}".format(loaded_template))
# Load output_template if args.render_html is True.
# All non-output-html variables must be read from shared file.
# Output-html varialbles must explicitly set.
    if args.render_html is True:
        loaded_template = mut.load_template_file(output_template,
                                             searchpath=mut.get_dir_path("../templates"))
        label = shared_info["label"]
        junk_grps = shared_info["junk_grps"]
        sampl_num = shared_info["samples_number"]
        krona_html = mut.parse_html("alpha/{}.krona.html".format(args.job_name),
                                html_type="krona")
        sum_html = mut.parse_html("alpha/{}.sum.html".format(args.job_name),
                              html_type="summary")
        raref_html = mut.parse_html("alpha/{}.raref.html".format(args.job_name),
                                html_type="rarefaction")
        if sampl_num > 1:
            nmds_jc_html = mut.parse_html("beta/{}.jclass.nmds.html".format(args.job_name),
                                      html_type="nmds")
            nmds_th_html = mut.parse_html("beta/{}.thetayc.nmds.html".format(args.job_name),
                                      html_type="nmds")
        with open(logfile_name, "a") as fin:
            fin.write("\nTemplate used:\n\n{}".format(loaded_template))
# Pass all the variables to template and render to str.
    template_vars = {"files_directory": files_directory_abs,
                     "output_dir": output_dir_abs,
                     "job_name": args.job_name,
                     "run": args.run,
                     "processors": processors,
                     "slurm_setting": slurm_setting,
                     "dbcut_settings": dbcut_settings,
                     "max_ambig": args.max_ambig,
                     "max_homop": args.max_homop,
                     "min_length": args.min_length,
                     "max_length": args.max_length,
                     "min_overlap": args.min_overlap,
                     "screen_criteria": args.screen_criteria,
                     "chop_length": args.chop_length,
                     "precluster_diffs": args.precluster_diffs,
                     "chimera_dereplicate": args.chimera_dereplicate,
                     "classify_seqs_cutoff": args.classify_seqs_cutoff,
                     "classify_ITS": args.classify_ITS,
                     "align_database": align_database_abs,
                     "taxonomy_database": taxonomy_database_abs,
                     "design_file": design_file,
                     "cluster_cutoff": args.cluster_cutoff,
                     "cluster_method": args.cluster_method,
                     "full_ram_load": args.full_ram_load,
                     "label": label,
                     "remove_rare_nseq": args.remove_rare_nseq,
                     "junk_grps": junk_grps,
                     "notify_email": args.notify_email,
                     "sampl_num": sampl_num,
                     "shared_file": shared_file,
                     "tax_sum_file": tax_sum_file,
                     "w3_css": w3_css,
                     "datatables_css": datatables_css,
                     "datatables_js": datatables_js,
                     "slideshow_js": slideshow_js,
                     "krona_html": krona_html,
                     "sum_html": sum_html,
                     "raref_html": raref_html,
                     "nmds_jc_html": nmds_jc_html,
                     "nmds_th_html": nmds_th_html,
                     "exclude_krona": args.exclude_krona}
    rendered_template = mut.render_template(loaded_template,
                                        template_vars)
# Save template as bash script of HTML file depending on args.render_html value.
    if args.render_html is True:
        mut.save_template("{}.html".format(args.job_name), rendered_template)
    else:
        mut.save_template("{}{}.sh".format(output_dir_abs, args.job_name),
                      rendered_template)
# Run outputted script or not depending on args.run and args.dry-run
    if args.run is not None and args.dry_run is not True:
        os.system("{} {}".format(args.run, "{}{}.sh".format(output_dir_abs,
                                                            args.job_name)))


if __name__ == "__main__":
    main()
