#!/usr/bin/env python3
#-*- coding: utf-8 -*-

"""
Created on Sun Jul 24 19:33:37 2016

See README.md for more info and usage
"""

import argparse
import sys
import time
import os
import shutil
import pkg_resources

try:  # development mode
    from _version import __version__
except ImportError:  # ie, if an installed pkg from pip or other using setup.py
    __version__ = pkg_resources.require("riboSeed")[0].version

def get_args():  # pragma: no cover
    parser = argparse.ArgumentParser(
        description="Given cluster file of rDNA regions from riboSelect and " +
        "either paired-end or single-end reads, assembles the mapped reads " +
        "into pseduocontig 'seeds', and uses those with the reads to run" +
        "de fere novo and de novo assembly with SPAdes",
        add_help=True)
    parser.add_argument("-o", "--outdir", dest='outdir', action="store",
                        help="output directory; " +
                        "default: %(default)s", default=os.getcwd(),
                        type=str, required=False)
    parser.add_argument("-n", "--name", dest='name', action="store",
                        help="name of config file; " +
                        "default: timestamped", default=None,
                        type=str, required=False)
    args = parser.parse_args()
    return args


def make_config_header():
    hashbang = ["#!/usr/bin/env python3",
                "#-*- coding: utf-8 -*-"]
    copy_header = [
        "# Copyright 2017, National University of Ireland and The James Hutton Insitute",
        "# Author: Nicholas Waters",
        "#",
        "# This code is part of the riboSeed package, and is governed by its licence.",
        "# Please see the LICENSE file that should have been included as part of",
        "# this package.\n\n"]
    t0 = time.asctime()
    timestamp = "# this config file was generated " + str(t0) + "\n\n"
    hashbang.extend(copy_header)
    hashbang.append(timestamp)
    return(hashbang)


def config_exes():
    # find all needed system requiremnts
    req_programs = [("BARRNAP_EXE", "barrnap"),
                    ("SEQRET_EXE", "seqret"),
                    ("SPADES_EXE", "spades.py"),
                    ("BWA_EXE", "bwa"),
                    ("SAMTOOLS_EXE", "samtools"),
                    ("BALST_EXE", "blastn"),
                    ("MAUVE_ALIGNER", "mauveAligner")]
    config_lines = [
        "#------------------------#",
        "##  Required programs   ##",
        "#------------------------#"]
    for k, v in req_programs:
        config_lines.append("# executable for " + v)
        if shutil.which(v):
            config_lines.append(k + " = '" + shutil.which(v) + "'\n")
        else:
            config_lines.append(k + " = None\n" )

    # # find all optional sys requirements
    opt_programs = [("QUAST_EXE", "quast.py"),
                    ("SMALT_EXE", "smalt")]
    config_lines.extend([
        "#------------------------#",
        "##  Optional programs   ##",
        "#------------------------#"])
    for k, v in opt_programs:
        config_lines.append("# executable for " + v)
        if shutil.which(v):
            config_lines.append(k + " = '" + shutil.which(v) + "'\n")
        else:
            config_lines.append(k + " = None\n" )
    return config_lines


def config_scan_defaults():
    scan_params = [("SCAN_ID_THRESH", "0.5",
                    "--id_thresh: partial rRNA hits below this threshold will be ignored"),
                   ("SCAN_CONTIG_NAME", "None",
                    "--name: stem to give the files generated by riboScan  "),
                   ("SCAN_MIN_LENGTH", "0",
                    "--min_length: skip annotating if contig shorter than this"),
                   ("SCAN_VERBOSITY", "2",
                    "-v: verbosity for riboScan")]
    scan_lines = [
        "#------------------------#",
        "##  riboScan Parameters ##",
        "#------------------------#"]
    for k, v, h in scan_params:
        scan_lines.append("# " + h)
        scan_lines.append(k + " = " + v + "\n")
    return scan_lines


def config_select_defaults():
    select_params = [
        ("SELECT_FEATURE", "'rRNA'",
         "--feature: which annotations to pay attention to; \n# " +
         "barrnap uses 'rRNA', but others may use 'RRNA', etc"),
        ("SELECT_SPECIFIC_FEATURES", "'16S:23S:5S'",
         "--specific_features: specific features to use; \n#" +
         "if not assembling a prokaryote, or if refernce is \n# " +
         "missing a subunit's annotation, adjust this as needed."),
        ("SELECT_VERBOSITY", "2",
         "-v: verbosity for riboSelect")]
    select_lines = [
        "#------------------------#",
        "##  riboSelect Parameters ##",
        "#------------------------#"]
    for k, v, h in select_params:
        select_lines.append("# " + h)
        select_lines.append(k + " = " + v + "\n")
    return select_lines


