"""
Factory functions for instanciating `taxidTools.Taxonomy` objects
"""

import json
from typing import Iterator, Optional
from .Taxonomy import Taxonomy
from .Node import Node, DummyNode, _BaseNode, MergedNode


def read_taxdump(
    nodes: str, rankedlineage: str,
    merged: Optional[str] = None,
    skip_synth: Optional[bool] = False,
    skip_env: Optional[bool] = False,
    skip_nodiv: Optional[bool] = True,
    ) -> Taxonomy:
    """
    Read a Taxonomy from the NCBI`s taxdump files

    Parameters
    ----------
    nodes: str
        Path to the nodes.dmp file
    rankedlineage: str
        Path to the rankedlineage.dmp file
    merged: str, optional
        Path to the merged.mp file
    skip_synth: bool, optional
        Skip taxa in the 'Synthetic and Chimeric' division
    skip_env: bool, optional
        Skip taxa in the 'Environmental samples' division
    skip_nodiv: bool, optional
        Skip taxa in the 'Unassigned' division

    Returns
    -------
    taxidTools.Taxonomy

    Examples
    --------
    >>> tax = read_taxdump("nodes.dmp', 'rankedlineage.dmp')
    >>> tax = read_taxdump("nodes.dmp', 'rankedlineage.dmp', merged='merged.dmp', skip_env=True, skip_synth=True)

    See Also
    --------
    read_json
    """
    txd = {}
    parent_dict = {}

    # Skipping divisions
    skip_list = []
    if skip_synth:
        skip_list += [7]
    if skip_env:
        skip_list += [11]
    if skip_nodiv:
        skip_list += [8]

    # Creating nodes
    for line in _parse_dump(nodes):
        if line[4] in skip_list:
            continue
        txd[line[0]] = Node(taxid=line[0], rank=str(line[2]))
        parent_dict[str(line[0])] = line[1]  # storing parent id

    # Add names from rankedlineage
    for line in _parse_dump(rankedlineage):
        txd[line[0]].name = line[1]

    # Update parent info
    for k, v in parent_dict.items():
        txd[k].parent = txd[v]

    # parsing merged
    if merged:
        for line in _parse_dump(merged):
            txd[line[0]] = MergedNode(line[0],line[1])

    return Taxonomy(txd)


def read_json(path: str) -> Taxonomy:
    """
    Load a Taxonomy from a previously exported json file.

    Parameters
    ----------
    path: str
        Path of file to load

    Returns
    -------
    taxidTools.Taxonomy

    See Also
    --------
    taxidTools.Taxonomy.write
    read_taxdump
    """
    # parse json
    with open(path, 'r') as fi:
        parser = json.loads(fi.read())

    txd = {}
    parent_dict = {}

    # Create nodes from records
    for record in parser:
        class_call = eval(record.pop('type'))
        if '_parent' in record:
            parent_dict[record['_taxid']] = record.pop('_parent')

        # Class attributes are hidden and therefore start with "_"
        # Init takes same named arguments with the "_"
        txd[record['_taxid']] = class_call(
            **{k[1:]: v for k, v in record.items()}
        )

    # Update parent info
    for k, v in parent_dict.items():
        if v:
            txd[k].parent = txd[v]

    return Taxonomy(txd)


def _parse_dump(filepath: str) -> Iterator:
    """
    Dump file line iterator, returns a yields of fields
    """
    with open(filepath, 'r') as dmp:
        for line in dmp:
            yield [item.strip() for item in line.split("|")]
