# Path: augur/utils.py
# def read_tree(fname, min_terminals=3):
#     """Safely load a tree from a given filename or raise an error if the file does
#     not contain a valid tree.
# 
#     Parameters
#     ----------
#     fname : str
#         name of a file containing a phylogenetic tree
# 
#     min_terminals : int
#         minimum number of terminals required for the parsed tree as a sanity
#         check on the tree
# 
#     Raises
#     ------
#     InvalidTreeError
#         If the given file exists but does not seem to contain a valid tree format.
# 
#     Returns
#     -------
#     Bio.Phylo :
#         BioPython tree instance
# 
#     """
#     T = None
#     supported_tree_formats = ["newick", "nexus"]
#     for fmt in supported_tree_formats:
#         try:
#             T = Bio.Phylo.read(fname, fmt)
# 
#             # Check the sanity of the parsed tree to handle cases when non-tree
#             # data are still successfully parsed by BioPython. Too few terminals
#             # in a tree indicates that the input is not valid.
#             if T.count_terminals() < min_terminals:
#                 T = None
#             else:
#                 break
#         except ValueError:
#             # We cannot open the tree in the current format, so we will try
#             # another.
#             pass
# 
#     # If the tree cannot be loaded, raise an error to that effect.
#     if T is None:
#         raise InvalidTreeError(
#             "Could not read the given tree %s using the following supported formats: %s" % (fname, ", ".join(supported_tree_formats))
#         )
# 
#     return T
# 
# class InvalidTreeError(Exception):
#     """Represents an error loading a phylogenetic tree from a filename.
#     """
#     pass
# 
# def write_json(data, file_name, indent=(None if os.environ.get("AUGUR_MINIFY_JSON") else 2), include_version=True):
#     """
#     Write ``data`` as JSON to the given ``file_name``, creating parent directories
#     if necessary. The augur version is included as a top-level key "augur_version".
# 
#     Parameters
#     ----------
#     data : dict
#         data to write out to JSON
#     file_name : str
#         file name to write to
#     indent : int or None, optional
#         JSON indentation level. Default is `None` if the environment variable `AUGUR_MINIFY_JSON`
#         is truthy, else 1
#     include_version : bool, optional
#         Include the augur version. Default: `True`.
# 
#     Raises
#     ------
#     OSError
#     """
#     #in case parent folder does not exist yet
#     parent_directory = os.path.dirname(file_name)
#     if parent_directory and not os.path.exists(parent_directory):
#         try:
#             os.makedirs(parent_directory)
#         except OSError: #Guard against race condition
#             if not os.path.isdir(parent_directory):
#                 raise
# 
#     if include_version:
#         data["generated_by"] = {"program": "augur", "version": get_augur_version()}
# 
#     with open(file_name, 'w', encoding='utf-8') as handle:
#         json.dump(data, handle, indent=indent, sort_keys=True)
# 
# def get_json_name(args, default=None):
#     if args.output_node_data:
#         return args.output_node_data
#     else:
#         if default:
#             print("WARNING: no name for the output file was specified. Writing results to %s."%default, file=sys.stderr)
#             return default
#         else:
#             raise ValueError("Please specify a name for the JSON file containing the results.")


import os, shutil, time, json, sys
import numpy as np
    import numpy as np
    import treetime
from Bio import Phylo, SeqIO
from Bio.Seq import Seq
from Bio.SeqRecord import SeqRecord
from .utils import read_tree, InvalidTreeError, write_json, get_json_name
from treetime.vcf_utils import read_vcf, write_vcf
from collections import defaultdict
    from treetime import TreeAnc, version as treetime_version
    from distutils.version import StrictVersion

    tt = ancestral_sequence_inference(tree=T, aln=aln, ref=ref, marginal=args.inference,
                                      fill_overhangs = not(args.keep_overhangs),
                                      infer_tips = infer_ambiguous)

    character_map = {}
    for x in tt.gtr.profile_map:
        if tt.gtr.profile_map[x].sum()==tt.gtr.n_states:
            # TreeTime treats all characters that are not valid IUPAC nucleotide chars as fully ambiguous
            # To clean up auspice output, we map all those to 'N'
            character_map[x] = 'N'
        else:
            character_map[x] = x

    anc_seqs.update(collect_mutations_and_sequences(tt, full_sequences=not is_vcf,
                          infer_tips=infer_ambiguous, character_map=character_map))
    # add reference sequence to json structure. This is the sequence with
    # respect to which mutations on the tree are defined.
    if is_vcf:
        anc_seqs['reference'] = {"nuc":compress_seq['reference']}
    else:
        root_seq = tt.sequence(T.root, as_string=False)
        if anc_seqs.get("mask") is not None:
            root_seq[anc_seqs['mask']] = tt.gtr.ambiguous
        anc_seqs['reference'] = {"nuc": ''.join(root_seq)}

    if anc_seqs.get("mask") is not None:
        anc_seqs["mask"] = "".join(['1' if x else '0' for x in anc_seqs["mask"]])

    out_name = get_json_name(args, '.'.join(args.alignment.split('.')[:-1]) + '_mutations.json')

