from __future__ import annotations

import enum
from typing import final


class Base(enum.Enum):
    __module__ = 'rene.enums'

    def __repr__(self, /) -> str:
        return f'{type(self).__qualname__}.{self.name}'


@final
@enum.unique
class Location(Base):
    #: point lies on the boundary of the geometry
    BOUNDARY = 0
    #: point lies in the exterior of the geometry
    EXTERIOR = -1
    #: point lies in the interior of the geometry
    INTERIOR = 1


@final
@enum.unique
class Orientation(Base):
    CLOCKWISE = -1
    COLLINEAR = 0
    COUNTERCLOCKWISE = 1


@final
@enum.unique
class Relation(Base):
    """
    Represents kinds of relations in which geometries can be.
    Order of members assumes that conditions for previous ones do not hold.
    """

    #: geometry is a strict subset of the other
    #: and interior/boundary of the geometry is a subset
    #: of interior/boundary of the other
    COMPONENT = 1
    #: geometry is a strict superset of the other
    #: and interior/boundary of the geometry is a superset
    #: of interior/boundary of the other
    COMPOSITE = 2
    #: interior of the geometry is a superset of the other
    COVER = 3
    #: intersection is a strict subset of each of the geometries,
    #: has dimension less than at least of one of the geometries,
    #: one of the geometries intersects interior of the other
    #: or if we traverse boundary of each of the geometries in any direction
    #: then boundary of the other geometry will be on both sides
    #: at some point of boundaries intersection
    CROSS = 4
    #: at least one geometry is non-empty and intersection is empty
    DISJOINT = 5
    #: at least one boundary point of the geometry
    #: lies on the boundary of the other, but not all,
    #: other points of the geometry lie in the interior of the other
    ENCLOSED = 6
    #: boundary of the geometry contains
    #: at least one boundary point of the other, but not all,
    #: interior of the geometry contains other points of the other
    ENCLOSES = 7
    #: geometries are equal
    EQUAL = 8
    #: intersection is a strict subset of each of the geometries
    #: and has the same dimension as geometries
    OVERLAP = 9
    #: intersection is a strict subset of each of the geometries,
    #: has dimension less than at least of one of the geometries
    #: and if we traverse boundary of each of the geometries in any direction
    #: then boundary of the other geometry won't be on one of sides
    #: at each point of boundaries intersection
    TOUCH = 10
    #: geometry is a subset of the interior of the other
    WITHIN = 11

    @property
    def complement(self, /) -> Relation:
        if (
            self is Relation.CROSS
            or self is Relation.DISJOINT
            or self is Relation.EQUAL
            or self is Relation.OVERLAP
            or self is Relation.TOUCH
        ):
            return self
        if self is Relation.COMPONENT:
            return Relation.COMPOSITE
        if self is Relation.COMPOSITE:
            return Relation.COMPONENT
        if self is Relation.COVER:
            return Relation.WITHIN
        if self is Relation.ENCLOSED:
            return Relation.ENCLOSES
        if self is Relation.ENCLOSES:
            return Relation.ENCLOSED
        assert self is Relation.WITHIN
        return Relation.COVER
