#!/usr/bin/env python3
from docopt import docopt
from sys import stderr
from inspect import getfullargspec
from re import sub, search
import edgecaselib


__doc__ = """edgeCase: a telomere analysis pipeline

Usage: {0} [-h | --help]
       {0} <command> [<args>...]

Commmands (<command>):
    tailpuller               select overhanging long reads
    tailchopper              get overhanging heads/tails of long reads
    repeatfinder             discover enriched repeats in candidate sequences
    kmerscanner              perform scan of known kmers/motifs
    densityplot              visualize densities of candidate motifs

Development area:
    entropy                  calculate motif entropy among long reads
    levenshtein              calculate pairwise edit distance among long reads
"""


def postprocess_docopt(submodule, docopt_dict, __command_doc__):
    """Interpret and validate aruments returned by docopt"""
    kwargs = {
        sub(r'^[<>-]+|[<>-]+$', "", k).replace("-", "_"): v
        for k, v in docopt_dict.items() if search(r'[^<>-]', k)
    }
    for converter in getattr(submodule, "__docopt_converters__", []):
        converter_arg_names = getfullargspec(converter).args
        if len(converter_arg_names) != 1:
            error_mask = "Incorrect argument converter for: {}"
            exit(error_mask.format(", ".join(converter_arg_names)))
        elif converter_arg_names[0] not in kwargs:
            error_mask = "Unknown converter argument: {}"
            exit(error_mask.format(converter_arg_names[0]))
        else:
            key = converter_arg_names[0]
            try:
                kwargs[key] = converter(kwargs[key])
            except Exception:
                exit(__command_doc__)
    for test, error in getattr(submodule, "__docopt_tests__", {}).items():
        test_arg_names = getfullargspec(test).args
        test_arguments = [kwargs[k] for k in test_arg_names]
        if not test(*test_arguments):
            if error:
                exit("Error: " + error.format(*test_arguments))
            else:
                exit("Could not validate: {}".format(", ".join(test_arg_names)))
    return kwargs


def main(module):
    """Dispatch command line arguments to subroutines (commands)"""
    dispatcher_dict = docopt(__doc__.format(__file__), options_first=True)
    command, raw_args = dispatcher_dict["<command>"], dispatcher_dict["<args>"]
    if (command is not None) and (command[0] != "_"):
        submodule = getattr(module, command.replace("-", "_"), None)
        submodule_entrypoint = getattr(submodule, "main", None)
        if submodule_entrypoint:
            submodule_warning = getattr(submodule, "__warning__", None)
            if submodule_warning:
                print("WARNING:", submodule_warning.strip(), file=stderr)
            __command_doc__ = submodule.__doc__.lstrip().format(
                __file__, " "*len(__file__),
            )
            docopt_dict = docopt(__command_doc__, argv=[command, *raw_args])
            kwargs = postprocess_docopt(submodule, docopt_dict, __command_doc__)
            return submodule_entrypoint(**kwargs)
    print(__doc__.format(__file__).lstrip(), file=stderr)
    return 1


if __name__ == "__main__":
    returncode = main(edgecaselib)
    exit(returncode)