# Path: augur/utils.py
# def read_tree(fname, min_terminals=3):
#     """Safely load a tree from a given filename or raise an error if the file does
#     not contain a valid tree.
# 
#     Parameters
#     ----------
#     fname : str
#         name of a file containing a phylogenetic tree
# 
#     min_terminals : int
#         minimum number of terminals required for the parsed tree as a sanity
#         check on the tree
# 
#     Raises
#     ------
#     InvalidTreeError
#         If the given file exists but does not seem to contain a valid tree format.
# 
#     Returns
#     -------
#     Bio.Phylo :
#         BioPython tree instance
# 
#     """
#     T = None
#     supported_tree_formats = ["newick", "nexus"]
#     for fmt in supported_tree_formats:
#         try:
#             T = Bio.Phylo.read(fname, fmt)
# 
#             # Check the sanity of the parsed tree to handle cases when non-tree
#             # data are still successfully parsed by BioPython. Too few terminals
#             # in a tree indicates that the input is not valid.
#             if T.count_terminals() < min_terminals:
#                 T = None
#             else:
#                 break
#         except ValueError:
#             # We cannot open the tree in the current format, so we will try
#             # another.
#             pass
# 
#     # If the tree cannot be loaded, raise an error to that effect.
#     if T is None:
#         raise InvalidTreeError(
#             "Could not read the given tree %s using the following supported formats: %s" % (fname, ", ".join(supported_tree_formats))
#         )
# 
#     return T
# 
# class InvalidTreeError(Exception):
#     """Represents an error loading a phylogenetic tree from a filename.
#     """
#     pass
# 
# def write_json(data, file_name, indent=(None if os.environ.get("AUGUR_MINIFY_JSON") else 2), include_version=True):
#     """
#     Write ``data`` as JSON to the given ``file_name``, creating parent directories
#     if necessary. The augur version is included as a top-level key "augur_version".
# 
#     Parameters
#     ----------
#     data : dict
#         data to write out to JSON
#     file_name : str
#         file name to write to
#     indent : int or None, optional
#         JSON indentation level. Default is `None` if the environment variable `AUGUR_MINIFY_JSON`
#         is truthy, else 1
#     include_version : bool, optional
#         Include the augur version. Default: `True`.
# 
#     Raises
#     ------
#     OSError
#     """
#     #in case parent folder does not exist yet
#     parent_directory = os.path.dirname(file_name)
#     if parent_directory and not os.path.exists(parent_directory):
#         try:
#             os.makedirs(parent_directory)
#         except OSError: #Guard against race condition
#             if not os.path.isdir(parent_directory):
#                 raise
# 
#     if include_version:
#         data["generated_by"] = {"program": "augur", "version": get_augur_version()}
# 
#     with open(file_name, 'w', encoding='utf-8') as handle:
#         json.dump(data, handle, indent=indent, sort_keys=True)
# 
# def get_json_name(args, default=None):
#     if args.output_node_data:
#         return args.output_node_data
#     else:
#         if default:
#             print("WARNING: no name for the output file was specified. Writing results to %s."%default, file=sys.stderr)
#             return default
#         else:
#             raise ValueError("Please specify a name for the JSON file containing the results.")


# Path: augur/ancestral.py
import os, shutil, time, json, sys
import numpy as np
    import numpy as np
    import treetime
from Bio import Phylo, SeqIO
from Bio.Seq import Seq
from Bio.SeqRecord import SeqRecord
from .utils import read_tree, InvalidTreeError, write_json, get_json_name
from treetime.vcf_utils import read_vcf, write_vcf
from collections import defaultdict
    from treetime import TreeAnc, version as treetime_version
    from distutils.version import StrictVersion


    tt = ancestral_sequence_inference(tree=T, aln=aln, ref=ref, marginal=args.inference,
                                      fill_overhangs = not(args.keep_overhangs),
                                      infer_tips = infer_ambiguous)

    character_map = {}
    for x in tt.gtr.profile_map:
        if tt.gtr.profile_map[x].sum()==tt.gtr.n_states:
            # TreeTime treats all characters that are not valid IUPAC nucleotide chars as fully ambiguous
            # To clean up auspice output, we map all those to 'N'
            character_map[x] = 'N'
        else:
            character_map[x] = x

    anc_seqs.update(collect_mutations_and_sequences(tt, full_sequences=not is_vcf,
                          infer_tips=infer_ambiguous, character_map=character_map))
    # add reference sequence to json structure. This is the sequence with
    # respect to which mutations on the tree are defined.
    if is_vcf:
        anc_seqs['reference'] = {"nuc":compress_seq['reference']}
    else:
        root_seq = tt.sequence(T.root, as_string=False)
        if anc_seqs.get("mask") is not None:
            root_seq[anc_seqs['mask']] = tt.gtr.ambiguous
        anc_seqs['reference'] = {"nuc": ''.join(root_seq)}

    if anc_seqs.get("mask") is not None:
        anc_seqs["mask"] = "".join(['1' if x else '0' for x in anc_seqs["mask"]])

    out_name = get_json_name(args, '.'.join(args.alignment.split('.')[:-1]) + '_mutations.json')

    write_json(anc_seqs, out_name)