import sys
import os
import subprocess
import textwrap

# directory with text files for additional help topics
DOC_BASE = os.path.join(os.path.dirname(__file__), 'help_topics')


# mimodd subcommands along with their help strings
# as displayed by mimodd --help
help_commands = {
    'info': 'retrieve information about the samples encoded in a file for '
            'various supported formats',
    'header': 'generate a SAM format header from an NGS run description',
    'convert': 'convert between different sequenced reads file formats',
    'reheader': 'from a BAM file generate a new file with specified header '
                'sections modified based on the header of a template SAM file',
    'sort': 'sort a SAM or BAM file by coordinates (or names) of the mapped '
            'reads',
    'snap': 'align sequence reads using the SNAP aligner',
    'snap-batch': 'run several snap jobs and pool the resulting alignments '
                  'into a multi-sample SAM/BAM file',
    'index': 'generate fasta, bam or snap index files for use with downstream '
             'or external tools',
    'varcall': 'predict SNPs and indels in one or more aligned read samples '
               'and calculate the coverage of every base in the reference '
               'genome using samtools/bcftools',
    'varextract': 'extract variant sites from BCF input as generated by '
                  'varcall and report them in VCF',
    'covstats': 'summary coverage statistics for varcall output',
    'delcall': 'predict deletions in one or more samples of aligned paired-end '
               'reads based on coverage of the reference genome and on insert '
               'sizes',
    'rebase': 'rebase the variant positions in a VCF file on a different '
              'reference coordinate system according to a UCSC chain file',
    'vcf-filter': 'extract lines from a vcf variant file based on sample- and '
                  'field-specific filters',
    'annotate': 'annotate the variants from a VCF file with information about '
                'the affected genes',
    'varreport': 'report the variants from a VCF file in a user-friendly form',
    'snpeff-genomes': 'list installed SnpEff genomes',
    'map': 'perform a linkage analysis between a selected phenotype and '
           'identified variants',
    'version': 'display version and copyright information',
    'help': 'show help for a given topic or command',
    }

# mimodd administrative tools with simple help strings
help_admin = {'config': 'the MiModD.config tool',
              'upgrade': 'the MiModD.upgrade tool',
              'enablegalaxy': 'the MiModD.enablegalaxy tool',
              }

# mimodd in-development tools with simple help strings
help_devtools = {'sanitize': 'the MiModD.sanitize tool',
                 }

# additional help topics with simple help strings and location of
# corresponding doc files
help_topics = {
    'configure': {
        'summary': 'Configuring MiModD',
        'doc': 'config.txt'
        },
    'updates': {
        'summary': 'Keeping MiModD up to date',
        'doc': 'upgrade.txt'
        },
    'galaxy': {
        'summary': 'Setting up Galaxy for integration of MiModD',
        'doc': 'install_galaxy.txt'
        },
    'fileformats': {
        'summary': 'Specifications of file formats supported by MiModD',
        'doc': 'fileformats.txt'
        },
    }
               

def help_formatter (col1_width):
    """Format help section records as two columns."""
    
    hanging_indent = ' ' * (col1_width+1)
    formatted_string = ''
    while True:
        command, help_string = yield formatted_string
        formatted_string = textwrap.fill(
            help_string,
            initial_indent=' {0:<{1}}'.format(command, col1_width),
            subsequent_indent=hanging_indent
            )


def print_help_section (section, title, summary_key = None):
    """Print a help section.

    A section should be one of the module-global help_* dictionaries.
    If summary_key is given, it indicates that the section object is a nested
    dictionary, in which each value is a dictionary with a key summary_key that
    can be used to retrieve the help summary. Otherwise the dictionary values
    themselves are assumed to represent the help summary.
    """

    # The longest topic name in the section determines the width of the first
    # column.
    col1_width = max(len(topic) for topic in section) + 8
    formatter = help_formatter(col1_width)
    # Retrieve topic/summary pairs from the section dictionary
    # according to summary_key.
    if summary_key is None:
        it = sorted(section.items())
    else:
        it = ((topic, help_source[summary_key])
              for topic, help_source in sorted(section.items())
              )
    print(title + ':')
    print(next(formatter))
    for topic, summary in it:
        print(formatter.send((topic, summary)))
    formatter.close()
    print()


def help (args, parser):
    if args.topic is None:
        # mimodd help
        # display general help
        print_help_section(help_commands, 'MiModD commands')
        print_help_section(help_devtools, 'MiModD in-development tools')
        print_help_section(help_admin, 'MiModD administrative tools')
        print_help_section(
            help_topics, 'other help topics', 'summary'
            )
    elif args.topic in help_commands:
        # mimodd help subcommand
        # display subcommand help by reparsing
        # mimodd subcommand --help
        print('MiModD {0} command'.format(args.topic))
        print()
        print(textwrap.fill(help_commands[args.topic]))
        print()
        args = parser.parse_args([args.topic, '--help'])
    elif args.topic in help_admin or args.topic in help_devtools:
        # mimodd help tool
        # display help for a module-based tool
        # by running python3 -m MiModD.tool --help as a subprocess
        print('MiModD.{0} tool'.format(args.topic))
        print()
        print('Basic invocation:        python3 -m MiModD.{0}'
              .format(args.topic))
        print(' followed by any of the tool-specific arguments below.')
        print()
        print(textwrap.fill(
            'Note: You may need to replace "python3" in the above command with '
            'the name of the Python 3 interpreter that was used to install '
            'MiModD!'
            ))
        print()
        print()
        help_string = subprocess.check_output(
            [sys.executable, '-m', 'MiModD.{0}'.format(args.topic), '--help'],
            universal_newlines=True
            )
        print(help_string)
    elif args.topic in help_topics:
        # mimodd help topic
        # display help on an additional topic
        # read from a doc file
        print(textwrap.fill(help_topics[args.topic]['summary']))
        print()
        doc_file = help_topics[args.topic]['doc']
        if doc_file is None:
            print(
                'Our apologies, but this section of the help system needs yet '
                'to be written'
                )
        else:
            doc_location = os.path.join(DOC_BASE, doc_file)
            with open(doc_location, encoding='utf-8') as i:
                print(i.read())
    else:
        # give up
        print('No help available for topic "{0}"'.format(args.topic))
