#!/opt/anaconda1anaconda2anaconda3/bin/python
# -*- coding: utf-8
"""A DIAMOND and MCL-based pangenome workflow"""

import sys

import anvio
import anvio.panops as panops
import anvio.terminal as terminal
import anvio.constants as constants

from anvio.errors import ConfigError, FilesNPathsError, HDF5Error


__author__ = "Developers of anvi'o (see AUTHORS.txt)"
__copyright__ = "Copyleft 2015-2018, the Meren Lab (http://merenlab.org/)"
__credits__ = []
__license__ = "GPL 3.0"
__version__ = anvio.__version__
__maintainer__ = "A. Murat Eren"
__email__ = "a.murat.eren@gmail.com"
__requires__ = ['genomes-storage-db',]
__provides__ = ['pan-db', 'misc-data-item-orders']


run = terminal.Run()
progress = terminal.Progress()


if __name__ == '__main__':
    run.warning('If you publish results from this workflow, please do not forget to cite DIAMOND\
                 (doi:10.1038/nmeth.3176), unless you use it with --use-ncbi-blast flag, and MCL\
                 (http://micans.org/mcl/ and doi:10.1007/978-1-61779-361-5_15)', lc = 'yellow')

    import argparse

    parser = argparse.ArgumentParser(description="A DIAMOND and MCL-based anvi'o pangenome workflow. You provide genomes from anywhere\
                                                  (whether they are external genomes, or anvi'o genome bins in collections), and it\
                                                  gives you back a pangenome analysis.")

    groupA = parser.add_argument_group('GENOMES', "The very fancy genomes storage file. This file is generated by the program `anvi-genomes-storage`.\
                                                   Please see the online tutorial on pangenomic workflow if you don't know how to generate one.")
    groupA.add_argument(*anvio.A('genomes-storage'), **anvio.K('genomes-storage', {'required': True}))
    groupA.add_argument(*anvio.A('genomes-names'), **anvio.K('genomes-names'))

    groupC = parser.add_argument_group("PARAMETERS", "Important stuff Tom never pays attention (but you should).")
    groupC.add_argument('--skip-alignments', default = False, action = 'store_true', help = "By default, anvi'o attempts to align amino acid\
                                sequences in each gene cluster using multiple sequnce alignment via muscle. You can use this flag to skip\
                                that step and be upset later.")
    groupC.add_argument('--skip-homogeneity',default=False, action='store_true', dest='skip_homogeneity',help="By default, anvi'o attempts to calculate homogeneity\
                                values for every gene cluster, given that they are aligned. You can use this flag to have anvi'o skip\
                                homogeneity calculations. Anvi'o will ignore this flag if you decide to skip alignments")
    groupC.add_argument('--quick-homogeneity',default=False, action='store_true', dest='quick_homogeneity',help="By default, anvi'o will use a homogeneity\
                                algorithm that checks for horizontal and vertical geometric homogeneity (along with functional). With this\
                                flag, you can tell anvi'o to skip horizontal geometric homogeneity calculations. It will be less accurate but quicker.\
                                Anvi'o will ignore this flag if you skip homogeneity calculations or alignments all together.")
    groupC.add_argument(*anvio.A('align-with'), **anvio.K('align-with'))
    groupC.add_argument('--exclude-partial-gene-calls', default = False, action = 'store_true', help = "By default, anvi'o includes all partial\
                                gene calls from the analysis, which, in some cases, may inflate the number of gene clusters identified and\
                                introduce extra heterogeneity within those gene clusters. Using this flag, you can request anvi'o to exclude\
                                partial gene calls from the analysis (whether a gene call is partial or not is an information that comes directly\
                                from the gene caller used to identify genes during the generation of the contigs database).")
    groupC.add_argument('--use-ncbi-blast', default = False, action = 'store_true', help = "This program uses DIAMOND by default, however,\
                                if you like, you can use good ol' blastp from NCBI instead.")
    groupC.add_argument('--minbit', type = float, default = 0.5, metavar = "MINBIT", help = "The minimum minbit value. The minbit heuristic \
                                provides a mean to set a to eliminate weak matches between two amino acid sequences. We learned it from ITEP \
                                (Benedict MN et al, doi:10.1186/1471-2164-15-8), which is a comprehensive analysis workflow for pangenomes, \
                                and decided to use it in the anvi'o pangenomic workflow, as well. Briefly, If you have two amino acid sequences,\
                                'A' and 'B', the minbit is defined as 'BITSCORE(A, B) / MIN(BITSCORE(A, A), BITSCORE(B, B))'. So the minbit score\
                                between two sequences goes to 1 if they are very similar over the entire length of the 'shorter' amino acid sequence,\
                                and goes to 0 if (1) they match over a very short stretch compared even to the length of the shorter amino acid sequence\
                                or (2) the match betwen sequence identity is low. The default is %(default)g.")
    groupC.add_argument('--mcl-inflation', type = float, default = 2.0, metavar = "INFLATION", help = "MCL inflation parameter, that defines\
                                the sensitivity of the algorithm during the identification of the gene clusters. More information on this\
                                parameter and it's effect on cluster granularity is here: (http://micans.org/mcl/man/mclfaq.html#faq7.2).\
                                The default is %(default)g.")
    groupC.add_argument('--min-occurrence', type = int, default = 1, metavar = 'NUM_OCCURRENCE', help = "Do you not want singletons?\ You don't?\
                                Well, this parameter will help you get rid of them (along with doubletons, if you want). Anvi'o will remove\
                                gene clusters that occur less than the number you set using this parameter from the analysis. The default\
                                is %(default)d, which means everything will be kept. If you want to remove singletons, set it to 2, if you want to\
                                remove doubletons as well, set it to 3, and so on.")
    groupC.add_argument('--min-percent-identity', type = float, default = 0.0, metavar = "PERCENT", help = "Minimum percent identity\
                                between the two amino acid sequences for them to have an edge for MCL analysis. This value will be used\
                                to filter hits from Diamond search results. Because percent identity is not a predictor of a good match (since\
                                it does not communicate many other important factors such as the alignment length between the two sequences and\
                                its proportion to the entire length of those involved), we suggest you rely on 'minbit' parameter. But you know\
                                what? Maybe you shouldn't listen to anyone, and experiment on your own! The default is %(default)g percent.")
    groupC.add_argument(*anvio.A('sensitive'), **anvio.K('sensitive'))

    groupD = parser.add_argument_group("OTHERS", "Sweet parameters of convenience.")
    groupD.add_argument(*anvio.A('project-name'), **anvio.K('project-name'))
    groupD.add_argument(*anvio.A('description'), **anvio.K('description'))
    groupD.add_argument(*anvio.A('output-dir'), **anvio.K('output-dir', {'metavar':'PAN_DB_DIR'}))
    groupD.add_argument(*anvio.A('overwrite-output-destinations'), **anvio.K('overwrite-output-destinations'))
    groupD.add_argument(*anvio.A('num-threads'), **anvio.K('num-threads'))

    groupE = parser.add_argument_group("ORGANIZING GENE CLUSTERs", "These are stuff that will change the clustering dendrogram of your gene clusters.")
    groupE.add_argument(*anvio.A('skip-hierarchical-clustering'), **anvio.K('skip-hierarchical-clustering', {'help': "Anvi'o attempts\
                                to generate a hierarchical clustering of your gene clusters once it identifies them so you can use\
                                `anvi-display-pan` to play with it. But if you want to skip this step, this is your flag."}))
    groupE.add_argument(*anvio.A('enforce-hierarchical-clustering'), **anvio.K('enforce-hierarchical-clustering', {'help': "If you\
                                want anvi'o to try to generate a hierarchical clustering of your gene clusters even if the number of gene clusters exceeds\
                                its suggested limit for hierarchical clustering, you can use this flag to enforce it. Are you are a\
                                rebel of some sorts? Or did computers made you upset? Express your anger towards machine using this\
                                flag."}))
    groupE.add_argument(*anvio.A('distance'), **anvio.K('distance', {'default': None, 'help':
                      'The distance metric for the clustering of gene clusters. If you do not use this flag,\
                       the default distance metric will be used for each clustering configuration\
                       which is "%s".' % constants.distance_metric_default}))
    groupE.add_argument(*anvio.A('linkage'), **anvio.K('linkage', {'default': None, 'help':
                      'The same story with the `--distance`, except, the system default for this one\
                       is %s.' % constants.linkage_method_default}))

    args = anvio.get_args(parser)

    try:
        pan = panops.Pangenome(args, run, progress)
        pan.process()
    except ConfigError as e:
        print(e)
        sys.exit(-1)
    except FilesNPathsError as e:
        print(e)
        sys.exit(-2)
    except HDF5Error as e:
        print(e)
        sys.exit(-2)
