# Path: augur/utils.py
# def read_metadata(fname, query=None, as_data_frame=False):
#     return MetadataFile(fname, query, as_data_frame).read()
# 
# def read_node_data(fnames, tree=None):
#     return NodeDataReader(fnames, tree).read()
# 
# 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 read_config(fname):
#     if not (fname and os.path.isfile(fname)):
#         print("ERROR: config file %s not found."%fname)
#         return defaultdict(dict)
# 
#     try:
#         with open(fname, 'rb') as ifile:
#             config = json.load(ifile)
#     except json.decoder.JSONDecodeError as err:
#         print("FATAL ERROR:")
#         print("\tCouldn't parse the JSON file {}".format(fname))
#         print("\tError message: '{}'".format(err.msg))
#         print("\tLine number: '{}'".format(err.lineno))
#         print("\tColumn number: '{}'".format(err.colno))
#         print("\tYou must correct this file in order to proceed.")
#         sys.exit(2)
# 
#     return config
# 
# def read_lat_longs(overrides=None, use_defaults=True):
#     coordinates = {}
#     # TODO: make parsing of tsv files more robust while allow for whitespace delimiting for backwards compatibility
#     def add_line_to_coordinates(line):
#         if line.startswith('#') or line.strip() == "":
#             return
#         fields = line.strip().split() if not '\t' in line else line.strip().split('\t')
#         if len(fields) == 4:
#             geo_field, loc = fields[0].lower(), fields[1].lower()
#             lat, long = float(fields[2]), float(fields[3])
#             coordinates[(geo_field, loc)] = {
#                 "latitude": lat,
#                 "longitude": long
#             }
#         else:
#             print("WARNING: geo-coordinate file contains invalid line. Please make sure not to mix tabs and spaces as delimiters (use only tabs):",line)
#     if use_defaults:
#         with resource_stream(__package__, "data/lat_longs.tsv") as stream:
#             with TextIOWrapper(stream, "utf-8") as defaults:
#                 for line in defaults:
#                     add_line_to_coordinates(line)
#     if overrides:
#         if os.path.isfile(overrides):
#             with open(overrides, encoding='utf-8') as ifile:
#                 for line in ifile:
#                     add_line_to_coordinates(line)
#         else:
#             print("WARNING: input lat/long file %s not found." % overrides)
#     return coordinates
# 
# def read_colors(overrides=None, use_defaults=True):
#     return ColorParser(mapping_filename=overrides, use_defaults=use_defaults).mapping


import os, sys
import re
import time
import numpy as np
from Bio import Phylo
from argparse import SUPPRESS
from collections import defaultdict
from .utils import read_metadata, read_node_data, write_json, read_config, read_lat_longs, read_colors
        from Bio import SeqIO
        if T.root.name in nodes:
            root_sequence = get_root_sequence(nodes[T.root.name], ref=args.reference,
                                                translations=args.reference_translations)
        else:
            root_sequence = {}

        write_json(root_sequence, args.output_sequence, include_version=False)

    meta_json = read_config(args.auspice_config)
    ensure_config_is_v1(meta_json)
    meta_tsv, _ = read_metadata(args.metadata)
    add_tsv_metadata_to_nodes(nodes, meta_tsv, meta_json)

    tree_layout(T)
    tree_json, _ = convert_tree_to_json_structure(T.root, nodes)

    # now the messy bit about what decorations (e.g. "country", "aa_muts") do we want to add to the tree?
    # see recursively_decorate_tree_json to understand the tree_decorations structure
    tree_decorations = [
        {"key": "num_date", "lookup_key": "numdate", "is_attr": True},
        {"key": "muts", "is_attr": False},
        {"key": "aa_muts", "is_attr": False}
    ]
    traits_via_node_metadata = {k for node in nodes.values() for k in node.keys()}
    traits_via_node_metadata -= {'sequence', 'mutation_length', 'branch_length', 'numdate',
                                    'mutations', 'muts', 'aa_muts', 'aa_sequences'}
    for trait in traits_via_node_metadata:
        tree_decorations.append({"key": trait, "is_attr": True})

    recursively_decorate_tree_json_v1_schema(tree_json, nodes, decorations=tree_decorations)

