# -*- coding: utf-8
# pylint: disable=line-too-long

"""Lots of under-the-rug, operational garbage in here. Run. Run away.."""

import os
import sys
import copy
import pkg_resources


# Make sure the Python environment hasn't changed since the installation (happens more often than you'd think
# on systems working with multiple Python installations that are managed through modules):
try:
    if sys.version_info < (2, 7, 5):
        v = '.'.join([str(x) for x in sys.version_info[0:3]])
        sys.stderr.write("Your active Python version is '%s'. Anything less than '2.7.5' will not do it for anvi'o :/\n" % v)
        sys.exit(-1)
except Exception:
    sys.stderr.write("(anvi'o failed to learn about your Python version, but it will pretend as if nothing happened)\n\n")


# a comprehensive arguments dictionary that provides easy access from various programs that interface anvi'o modules:
D = {
    'profile-db': (
            ['-p', '--profile-db'],
            {'metavar': "PROFILE_DB",
             'required': True,
             'help': "Anvi'o profile database"}
                ),
    'serialized-profile': (
            ['-d', '--serialized-profile'],
            {'metavar': "PROFILE",
             'help': "Serialized profile (PROFILE.cp). You can use anvi'o serialized profile files to re-do the\
                      profiling much more quickly. This file is generated only if it is requested during the\
                      initial profiling of the BAM file. See '--gen-serialized-profile' flag for details."}
                ),
    'blank-profile': (
            ['--blank-profile'],
            {'default': False,
             'action': 'store_true',
             'help': "If you only have contig sequences, but no mapping data (i.e., you found a genome and would like to\
                      take a look from it), this flag will become very hand. After creating a contigs database for your\
                      contigs, you can create a blank anvi'o profile database to use anvi'o interactive\
                      interface with that contigs database without any mapping data."}
                ),
    'samples-information-db': (
            ['-s', '--samples-information-db'],
            {'metavar': 'SAMPLES_DB',
             'help': "Samples information database generated by 'anvi-gen-samples-info-database'"}
                ),
    'contigs-db': (
            ['-c', '--contigs-db'],
            {'metavar': 'CONTIGS_DB',
             'required': True,
             'help': "Anvi'o contigs database generated by 'anvi-gen-contigs'"}
                ),
    'runinfo': (
            ['-r', '--runinfo'],
            {'metavar': 'RUNINFO_PATH',
             'required': True,
             'help': "Anvi'o runinfo file path."}
                ),
    'additional-view': (
            ['-V', '--additional-view'],
            {'metavar': 'ADDITIONAL_VIEW',
             'help': "A TAB-delimited file for an additional view to be used in the interface. This\
                      file file should contain all split names, and values for each of them in all\
                      samples. Each column in this file must correspond to a sample name. Content\
                      of this file will be called 'user_vuew', which will be available as a new item\
                      in the 'views' combo box in the interface"}
                ),
    'fasta-file': (
            ['-f', '--fasta-file'],
            {'metavar': 'FASTA',
             'help': "A FASTA-formatted input file"}
                ),
    'samples-information': (
            ['-D', '--samples-information'],
            {'metavar': 'SAMPLES-INFO',
             'help': "A TAB-delimited file with information about samples in your dataset. Each row in this\
                      file must correspond to a sample name. Each column must contain a unique attribute.\
                      Please refer to the documentation to learn more about the structure and purpose of\
                      this file."}
                ),
    'samples-order': (
            ['-R', '--samples-order'],
            {'metavar': 'SAMPLES-ORDER',
             'help': "A TAB-delimited file with three columns: 'attribute', 'basic', 'newick'. For each attribute,\
                      the order of samples must be defined either in the 'basic' form or via a 'newick'-formatted\
                      tree structurei that describes the organization of each sample. Anvi'o will look for a\
                      comma-separated list of sample names for the 'basic' form. Please refer to the online docs\
                      for more info. Also you shouldn't hesitate to try to find the right file format until you get\
                      it working. There are stringent checks on this file, and you will not break anything while trying!."}
                ),
    'split-length': (
            ['-L', '--split-length'],
            {'metavar': 'INT',
             'default': 20000,
             'type': int,
             'help': "Splitting very large contigs into multiple pieces improves the efficacy of the\
                      visualization step. The default value is (%(default)d). If you are not sure, we\
                      advise you to not go below 10,000. The lower you go, the more complicated the\
                      tree will be, and will take more time and computational resources to finish the\
                      analysis. Also this is not a case of 'the smaller the split size the more sensitive\
                      the results'. If you do not want your contigs to be split, you can either simply\
                      enter '0' or ANY OTHER negative integer (lots of unnecessary freedom here, enjoy!)."}
                ),
    'kmer-size': (
            ['-K', '--kmer-size'],
            {'metavar': 'INT',
             'default': 4,
             'type': int,
             'help': "K-mer size for k-mer frequency calculations. The default k-mer size for composition-based\
                      analyses is 4, historically. Although tetra-nucleotide frequencies seem to offer the\
                      the sweet spot of sensitivity, information density, and manageable number of dimensions\
                      for clustering approaches, you are welcome to experiment (but maybe you should leave\
                      it as is for your first set of analyses)."}
                ),
    'skip-gene-calling': (
            ['--skip-gene-calling'],
            {'default': False,
             'action': 'store_true',
             'help': "By default, generating an anvi'o contigs database includes the identification of open reading\
                      frames in contigs by running a bacterial gene caller. Declaring this flag will by-pass that\
                      process. If you prefer, you can later import your own gene calling results into the database."}
                ),
    'external-gene-calls': (
            ['--external-gene-calls'],
            {'metavar': 'GENE-CALLS',
             'help': "A TAB-delimited file to utilize external gene calls. The file must have these columns: 'gene_callers_id'\
                      (a unique integer number for each gene call, start from 1), 'contig' (the contig name the gene call is found),\
                      'start' (start position, integer), 'stop' (stop position, integer), 'direction' (the direction of the gene open reading\
                      frame; can be 'f' or 'r'), 'partial' (whether it is a complete gene call, or a partial one; must be 1 for partial\
                      calls, and 0 for complete calls), 'source' (the gene caller), and 'version' (the version of the gene caller, i.e.,\
                      v2.6.7 or v1.0). An example file can be found via the URL https://goo.gl/TqCWT2"}
                ),
    'skip-SNV-profiling': (
            ['--skip-SNV-profiling'],
            {'default': False,
             'action': 'store_true',
             'help': "By default, anvi'o characterizes single-nucleotide variation in each sample. The use of this flag\
                      will instruct profiler to skip that step. Please remember that parameters and flags must be\
                      identical between different profiles using the same contigs database for them to merge properly."}
                ),
    'profile-AA-frequencies': (
            ['--profile-AA-frequencies'],
            {'default': False,
             'action': 'store_true',
             'help': "Anvi'o can characterize linkmer frequencies for AA distribution in genes in contigs during\
                      profiling. However, due to its computational complexity, this feature is by default off. Using\
                      this flag you can go against the authority, and make anvi'o do it. Please remember that this\
                      functionality is available only if genes calls are present in contigs database."}
                ),
    'drop-previous-annotations': (
            ['--drop-previous-annotations'],
            {'default': False,
             'action': 'store_true',
             'help': "Use this flag if you want anvi'o to remove all previous functional annotations for your genes,\
                      and then import the new data. The default behavior is to add the new annotations incrementally."}
                ),
    'skip-mindful-splitting': (
            ['--skip-mindful-splitting'],
            {'default': False,
             'action': 'store_true',
             'help': "By default, anvi'o attempts to prevent soft-splitting large contigs by cutting prper gene calles\
                      to make sure a single gene is not broken into multiple splits. This requires a careful\
                      examination of where genes start and end, and to find best locations to split contigs with respect\
                      to this informtion. So, when the user asks for a split size of, say, 1,000, it serves as a\
                      mere suggestion. When this flag is used, anvi'o does what the user wants and creates splits at\
                      desired lengths (although some functionality may become unavailable for the projects that rely on\
                      a contigs database that is initiated this way)."}
                ),
    'contigs-fasta': (
            ['-f', '--contigs-fasta'],
            {'metavar': 'FASTA',
             'required': True,
             'help': "The FASTA file that contains reference sequences you mapped your samples against. This\
                      could be a reference genome, or contigs from your assembler. Contig names in this file\
                      must match to those in other input files. If there is a problem anvi'o will gracefully\
                      complain about it."}
                ),
    'view-data': (
            ['-d', '--view-data'],
            {'metavar': 'VIEW_DATA',
             'help': "A TAB-delimited file for view data"}
                ),
    'tree': (
            ['-t', '--tree'],
            {'metavar': 'NEWICK',
             'help': "NEWICK formatted tree structure"}
                ),
    'additional-layers': (
            ['-A', '--additional-layers'],
            {'metavar': 'ADDITIONAL_LAYERS',
             'help': "A TAB-delimited file for additional layers for splits. The first column of this file\
                      must be split names, and the remaining columns should be unique attributes.\
                      The file does not need to contain all split names, or values for each split in\
                      every column. Anvi'o will try to deal with missing data nicely. Each column in this\
                      file will be visualized as a new layer in the tree."}
                ),
    'view': (
            ['--view'],
            {'metavar': 'NAME',
             'help': "Start the interface with a pre-selected view. To see a list of available views,\
                      use --show-views flag."}
                ),
    'table': (
            ['--table'],
            {'metavar': 'TABLE_NAME',
             'help': "Table name to export."}
                ),
    'fields': (
            ['-f', '--fields'],
            {'metavar': 'FIELD(S)',
             'help': "Fields to report. USe --list-tables parameter with a table name to see available\
                      fields  You can list fields using this notation: --fields 'field_1, field_2, ... field_N'."}
                ),
    'list': (
            ['-l', '--list'],
            {'default': False,
             'action': 'store_true',
             'help': "Gives a list of tables in a database and quits. If a table is already declared\
                      this time it lists all the fields in a given table, in case you would to export\
                      only a specific list of fields from the table using --fields parameter."}
                ),
    'title': (
            ['--title'],
            {'metavar': 'NAME',
             'help': "Title for the interface. If you are working with a RUNINFO dict, the title\
                      will be determined based on information stored in that file. Regardless,\
                      you can override that value using this parameter. If you are not using a\
                      anvio RUNINFO dictionary, a meaningful title will appear in the interface\
                      only if you define one using this parameter."}
                ),
    'split-hmm-layers': (
            ['--split-hmm-layers'],
            {'default': False,
             'action': 'store_true',
             'help': "When declared, this flag tells the interface to split every gene found in HMM\
                      searches that were performed against non-singlecopy gene HMM profiles into\
                      their own layer. Please see the documentation for details."}
                ),
    'show-outlier-snvs': (
            ['--show-outlier-SNVs'],
            {'default': False,
             'action': 'store_true',
             'help': "During profiling, anvi'o marks positions of single-nucleotide variations (SNVs)\
                      that originate from places in contigs where coverage values are a bit 'sketchy'.\
                      By default, when you inspect a split in applicable projects, the interface does\
                      not show SNVs marked as outlier. Decleration of this flag changes that behavior,\
                      and tells anvi'o to show anything and everything reported (There may or may not\
                      be some historical data on this here: https://github.com/meren/anvio/issues/309)."}
                ),
    'hmm-sources': (
            ['--hmm-sources'],
            {'metavar': 'SOURCE NAME',
             'help': "Get sequences for a specific list of HMM sources. You can list one or more\
                      sources by separating them from each other with a comma character (i.e., \
                      '--hmm-sources source_1,source_2,source_3'). If you would like to see a list\
                      of available sources in the contigs database, run this program with\
                      '--list-available-hmm-sources' flag."}
                ),
    'list-available-hmm-sources': (
            ['-l', '--list-available-hmm-sources'],
            {'default': False,
             'action': 'store_true',
             'help': "List available HMM sources in the profile database and quit."}
                ),
    'gene-names': (
            ['--gene-names'],
            {'metavar': 'HMM HIT NAME',
             'help': "Get sequences only for a specific gene name. Each name should be separated from\
                      each other by a comma character. For instance, if you want to get back only RecA\
                      and Ribosomal_L27, you can type '--gene-names RecA,Ribosomal_L27', and you will\
                      get any and every hit that matches these names in any source. If you would like\
                      to see a list of available gene names, you can use '--list-available-gene-names'\
                      flag."}
                ),
    'list-available-gene-names': (
            ['-L', '--list-available-gene-names'],
            {'default': False,
             'action': 'store_true',
             'help': "List available gene names in HMM sources selection and quit."}
                ),
    'search-terms': (
            ['--search-terms'],
            {'metavar': 'SEARCH_TERMS',
             'help': "Search terms. Multiple of them can be declared separated by a delimiter (the default is a comma)."}
                ),
    'gene-caller-ids': (
            ['--gene-caller-ids'],
            {'metavar': 'GENE_CALLER_IDS',
             'help': "Gene caller ids. Multiple of them can be declared separated by a delimiter (the default is a comma).\
                      If you declare nothing, you may get everything. Or you may get an error. Really depends on the\
                      situation. Worth a try."}
                ),
    'gene-caller-id': (
            ['--gene-caller-id'],
            {'metavar': 'GENE_CALLER_ID',
             'type': int,
             'help': "A single gene id."}
                ),
    'delimiter': (
            ['--delimiter'],
            {'metavar': 'CHAR',
             'default': ',',
             'help': "The delimiter to parse multiple input terms. The default is '%(default)s'."}
                ),
    'wrap': (
            ['--wrap'],
            {'metavar': 'WRAP',
             'default': 120,
             'type': int,
             'help': "When to wrap sequences when storing them in a FASTA file. The default is\
                      '%(default)d'. A value of '0' would be equivalent to 'do not wrap'."}
                ),
    'leeway': (
            ['--leeway'],
            {'metavar': 'LEEWAY_NTs',
             'default': 100,
             'type': int,
             'help': "The minimum number of nucleotides for a given short read mapping into\
                      the gene context for it to be reported. You must consider the length of\
                      your short reads, as well as the length of the gene you are targeting.\
                      The default is %(default)d nts."}
                ),
    'gen-serialized-profile': (
            ['--gen-serialized-profile'],
            {'default': False,
             'action': 'store_true',
             'help': "When declared, anvi'o will store the profiling results in a serialized object that can be used for quick\
                      re-profiling. However, this object can get very large, and take a lot of space on disk. It is essentially\
                      useful for testing purposes, and for people who like to hack things."}
                ),
    'list-contigs': (
            ['--list-contigs'],
            {'default': False,
             'action': 'store_true',
             'help': "When declared, the program will list contigs in the BAM file and exit gracefully\
                      without any further analysis."}
                ),
    'list-collections': (
            ['--list-collections'],
            {'default': False,
             'action': 'store_true',
             'help': "Show available collections and exit."}
                ),
    'show-views': (
            ['--show-views'],
            {'default': False,
             'action': 'store_true',
             'help': "When declared, the program will show a list of available views, and exit."}
                ),
    'list-completeness-sources': (
            ['--list-completeness-sources'],
            {'default': False,
             'action': 'store_true',
             'help': "Show available sources and exit."}
                ),
    'completeness-source': (
            ['--completeness-source'],
            {'metavar': 'NAME',
             'help': "Single-copy gene source to use to estimate completeness."}
                ),
    'splits-of-interest': (
            ['--splits-of-interest'],
            {'metavar': 'FILE',
             'help': "A file with split names. There should be only one column in the file, and each line\
                      should correspond to a unique split name."}
                ),
    'contigs-of-interest': (
            ['--contigs-of-interest'],
            {'metavar': 'FILE',
             'help': "It is possible to analyze only a group of contigs from a given BAM file. If you provide\
                      a text file, in which every contig of interest is listed line by line, the profiler would\
                      engine only on those contigs in the BAM file and ignore the rest. This can be used for\
                      debugging purposes, or to engine on a particular group of contigs that were identified as\
                      relevant during the interactive analysis."}
                ),
    'samples-of-interest': (
            ['--samples-of-interest'],
            {'metavar': 'FILE',
             'help': "A file with samples names. There should be only one column in the file, and each line\
                      should correspond to a unique sample name (without a column header)."}
                ),
    'genes-of-interest': (
            ['--genes-of-interest'],
            {'metavar': 'FILE',
             'help': "A file with anvi'o gene caller IDs. There should be only one column in the file, and each line\
                      should correspond to a unique gene caller id (without a column header)."}
                ),
    'bin-id': (
            ['-b', '--bin-id'],
            {'metavar': 'BIN_NAME',
             'help': "Bin name you are interested in."}
                ),
    'bin-ids-file': (
            ['-B', '--bin-ids-file'],
            {'metavar': 'FILE_PATH',
             'help': "Text file for bins (each line should be a unique bin id)."}
                ),
    'collection-name': (
            ['-C', '--collection-name'],
            {'metavar': 'COLLECTION_NAME',
             'help': "Collection name."}
                ),
    'num-positions-from-each-split': (
            ['--num-positions-from-each-split'],
            {'metavar': 'INT',
             'default': 0,
             'type': int,
             'help': "Each split may have one or more variable positions. By default, anvi'o will report every SNV\
                      position found in a given split. This parameter will help you to define a cutoff for the maximum\
                      number of SNVs to be reported from a split (if the number of SNVs is more than the number you\
                      declare using this parameter, the positions will be randomly subsampled)."}
             ),
    'min-scatter': (
            ['-m', '--min-scatter'],
            {'metavar': 'INT',
             'default': 0,
             'type': int,
             'help': "This one is tricky. If you have N samples in your dataset, a given variable position x in one\
                      of your splits can split your N samples into `t` groups based on the identity of the\
                      variation they harbor at position x. For instance, `t` would have been 1, if all samples had the same\
                      type of variation at position x (which would not be very interesting, because in this case\
                      position x would have zero contribution to a deeper understanding of how these samples differ\
                      based on variability. When `t` > 1, it would mean that identities at position x across samples\
                      do differ. But how much scattering occurs based on position x when t > 1? If t=2, how many\
                      samples ended in each group? Obviously, even distribution of samples across groups may tell\
                      us something different than uneven distribution of samples across groups. So, this parameter\
                      filters out any x if 'the number of samples in the second largest group' (=scatter) is less\
                      than -m. Here is an example: lets assume you have 7 samples. While 5 of those have AG, 2\
                      of them have TC at position x. This would mean scatter of x is 2. If you set -m to 2, this\
                      position would not be reported in your output matrix. The default value for -m is\
                      %(default)d, which means every `x` found in the database and survived previous filtering\
                      criteria will be reported. Naturally, -m can not be more than half of the number of samples.\
                      Please refer to the user documentation if this is confusing."}
                ),
    'max-num-unique-positions': (
            ['-n', '--max-num-unique-positions'],
            {'metavar': 'NUM_POSITIONS',
             'default': 0,
             'type': int,
             'help': "Maximum number of unique positions to be used in the network. This may be one way to avoid extremely\
                      large network descriptions that would defeat the purpose of a quick visualization. If there are more\
                      unique positions in the variability profile, the program will randomly select a subset of them to match\
                      the `max-num-unique-positions`. The default is %(default)d, which means all positions should be reported.\
                      Remember that the number of nodes in the network will also depend on the number of samples described in\
                      the variability profile."}
                ),
    'num-threads': (
            ['-T', '--num-threads'],
            {'metavar': 'NUM_CPUS',
             'default': 1,
             'type': int,
             'help': "Maximum number of threads to use for multithreading whenever possible. Very conservatively, the default\
                      is '%(default)d'. It is a good idea to not exceed the number of CPUs / cores on your system. Plus, please\
                      be careful with this option if you are running your commands on a SGE --if you are clusterizing your runs,\
                      and asking for multiple threads to use, you may deplete your resources very fast."}
                ),

    'min-coverage-in-each-sample': (
            ['--min-coverage-in-each-sample'],
            {'metavar': 'INT',
             'default': 0,
             'type': int,
             'help': "Minimum coverage of a given variable nucleotide position in all samples. If a nucleotide position\
                      is covered less than this value even in one sample, it will be removed from the analysis. Default\
                      is %(default)d."}
                ),
    'min-departure-from-reference': (
            ['-r', '--min-departure-from-reference'],
            {'metavar': 'FLOAT',
             'default': 0,
             'type': float,
             'help': "Takes a value between 0 and 1, where 1 is maximum divergence from the reference. Default is %(default)f.\
                      The reference here observation that corresponds to a given position in the mapped context."}
                ),
    'max-departure-from-reference': (
            ['-z', '--max-departure-from-reference'],
            {'metavar': 'FLOAT',
             'default': 1,
             'type': float,
             'help': "Similar to '--min-departure-from-reference', but defines an upper limit for divergence. The\
                      default is %(default)f."}
                ),
    'min-departure-from-consensus': (
            ['-j', '--min-departure-from-consensus'],
            {'metavar': 'FLOAT',
             'default': 0,
             'type': float,
             'help': "Takes a value between 0 and 1, where 1 is maximum divergence from the consensus for a given position. The\
                      default is %(default)f. The consensus is the most frequent observation at a given positon."}
                ),
    'max-departure-from-consensus': (
            ['-a', '--max-departure-from-consensus'],
            {'metavar': 'FLOAT',
             'default': 1,
             'type': float,
             'help': "Similar to '--min-departure-from-consensus', but defines an upper limit for divergence. The\
                      default is %(default)f."}
                ),
    'min-occurrence-of-variable-positions': (
            ['-x', '--min-occurrence'],
            {'metavar': 'NUM_SAMPLES',
             'default': 1,
             'type': int,
             'help': "Minimum number of samples a nucleotide position should be reported as variable. Default is %(default)d.\
                      If you set it to 2, for instance, each eligable variable position will be expected to appear in at least\
                      two samples, which will reduce the impact of stochastic, or unintelligeable varaible positions."}
                ),
    'quince-mode': (
            ['--quince-mode'],
            {'default': False,
             'action': 'store_true',
             'help': "The default behavior is to report base frequencies of nucleotide positions only if there\
                      is any variation reported during profiling (which by default uses some heuristics to minimize\
                      the impact of error-driven variation). So, if there are 10 samples, and a given position has been\
                      reported as a varaible site during profiling in only one of those samples, there will be no\
                      information will be stored in the database for the remaining 9. When this flag is\
                      used, we go back to each sample, and report base frequencies for each sample at this position\
                      even if they do not vary. It will take considerably longer to report when this flag is on, and the use\
                      of it will increase the file size dramatically, however it is inevitable for some statistical approaches\
                      (as well as for some beautiful visualizations)."}
                ),
    'engine': (
            ['--engine'],
            {'default': 'NT',
             'metavar': 'ENGINE',
             'type': str,
             'help': "Varaibility engine. The default is '%(default)s'."}
                ),
    'transpose': (
            ['--transpose'],
            {'default': False,
             'action': 'store_true',
             'help': "Transpose the input matrix file before clustering."}
                ),
    'skip-check-names': (
            ['--skip-check-names'],
            {'default': False,
             'action': 'store_true',
             'help': "For debugging purposes. You should never really need it."}
                ),
    'experimental-org-input-dir': (
            ['-i', '--input-directory'],
            {'metavar': 'DIR_PATH',
             'type': str,
             'help': "Input directory where the input files addressed from the configuration\
                      file can be found (i.e., the profile database, if PROFILE.db::TABLE\
                      notation is used in the configuration file)."}
                ),
    'clustering-name': (
            ['-N', '--name'],
            {'metavar': 'NAME',
             'type': str,
             'help': "The name to use when storing the resulting clustering in the database.\
                      This name will appear in the interactive interface and other relevant\
                      interfaces. Please consider using a short and descriptive single-word\
                      (if you do not do that you will make anvi'o complain)."}
                ),
    'output-dir': (
            ['-o', '--output-dir'],
            {'metavar': 'DIR_PATH',
             'type': str,
             'help': "Directory path for output files"}
                ),
    'output-file': (
            ['-o', '--output-file'],
            {'metavar': 'FILE_PATH',
             'type': str,
             'help': "File path to store results."}
                ),
    'log-file': (
            ['--log-file'],
            {'metavar': 'FILE_PATH',
             'type': str,
             'help': "File path to a log output."}
                ),
    'output-db-path': (
            ['-o', '--output-db-path'],
            {'metavar': 'DB_FILE_PATH',
             'type': str,
             'help': "Output file path for the new database."}
                ),
    'output-file-prefix': (
            ['-O', '--output-file-prefix'],
            {'metavar': 'FILENAME_PREFIX',
             'type': str,
             'help': "A prefix to be used while naming the output files (no file type\
                      extensions please; just a prefix)."}
                ),
    'dry-run': (
            ['--dry-run'],
            {'default': False,
             'action': 'store_true',
             'help': "Don't do anything real. Test everything, and stop right before wherever the developer\
                      said 'well, this is enough testing', and decided to print out results."}
                ),
    'verbose': (
            ['--verbose'],
            {'default': False,
             'action': 'store_true',
             'help': "Be verbose, print more messages whenever possible."}
                ),
    'debug': (
            ['--debug'],
            {'default': False,
             'action': 'store_true',
             'help': "Turn on debug messages whenever possible, and skip removing temporary files (this may\
                      cause lots and lots of output, so you may want to not use it if your intention is not\
                      debugging)."}
                ),
    'ip-address': (
            ['-I', '--ip-address'],
            {'metavar': 'IP_ADDR',
             'type': str,
             'default': '0.0.0.0',
             'help': "IP address for the HTTP server. The default ip address (%(default)s) should\
                      work just fine for most."}
                ),
    'hostname': (
            ['--hostname'],
            {'metavar': 'HOST_NAME',
             'type': str,
             'default': None,
             'help': "Host name for an anvi'server."}
                ),
    'port-number': (
            ['-P', '--port-number'],
            {'metavar': 'INT',
             'default': 8080,
             'type': int,
             'help': "Port number to use for communication. If nothing is declared, anvi'o will try to find\
                      a suitable port number."}
                ),
    'user': (
            ['--user'],
            {'metavar': 'USERNAME',
             'default': None,
             'type': str,
             'help': "The user for an anvi'server."}
                ),
    'read-only': (
            ['--read-only'],
            {'default': False,
             'action': 'store_true',
             'help': "When the interactive interface is started with this flag, all 'database write'\
                      operations will be disabled."}
                ),
    'server-only': (
            ['--server-only'],
            {'default': False,
             'action': 'store_true',
             'help': "The default behavior is to start the local server, and fire up a browser that\
                      connects to the server. If you have other plans, and want to start the server\
                      without calling the browser, this is the flag you need."}
                ),
    'skip-store-in-db': (
            ['--skip-store-in-db'],
            {'default': False,
             'action': 'store_true',
             'help': "By default, analysis results are stored in the profile database. The use of\
                      this flag will let you skip that"}
                ),
    'min-e-value': (
            ['-e', '--min-e-value'],
            {'metavar': 'E-VALUE',
             'default': 1e-15,
             'type': float,
             'help': "Minimum significance score of an HMM find to be considered as a valid hit.\
                      Default is %(default)g."}
                ),
    'min-percent-identity': (
            ['--min-percent-identity'],
            {'metavar': 'PERCENT_IDENTITY',
             'default': 80.0,
             'type': float,
             'help': "Minimum percent identity. The default is %(default)g."}
                ),
    'bins-info': (
            ['--bins-info'],
            {'metavar': 'BINS_INFO',
             'help': "Additional information for bins. The file must contain three TAB-delimited columns,\
                      where the first one must be a unique bin name, the second should be a 'source', and the\
                      last one should be a 7 character HTML color code (i.e., '#424242'). Source column must\
                      contain information about the origin of the bin. If these bins are automatically\
                      identified by a program like CONCOCT, this column could contain the program name and\
                      version. The source information will be associated with the bin in various interfaces\
                      so in a sense it is not *that* critical what it says there, but on the other hand it is,\
                      becuse we should also think about people who may end up having to work with what we put\
                      together later."}
                ),
    'contigs-mode': (
            ['--contigs-mode'],
            {'default': False,
             'action': 'store_true',
             'help': "Use this flag if your binning was done on contigs instead of splits. Please refer\
                      to the documentation for help."}
                ),
    'sample-name': (
            ['-S', '--sample-name'],
            {'metavar': 'NAME',
             'help': "It is important to set a sample name (using only ASCII letters and digits\
                      and without spaces) that is unique (considering all others). If you do not\
                      provide one, anvi'o will try to make up one for you based on other information,\
                      although, you should never let the software to decide these things)."}
                ),
    'project-name': (
            ['-J', '--project-name'],
            {'metavar': 'PROJECT_NAME',
             'help': "Name of the project. Please choose a short but descriptive name."}
                ),
    'skip-hierarchical-clustering': (
            ['--skip-hierarchical-clustering'],
            {'default': False,
             'action': 'store_true',
             'help': "If you are not planning to use the interactive interface (or if you have other\
                      means to add a tree of contigs in the database) you may skip the clustering step\
                      and simply just merge multiple runs."}
                ),
    'enforce-hierarchical-clustering': (
            ['--enforce-hierarchical-clustering'],
            {'default': False,
             'action': 'store_true',
             'help': "If you have more than 25,000 splits in your merged profile, anvi-merge will automatically\
                      skip the hierarchical clustering of splits (by setting --skip-hierarchical-clustering flag\
                      on). This is due to the fact that computational time required for hierarchical clustering\
                      increases exponentially with the number of items being clustered. Based on our experience\
                      we decided that 25,000 splits is about the maximum we should try. However, this is not a\
                      theoretical limit, and you can overwrite this heuristic by using this flag, which would\
                      tell anvi'o to attempt to cluster splits regardless."}
                ),
    'cluster-contigs': (
            ['--cluster-contigs'],
            {'default': False,
             'action': 'store_true',
             'help': "Single profiles are rarely used for genome binning or visualization, and since\
                      clustering step increases the profiling runtime for no good reason, the default\
                      behavior is to not cluster contigs for individual runs. However, if you are\
                      planning to do binning on one sample, you must use this flag to tell anvio to\
                      run cluster configurations for single runs on your sample."}
                ),
    'skip-concoct-binning': (
            ['--skip-concoct-binning'],
            {'default': False,
             'action': 'store_true',
             'help': "Anvi'o uses CONCOCT (Alneberg et al.) by default for unsupervised genome binning\
                      for merged runs. CONCOCT results are stored in the profile database, which then\
                      can be used from within appropriate interfaces (i.e., anvi-interactive, anvi-summary,\
                      etc). Use this flag if you would like to skip this step"}
                ),
    'num-clusters-requested': (
            ['--num-clusters-requested'],
            {'metavar': 'INT',
             'default': 80,
             'type': int,
             'help': "How many clusters do you request? Default is %(default)d."}
             ),
    'overwrite-output-destinations': (
            ['-W', '--overwrite-output-destinations'],
            {'default': False,
             'action': 'store_true',
             'help': "Overwrite if the output files and/or directories exist."}
                ),
    'delete-if-exists': (
            ['--delete-if-exists'],
            {'default': False,
             'action': 'store_true',
             'help': "Be bold (at your own risk), and delete if exists."}
                ),
    'report-variability-full': (
            ['--report-variability-full'],
            {'default': False,
             'action': 'store_true',
             'help': "One of the things anvi-profile does is to store information about variable\
                      nucleotide positions. Usually it does not report every variable position, since\
                      not every variable position is geniune variation. Say, if you have 1,000 coverage,\
                      and all nucleotides at that position are Ts and only one of them is a C, the\
                      confidence of that C being a real variation is quite low. anvio has a simple\
                      algorithm in place to reduce the impact of noise. However, using this flag\
                      you can diable it and ask profiler to report every single variation (which\
                      may result in very large output files and millions of reports, but you are the\
                      boss). Do not forget to take a look at '--min-coverage-for-variability' parameter"}
                ),
    'manual-mode': (
            ['--manual-mode'],
            {'default': False,
             'action': 'store_true',
             'help': "Using this flag, you can run the interactive interface in an ad hoc manner using\
                      input files you curated instead of standard output files generated by an anvi'o\
                      run. In the manual mode you will be asked to provide a profile database. In this\
                      mode a profile database is only used to store 'state' of the interactive interface\
                      so you can reload your visual settings when you re-analyze the same files again. If\
                      the profile database you provide does not exist, anvi'o will create an empty one for\
                      you."}
                ),

    'hmm-profile-dir': (
            ['-H', '--hmm-profile-dir'],
            {'metavar': 'PATH',
             'help': "If this is empty, anvi'o will perform the HMM search against the default collections that\
                      are on the system. If it is not, this parameter should be used to point to a directory\
                      that contains 4 files: (1) genes.hmm.gz, (2) genes.txt, (3) kind.txt, and (4)\
                      reference.txt. Please see the documentation for specifics of these files."}
                ),
    'min-contig-length': (
            ['-M', '--min-contig-length'],
            {'metavar': 'INT',
             'default': 5000,
             'type': int,
             'help': "Minimum length of contigs in a BAM file to analyze. The minimum length should be long enough\
                      for tetra-nucleotide frequency analysis to be meaningful. There is no way to define a golden\
                      number of minumum length that would be applicable to genomes found in all environments, but we\
                      chose the default to be %(default)d, and have been happy with it. You are welcome to experiment,\
                      but we advise to never go below 1,000. You also should remember that the lower you go, the more\
                      time it will take to analyze all contigs. You can use --list-contigs parameter to have an idea how\
                      many contigs would be discarded for a given M."}
                ),
    'min-mean-coverage': (
            ['-X', '--min-mean-coverage'],
            {'metavar': 'INT',
             'default': 0,
             'type': int,
             'help': "Minimum mean coverage for contigs to be kept in the analysis. The default value is %(default)d,\
                      which is for your best interest if you are going to profile muptiple BAM files which are then\
                      going to be merged for a cross-sectional or time series analysis. Do not change it if you are not\
                      sure this is what you want to do."}
                ),
    'min-coverage-for-variability': (
            ['-V', '--min-coverage-for-variability'],
            {'metavar': 'INT',
             'default': 10,
             'type': int,
             'help': "Minimum coverage of a nucleotide position to be subjected to SNV profiling. By default, anvio will\
                      not attempt to make sense of variation in a given nucleotide position if it is covered less than\
                      %(default)dX. You can change that minimum using this parameter."}
                ),
    'contigs-and-positions': (
            ['--contigs-and-positions'],
            {'metavar': 'CONTIGS_AND_POS',
             'required': True,
             'help': "This is the file where you list the contigs, and nucleotide positions you are interested in. This\
                      is supposed to be a TAB-delimited file with two columns. In each line, the first column should be\
                      the contig name, and the second column should be the comma-separated list of integers for nucleotide\
                      positions."}
                ),
    'state': (
            ['--state'],
            {'metavar': 'NAME',
             'help': "Automatically load previous saved state and draw tree. To see a list of available states,\
                      use --show-states flag."}
                ),
    'full-report': (
            ['--full-report'],
            {'metavar': 'FILE_NAME',
             'default': None,
             'help': "Optional output file with a fuller description of findings."}
                ),
    'show-states': (
            ['--show-states'],
            {'default': False,
             'action': 'store_true',
             'help': "When declared the program will print all available states and exit."}
                ),
    'skip-init-functions': (
            ['--skip-init-functions'],
            {'default': False,
             'action': 'store_true',
             'help': "When declared, function calls for genes will not be initialized (therefore will be missing from all\
                      relevant interfaces or output files). The use of this flag may reduce the memory fingerprint and\
                      processing time for large datasets."}
                ),
    'quick-summary': (
            ['--quick-summary'],
            {'default': False,
             'action': 'store_true',
             'help': "When declared the summary output will be generated as quickly as possible, with minimum amount\
                      of essential information about bins."}
                ),
    'only-complete-links': (
            ['--only-complete-links'],
            {'default': False,
             'action': 'store_true',
             'help': "When declared, only reads that cover all positions will be reported. It is necessary to use this\
                      flag if you want to perform oligotyping-like analyses on matching reads."}
                ),
    'users-data-dir': (
            ['-U', '--users-data-dir'],
            {'metavar': 'USERS_DATA_DIR',
             'type': str,
             'help': "Input directory where the user database is read and stored by the server. A new database will be\
                      created if no directory is found."}
                ),
    'smtp-config-file': (
            ['-E', '--smtp-config-file'],
            {'metavar': 'SMTP_CONFIG_INI',
             'type': str,
             'help': "The configuration file for SMTP server to send e-mails. The input file should be formatted as an INI\
                      file that starts with the header '[SMTP]', and should describe values of each of these variables in\
                      the following lines: 'from_address' (the e-mail address that should appear in the 'From' section of\
                      e-mails sent by the server), 'server_address' (the address of the SMTP server to connect), 'server_port'\
                      (the port number to connect), 'init_tls' (whether to initialize TLS protocol), 'username' (the username\
                      for the server to login, if necessary), 'password' (the password associated with the username for login,\
                      if the password is not blank)."}
                ),
    'validate-users-automatically': (
            ['--validate-users-automatically'],
            {'default': True,
             'action': 'store_true',
             'help': "If this is true, users will not receive a link via email to confirm their account but instead be validated\
                      automatically if there is no smtp configuration."}
                ),
}

