"""Perform queries against the ontology and taxonomy endpoints
"""
from ensembl_rest_client.base import base_rest_client as brc


# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
class _OntologiesAndTaxonomy(object):
    """Perform OntologiesAndTaxonomy queries
    """
    # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    def get_ontology_ancestors(self, query_id, ontology=None,
                               norm_func=brc.default_pandas):
        """
        Reconstruct the entire ancestry of a term from is_a and part_of
        relationships. GET method. Queries:
        `ontology/ancestors/:id <https://rest.ensembl.org/documentation/info/ontology_ancestors>`_.

        Parameters
        ----------
        query_id : str
            An ontology term identifier. Example values: 'GO:0005667'.
        ontology : str or NoneType, optional, default: NoneType
            Filter by ontology. Used to disambiguate terms which are shared
            between ontologies such as GO and EFO. Example values: 'GO'.
        norm_func : obj:`func`, optional, default: default_pandas
            The normalisation function to use when obj.pandas is True

        Returns
        -------
        data : list or dict or :obj:`pandas.DataFrame`
            The rest query data
        """
        method_type = 'GET'
        endpoint = 'ontology/ancestors/{id}'.format(
            id=query_id
        )

        return self.rest_query(
            method_type,
            endpoint,
            ontology=ontology,
            norm_func=norm_func
        )

    # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    def get_ontology_ancestors_chart(self, query_id, ontology=None,
                                     norm_func=brc.default_pandas):
        """
        Reconstruct the entire ancestry of a term from is_a and part_of
        relationships. GET method. Queries:
        `ontology/ancestors/chart/:id <https://rest.ensembl.org/documentation/info/ontology_ancestors_chart>`_.

        Parameters
        ----------
        query_id : str
            An ontology term identifier. Example values: 'GO:0005667'.
        ontology : str or NoneType, optional, default: NoneType
            Filter by ontology. Used to disambiguate terms which are shared
            between ontologies such as GO and EFO. Example values: 'GO'.
        norm_func : obj:`func`, optional, default: default_pandas
            The normalisation function to use when obj.pandas is True

        Returns
        -------
        data : list or dict or :obj:`pandas.DataFrame`
            The rest query data
        """
        method_type = 'GET'
        endpoint = 'ontology/ancestors/chart/{id}'.format(
            id=query_id
        )

        return self.rest_query(
            method_type,
            endpoint,
            ontology=ontology,
            norm_func=norm_func
        )

    # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    def get_ontology_descendants(self, query_id, closest_term=None,
                                 ontology=None, subset=None,
                                 zero_distance=None,
                                 norm_func=brc.default_pandas):
        """
        Find all the terms descended from a given term. By default searches are
        conducted within the namespace of the given identifier. GET method.
        Queries:
        `ontology/descendants/:id <https://rest.ensembl.org/documentation/info/ontology_descendants>`_.

        Parameters
        ----------
        query_id : str
            An ontology term identifier. Example values: 'GO:0005667'.
        closest_term : bool or NoneType, optional, default: NoneType
            If true return only the closest terms to the specified term.
        ontology : str or NoneType, optional, default: NoneType
            Filter by ontology. Used to disambiguate terms which are shared
            between ontologies such as GO and EFO. Example values: 'GO'.
        subset : str or NoneType, optional, default: NoneType
            Filter terms by the specified subset. Example values:
            'goslim_generic goslim_metagenomics'.
        zero_distance : bool or NoneType, optional, default: NoneType
            Return terms with a distance of 0.
        norm_func : obj:`func`, optional, default: default_pandas
            The normalisation function to use when obj.pandas is True

        Returns
        -------
        data : list or dict or :obj:`pandas.DataFrame`
            The rest query data
        """
        method_type = 'GET'
        endpoint = 'ontology/descendants/{id}'.format(
            id=query_id
        )

        return self.rest_query(
            method_type,
            endpoint,
            closest_term=closest_term,
            ontology=ontology,
            subset=subset,
            zero_distance=zero_distance,
            norm_func=norm_func
        )

    # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    def get_ontology_id(self, query_id, relation=None, simple=None,
                        norm_func=brc.default_pandas):
        """
        Search for an ontological term by its namespaced identifier. GET
        method. Queries:
        `ontology/id/:id <https://rest.ensembl.org/documentation/info/ontology_id>`_.

        Parameters
        ----------
        query_id : str
            An ontology term identifier. Example values: 'GO:0005667'.
        relation : str or NoneType, optional, default: NoneType
            The types of relationships to include in the output. Fetches all
            relations by default. Example values: 'is_a part_of'.
        simple : bool or NoneType, optional, default: NoneType
            If set the API will avoid the fetching of parent and child terms.
        norm_func : obj:`func`, optional, default: default_pandas
            The normalisation function to use when obj.pandas is True

        Returns
        -------
        data : list or dict or :obj:`pandas.DataFrame`
            The rest query data
        """
        method_type = 'GET'
        endpoint = 'ontology/id/{id}'.format(
            id=query_id
        )

        return self.rest_query(
            method_type,
            endpoint,
            relation=relation,
            simple=simple,
            norm_func=norm_func
        )

    # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    def get_ontology_name(self, name, ontology=None, relation=None,
                          simple=None, norm_func=brc.default_pandas):
        """
        Search for a list of ontological terms by their name. GET method.
        Queries:
        `ontology/name/:name <https://rest.ensembl.org/documentation/info/ontology_name>`_.

        Parameters
        ----------
        name : str
            An ontology name. SQL wildcards are supported. Example values:
            'transcription factor complex'.
        ontology : str or NoneType, optional, default: NoneType
            Filter by ontology. Used to disambiguate terms which are shared
            between ontologies such as GO and EFO. Example values: 'GO'.
        relation : str or NoneType, optional, default: NoneType
            The types of relationships to include in the output. Fetches all
            relations by default. Example values: 'is_a part_of'.
        simple : bool or NoneType, optional, default: NoneType
            If set the API will avoid the fetching of parent and child terms.
        norm_func : obj:`func`, optional, default: default_pandas
            The normalisation function to use when obj.pandas is True

        Returns
        -------
        data : list or dict or :obj:`pandas.DataFrame`
            The rest query data
        """
        method_type = 'GET'
        endpoint = 'ontology/name/{name}'.format(
            name=name
        )

        return self.rest_query(
            method_type,
            endpoint,
            ontology=ontology,
            relation=relation,
            simple=simple,
            norm_func=norm_func
        )

    # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    def get_taxonomy_classification(self, query_id,
                                    norm_func=brc.default_pandas):
        """
        Return the taxonomic classification of a taxon node. GET method.
        Queries:
        `taxonomy/classification/:id <https://rest.ensembl.org/documentation/info/taxonomy_classification>`_.

        Parameters
        ----------
        query_id : str
            A taxon identifier. Can be a NCBI taxon id or a name. Example
            values: '9606 Homo sapiens'.
        norm_func : obj:`func`, optional, default: default_pandas
            The normalisation function to use when obj.pandas is True

        Returns
        -------
        data : list or dict or :obj:`pandas.DataFrame`
            The rest query data
        """
        method_type = 'GET'
        endpoint = 'taxonomy/classification/{id}'.format(
            id=query_id
        )

        return self.rest_query(
            method_type,
            endpoint,
            norm_func=norm_func
        )

    # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    def get_taxonomy_id(self, query_id, simple=None,
                        norm_func=brc.default_pandas):
        """
        Search for a taxonomic term by its identifier or name. GET method.
        Queries:
        `taxonomy/id/:id <https://rest.ensembl.org/documentation/info/taxonomy_id>`_.

        Parameters
        ----------
        query_id : str
            A taxon identifier. Can be a NCBI taxon id or a name. Example
            values: '9606 Homo sapiens'.
        simple : bool or NoneType, optional, default: NoneType
            If set the API will avoid the fetching of parent and child terms.
        norm_func : obj:`func`, optional, default: default_pandas
            The normalisation function to use when obj.pandas is True

        Returns
        -------
        data : list or dict or :obj:`pandas.DataFrame`
            The rest query data
        """
        method_type = 'GET'
        endpoint = 'taxonomy/id/{id}'.format(
            id=query_id
        )

        return self.rest_query(
            method_type,
            endpoint,
            simple=simple,
            norm_func=norm_func
        )

    # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    def get_taxonomy_name(self, name, norm_func=brc.default_pandas):
        """
        Search for a taxonomic id by a non-scientific name. GET method. Queries:
        `taxonomy/name/:name <https://rest.ensembl.org/documentation/info/taxonomy_name>`_.

        Parameters
        ----------
        name : str
            A non-scientific species name. Can include SQL wildcards. Example
            values: 'Homo%25'.
        norm_func : obj:`func`, optional, default: default_pandas
            The normalisation function to use when obj.pandas is True

        Returns
        -------
        data : list or dict or :obj:`pandas.DataFrame`
            The rest query data
        """
        method_type = 'GET'
        endpoint = 'taxonomy/name/{name}'.format(
            name=name
        )

        return self.rest_query(
            method_type,
            endpoint,
            norm_func=norm_func
        )


# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
class OntologiesAndTaxonomy(brc._BaseRestClient, _OntologiesAndTaxonomy):
    """Perform OntologiesAndTaxonomy queries
    """
    pass
