""" Defines the ontology entrytypes
"""

from __future__ import annotations

from typing import Optional


# Define the base class and possible properties of the ontology relations
# ----------------------------------------------------------------------------------------------------------------------
class OntologyType:
    name:           str
    description:    str
    synonyms:       dict[str, str]      # For each source, what this relationship is called

    # Applies to compounds / reactions
    for_comp:       bool
    for_reac:       bool
    for_enzy:       bool

    # Relational properties
    symmetric:      bool
    transitive:     bool
    inverse:        Optional[OntologyType]
        # If there is a corresponding inverse relation. Not applicable if symmetric
    is_primary:     bool  # If relation has an inverse, is_primary is true if this relation is shown
    # If no primaries, then both are shown with a dash /
    # Drawing
    draw:           str                 # 'full' or 'arrow'

    enum_type: 'Ontology'

    def __init__(
        self,
        name: str,
        description: str,
        for_comp: bool,
        for_reac: bool,
        for_enzy: bool,
        symmetric: bool,
        transitive: bool = False,
        inverse: OntologyType = None,
        is_primary: bool = False,
        synonyms: dict[str, str] = None,
        draw = 'full'
    ):
        self.name = name
        self.description = description
        self.for_comp = for_comp
        self.for_reac = for_reac
        self.for_enzy = for_enzy
        self.symmetric = symmetric
        self.transitive = transitive
        self.inverse = inverse
        self.is_primary = is_primary
        self.synonyms = synonyms if synonyms else {}
        self.draw = draw



# Define the ontologies
# ----------------------------------------------------------------------------------------------------------------------

IS_A = OntologyType(
    name = 'Is a',
    description = 'Defines a subclass relation.',
    for_comp = True,
    for_reac = True,
    for_enzy = True,
    symmetric = False,
    synonyms = {
        'chebi': 'is_a'
    }
)

HAS_INSTANCE = OntologyType(
    name = 'Has instance',
    description = 'Reverse of is_a relation',
    for_comp = True,
    for_reac = True,
    for_enzy = True,
    symmetric = False,
)
IS_A.inverse = HAS_INSTANCE
HAS_INSTANCE.inverse = IS_A
IS_A.is_primary = True

HAS_PART = OntologyType(
    name = 'Has part',
    description = 'TODO',
    for_comp = True,
    for_reac = False,
    for_enzy = False,
    symmetric = False,
    synonyms = {
        'chebi': 'has_part'
    }
)

TAUTOMER = OntologyType(
    name = 'Tautomer',
    description = 'TODO',
    for_comp = True,
    for_reac = False,
    for_enzy = False,
    symmetric = True,
    transitive = True,
    synonyms = {
        'chebi': 'is_tautomer_of'
    }
)

CONJUCATE_ACID = OntologyType(
    name = 'Conjugate acid',
    description = 'TODO',
    for_comp = True,
    for_reac = False,
    for_enzy = False,
    symmetric = False,
    transitive = False,
    synonyms = {
        'chebi': 'is_conjugate_acid_of'
    }
)

CONJUGATE_BASE = OntologyType(
    name = 'Conjugate base',
    description = 'TODO',
    for_comp = True,
    for_reac = False,
    for_enzy = False,
    symmetric = False,
    transitive = False,
    synonyms = {
        'chebi': 'is_conjugate_base_of'
    }
)
CONJUCATE_ACID.inverse = CONJUGATE_BASE
CONJUGATE_BASE.inverse = CONJUCATE_ACID

STEREOISOMER = OntologyType(
    name = 'Stereoisomer',
    description = 'TODO',
    for_comp = True,
    for_reac = False,
    for_enzy = False,
    symmetric = True,
    transitive = True,
    synonyms = {}
)

ENANTIOMER = OntologyType(
    name = 'Enantiomer',
    description = 'TODO',
    for_comp = True,
    for_reac = False,
    for_enzy = False,
    symmetric = True,
    transitive = True,
    synonyms = {
        'chebi': 'is_enantiomer_of'
    }
)

HAS_NEW_ID = OntologyType(
    name = 'New ID',
    description = 'Is deprecated ID of',
    for_comp = True,
    for_reac = True,
    for_enzy = True,
    symmetric = False,
    transitive = True,
    synonyms = {},
    draw = 'arrow'
)

HAS_OLD_ID = OntologyType(
    name = 'Old ID',
    description = 'Has deprecated ID',
    for_comp = True,
    for_reac = True,
    for_enzy = True,
    symmetric = False,
    transitive = True,
    synonyms = {},
    draw = 'arrow'
)
HAS_NEW_ID.inverse = HAS_OLD_ID
HAS_OLD_ID.inverse = HAS_NEW_ID
HAS_NEW_ID.is_primary = True


# Make list of all ontology relations
# ----------------------------------------------------------------------------------------------------------------------
ontology_relations: list[OntologyType] = [
    IS_A, HAS_INSTANCE, HAS_PART, TAUTOMER, CONJUCATE_ACID, CONJUGATE_BASE, ENANTIOMER, HAS_NEW_ID, HAS_OLD_ID
]

ont_str_dict: dict[str, OntologyType] = dict()
for rel in ontology_relations:
    ont_str_dict[rel.name] = rel
    for syn in rel.synonyms.values():
        ont_str_dict[syn] = rel

def get_relation_type_from_str(s: str) -> OntologyType | None:
    try:
        return ont_str_dict[s]
    except KeyError:
        return None