# two functions that works with the dictionary above.
def A(param_id):
    return D[param_id][0]

def K(param_id, params_dict={}):
    kwargs = copy.deepcopy(D[param_id][1])
    for key in params_dict:
        kwargs[key] = params_dict[key]

    return kwargs


# The rest of this file is composed of code that responds to '-v' or '--version' calls from clients,
# and provides access to the database version numbers for all anvi'o modules.

import anvio.tables as t
from anvio.terminal import Run


run = Run()


def set_version():
    try:
        __version__ = pkg_resources.require("anvio")[0].version
    except:
        # maybe it is not installed but being run from the codebase dir?
        try:
            __version__ = open(os.path.normpath(os.path.dirname(os.path.abspath(__file__))) + '/../VERSION').read().strip()
        except:
            __version__ = 'unknown'

    return __version__, t.contigs_db_version, t.profile_db_version, t.samples_info_db_version, t.auxiliary_hdf5_db_version, t.users_db_version


def print_version():
    run.info("Anvi'o version", __version__, mc='green')
    run.info("Profile DB version", __profile__version__)
    run.info("Contigs DB version", __contigs__version__)
    run.info("Samples information DB version", __samples__version__)
    run.info("Auxiliary HDF5 DB version", __hdf5__version__)
    run.info("Users DB version (for anvi-server)", __users_db_version__)


__version__, __contigs__version__, __profile__version__, __samples__version__, __hdf5__version__, __users_db_version__ = set_version()


if '-v' in sys.argv or '--version' in sys.argv:
    print_version()
    sys.exit()