# Path: augur/utils.py
# def read_metadata(fname, query=None, as_data_frame=False):
#     return MetadataFile(fname, query, as_data_frame).read()
# 
# def read_node_data(fnames, tree=None):
#     return NodeDataReader(fnames, tree).read()
# 
# 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 read_config(fname):
#     if not (fname and os.path.isfile(fname)):
#         print("ERROR: config file %s not found."%fname)
#         return defaultdict(dict)
# 
#     try:
#         with open(fname, 'rb') as ifile:
#             config = json.load(ifile)
#     except json.decoder.JSONDecodeError as err:
#         print("FATAL ERROR:")
#         print("\tCouldn't parse the JSON file {}".format(fname))
#         print("\tError message: '{}'".format(err.msg))
#         print("\tLine number: '{}'".format(err.lineno))
#         print("\tColumn number: '{}'".format(err.colno))
#         print("\tYou must correct this file in order to proceed.")
#         sys.exit(2)
# 
#     return config
# 
# def read_lat_longs(overrides=None, use_defaults=True):
#     coordinates = {}
#     # TODO: make parsing of tsv files more robust while allow for whitespace delimiting for backwards compatibility
#     def add_line_to_coordinates(line):
#         if line.startswith('#') or line.strip() == "":
#             return
#         fields = line.strip().split() if not '\t' in line else line.strip().split('\t')
#         if len(fields) == 4:
#             geo_field, loc = fields[0].lower(), fields[1].lower()
#             lat, long = float(fields[2]), float(fields[3])
#             coordinates[(geo_field, loc)] = {
#                 "latitude": lat,
#                 "longitude": long
#             }
#         else:
#             print("WARNING: geo-coordinate file contains invalid line. Please make sure not to mix tabs and spaces as delimiters (use only tabs):",line)
#     if use_defaults:
#         with resource_stream(__package__, "data/lat_longs.tsv") as stream:
#             with TextIOWrapper(stream, "utf-8") as defaults:
#                 for line in defaults:
#                     add_line_to_coordinates(line)
#     if overrides:
#         if os.path.isfile(overrides):
#             with open(overrides, encoding='utf-8') as ifile:
#                 for line in ifile:
#                     add_line_to_coordinates(line)
#         else:
#             print("WARNING: input lat/long file %s not found." % overrides)
#     return coordinates
# 
# def read_colors(overrides=None, use_defaults=True):
#     return ColorParser(mapping_filename=overrides, use_defaults=use_defaults).mapping


# Path: augur/export_v1.py
import os, sys
import re
import time
import numpy as np
from Bio import Phylo
from argparse import SUPPRESS
from collections import defaultdict
from .utils import read_metadata, read_node_data, write_json, read_config, read_lat_longs, read_colors
        from Bio import SeqIO

        if T.root.name in nodes:
            root_sequence = get_root_sequence(nodes[T.root.name], ref=args.reference,
                                                translations=args.reference_translations)
        else:
            root_sequence = {}

        write_json(root_sequence, args.output_sequence, include_version=False)

    meta_json = read_config(args.auspice_config)
    ensure_config_is_v1(meta_json)
    meta_tsv, _ = read_metadata(args.metadata)
    add_tsv_metadata_to_nodes(nodes, meta_tsv, meta_json)

    tree_layout(T)
    tree_json, _ = convert_tree_to_json_structure(T.root, nodes)

    # now the messy bit about what decorations (e.g. "country", "aa_muts") do we want to add to the tree?
    # see recursively_decorate_tree_json to understand the tree_decorations structure
    tree_decorations = [
        {"key": "num_date", "lookup_key": "numdate", "is_attr": True},
        {"key": "muts", "is_attr": False},
        {"key": "aa_muts", "is_attr": False}
    ]
    traits_via_node_metadata = {k for node in nodes.values() for k in node.keys()}
    traits_via_node_metadata -= {'sequence', 'mutation_length', 'branch_length', 'numdate',
                                    'mutations', 'muts', 'aa_muts', 'aa_sequences'}
    for trait in traits_via_node_metadata:
        tree_decorations.append({"key": trait, "is_attr": True})

    recursively_decorate_tree_json_v1_schema(tree_json, nodes, decorations=tree_decorations)

    write_json(tree_json, args.output_tree, indent=json_indent, include_version=False)