from __future__ import division

from abc import ABC, abstractmethod
from typing import Optional

from mapproxy.image import BaseImageResult
from mapproxy.grid.resolutions import ResolutionRange
from mapproxy.layer import BlankImageError
from mapproxy.image.opts import ImageOptions
from mapproxy.util.coverage import Coverage
from mapproxy.query import MapQuery


class MapLayer(ABC):
    supports_meta_tiles = False

    res_range: Optional[ResolutionRange] = None

    coverage: Optional[Coverage] = None

    def __init__(self, image_opts=None):
        self.image_opts = image_opts or ImageOptions()

    @property
    def opacity(self) -> Optional[float]:
        return self.image_opts.opacity

    @opacity.setter
    def opacity(self, value: Optional[float]):
        self.image_opts.opacity = value

    def is_opaque(self, query):
        """
        Whether the query result is opaque.

        This method is used for optimizations: layers below an opaque
        layer can be skipped. As sources with `transparent: false`
        still can return transparent images (min_res/max_res/coverages),
        implementations of this method need to be certain that the image
        is indeed opaque. is_opaque should return False if in doubt.
        """
        return False

    def check_res_range(self, query):
        if (self.res_range and
                not self.res_range.contains(query.bbox, query.size, query.srs)):
            raise BlankImageError()

    @abstractmethod
    def get_map(self, query: MapQuery) -> BaseImageResult:
        pass

    def combined_layer(self, other, query):
        return None
