from typing import List, Optional, Union

from axipy.cpp_gui import ShadowMapView
from axipy.cpp_render import ShadowContext, ShadowMapReportItem
from axipy.cs import CoordSystem
from axipy.da import Geometry

__all__: List[str] = [
    "ClipGeometry",
]


class ClipGeometry:
    """Обрезка карты по выбранному участку."""

    _shadow: Union[ShadowMapReportItem, ShadowMapView, ShadowContext]

    def __init__(self) -> None:
        raise NotImplementedError

    @classmethod
    def _wrap(cls, shadow: Union[ShadowMapReportItem, ShadowMapView, ShadowContext]) -> "ClipGeometry":
        result = ClipGeometry.__new__(cls)
        result._shadow = shadow
        return result

    def __redraw(self) -> None:
        if isinstance(self._shadow, (ShadowMapView, ShadowMapReportItem)):
            self._shadow.redraw()

    @property
    def geometry(self) -> Optional[Geometry]:
        """
        Геометрия обрезки карты. Устанавливается геометрия, в рамках которой будет
        отрисована карта. За пределами отрисовка производиться не будет. Обрабатываются
        только площадные объекты. Так-же допустимо устанавливать коллекции.

        .. seealso::
            Элемент отчета :attr:`MapReportItem.clip`

        .. seealso::
            Окно карты :attr:`MapView.clip`

        .. seealso::
            Окно карты :attr:`Context.clip`
        """
        return Geometry._wrap(
            self._shadow.get_clip_geometry(self._shadow),  # type: ignore[arg-type]
        )

    @geometry.setter
    def geometry(self, geometry: Optional[Geometry]) -> None:
        if geometry is None:
            self._shadow.set_clip_geometry(None)
        else:
            if geometry.coordsystem is None and isinstance(self._shadow, (ShadowMapView, ShadowMapReportItem)):
                geometry.coordsystem = CoordSystem._wrap(self._shadow.coordsystem())
            self._shadow.set_clip_geometry(geometry._shadow)
            self.status = True
        self.__redraw()

    @property
    def status(self) -> bool:
        """
        Включение режима обрезки карты :attr:`geometry`.

        Если устанавливается значение True и отсутствует геометрия, то установка не
        производится.
        """
        return self._shadow.get_clip_geometry_status()

    @status.setter
    def status(self, status: bool) -> None:
        self._shadow.set_clip_geometry_status(status)
        self.__redraw()

    @property
    def buffer(self) -> int:
        """
        Размер буфера в координатах экрана или же растра.

        Это может быть необходимо когда объект обрезки имеет стиль оформления по контуру
        и этот контур необходимо включить.
        """
        return self._shadow.get_clip_geometry_buffer()

    @buffer.setter
    def buffer(self, w: int) -> None:
        self._shadow.set_clip_geometry_buffer(w)
        self.__redraw()