def config_seed_defaults():
    seed_params = [
        ("SEED_MAP_METHOD", "'bwa'",
         "--method_for_map: which mapper to use, (default bwa)"),
        ("SEED_SCORE_MIN", "None",
         "--score_min: If using smalt, this sets the '-m' param; \n\n#" +
         "default with smalt is inferred from \n\n#" +
         "read length. If using BWA, reads mapping with AS\n\n#" +
         "score lower than this will be rejected\n\n#" +
         "; default with BWA is half of read length\n"),
        ("SEED_MIN_ASSEMBLY_LENGTH", "6000",
         "if initial SPAdes assembly largest contig \n#" +
         "is not at least as long as --min_assembly_len, \n#" +
         "reject. Set this to the length of the seed \n#" +
         "sequence; if it is not achieved, seeding across \n#" +
         "regions will likely fail; default: %(default)s"),
        ("SEED_INCLUDE_SHORTS", "False",
         "if assembled contig is smaller than --min_assembly_len, contig\n#" +
         "will still be included in assembly; default: inferred"),
        ("SEED_SUBTRACT", "False",
         "if --subtract reads already used in previous\n#" +
         "round of subassembly will not be included in \n#" +
         "subsequent rounds.  This can lead to problems \n#" +
         "with multiple mapping and inflated coverage."),
        ("SEED_SKIP_CONTROL", "False",
         "if --skip_control, no de novo \n#" +
         "assembly will be done; default: %(default)s"),
        ("SEED_REF_AS_CONTIG", "None",
         "if 'trusted', SPAdes will  use the seed \n#" +
         "sequences as a --trusted-contig; if 'untrusted', \n#" +
         "SPAdes will treat as --untrusted-contig. if '', \n#" +
         "seeds will not be used during assembly. \n#" +
         "See SPAdes docs; default: if mapping \n#" +
         "percentage over 80%%: 'trusted', else 'untrusted'"),
        ("SEED_TARGET_LEN", "None",
         "if set, iterations will continue until \n#" +
         "contigs reach this length, or max iterations (\n#" +
         "set by --iterations) have been completed. Set as \n#" +
         "fraction of original seed length by giving a \n#" +
         "decimal between 0 and 5, or set as an absolute \n#" +
         "number of base pairs by giving an integer greater\n#" +
         " than 50. Not used by default"),
        ("SEED_MAPPER_ARGS", "'-L 0,0 -U 0 -a'",
         "submit custom parameters to mapper. \n#" +
         "And by mapper, I mean bwa, cause we dont support \n#" +
         "this option for SMALT, sorry. \n#" +
         "This requires knowledge of your chosen mapper's \n#" +
         "optional arguments. Proceed with caution!"),
        ("SEED_SMALT_SCORING", "'match=1,subst=-4,gapopen=-4,gapext=-3'",
         "if mapping with SMALT, \n#" +
         "submit custom smalt scoring via smalt -S \n#" +
         "scorespec option"),
        ("SEED_VERBOSITY", "2",
         "-v: verbosity for riboSeed")]
    seed_lines = [
        "#------------------------#",
        "##  riboSeed Parameters ##",
        "#------------------------#"]
    for k, v, h in seed_params:
        seed_lines.append("# \n#" + h)
        seed_lines.append(k + " = " + v + "\n")
    return seed_lines


def config_bug():
    pass


def write_config(header, outfile):
    with open(outfile, "w") as of:
        for hline in header:
            of.write(hline)
            of.write("\n")


def append_config(lines, outfile):
    with open(outfile, "a") as of:
        for line in lines:
            of.write(line)
            of.write("\n")


def main(args):
    header = make_config_header()
    if args.name is None:
        outfile = os.path.join(
            os.path.abspath(os.path.expanduser(args.outdir)),
            str(time.strftime("%Y-%m-%dT%H:%M") +
                "_riboSeed_config.py"))
    else:
        outfile = os.path.join(
            os.path.abspath(os.path.expanduser(args.outdir)),
            str(args.name + ".py"))
    write_config(header=header, outfile=outfile)
    #exes
    append_config(lines=config_exes(), outfile=outfile)
    # riboScan
    append_config(lines=config_scan_defaults(), outfile=outfile)
    # riboSelect
    append_config(lines=config_select_defaults(), outfile=outfile)
    # riboSeed
    append_config(lines=config_seed_defaults(), outfile=outfile)
    # this lines allows run_riboseed to find the path to the new config
    sys.stdout.write(outfile)
    # this line allows us to just grab the main function in run_riboSeed
    return outfile

if __name__ == "__main__":
    args = get_args()
    main(args)
