from django.contrib.auth.models import User
from django.contrib.gis import geos
from django.contrib.gis.db import models
from django.utils.translation import gettext_lazy as _

from osmaxx.utils.geometry_buffer_helper import with_metric_buffer

EARTH_CIRCUMFERENCE_IN_METERS = 40075.017 * 1000
DEGREES_PER_CIRCLE = 360
DEGREES_PER_METERS_AT_EQUATOR = DEGREES_PER_CIRCLE / EARTH_CIRCUMFERENCE_IN_METERS
NYQIST_FACTOR = 1 / 2


class Excerpt(models.Model):
    EXCERPT_TYPE_USER_DEFINED = 'user-defined'
    EXCERPT_TYPE_COUNTRY_BOUNDARY = 'country'
    EXCERPT_TYPES = [
        (EXCERPT_TYPE_USER_DEFINED, _('user defined')),
        (EXCERPT_TYPE_COUNTRY_BOUNDARY, _('country')),
    ]
    name = models.CharField(max_length=128, verbose_name=_('name'))
    is_public = models.BooleanField(default=False, verbose_name=_('is public'))
    is_active = models.BooleanField(default=True, verbose_name=_('is active'))
    owner = models.ForeignKey(User, related_name='excerpts', verbose_name=_('owner'), null=True)
    bounding_geometry = models.MultiPolygonField(verbose_name=_('bounding geometry'), null=True)
    excerpt_type = models.CharField(max_length=40, choices=EXCERPT_TYPES, default=EXCERPT_TYPE_USER_DEFINED)

    COUNTRY_SIMPLIFICATION_TOLERANCE_ANGULAR_DEGREES = 0.01
    BUFFER_METERS = 200

    def send_to_conversion_service(self):
        from osmaxx.api_client.conversion_api_client import ConversionApiClient
        api_client = ConversionApiClient()
        bounding_geometry = self.bounding_geometry
        if self.excerpt_type == self.EXCERPT_TYPE_COUNTRY_BOUNDARY:
            bounding_geometry = self.simplified_buffered()
        return api_client.create_boundary(bounding_geometry, name=self.name)

    def simplified_buffered(self):
        """
        First simplifies, then buffers a copy of the self.bounding_geometry.

        The resulting area completely includes the area enclosed by the bounding_geometry.

        Returns: the resulting area
        """
        simplification_tolerance = DEGREES_PER_METERS_AT_EQUATOR * NYQIST_FACTOR * self.BUFFER_METERS
        original_srid = self.bounding_geometry.srs
        bounding_geometry = self.bounding_geometry.simplify(
            tolerance=simplification_tolerance,
            preserve_topology=True
        )
        bounding_geometry = with_metric_buffer(bounding_geometry, buffer_meters=self.BUFFER_METERS, map_srid=original_srid)
        if not isinstance(bounding_geometry, geos.MultiPolygon):
            bounding_geometry = geos.MultiPolygon(bounding_geometry)
        return bounding_geometry

    @property
    def geometry(self):
        if self.excerpt_type == self.EXCERPT_TYPE_COUNTRY_BOUNDARY:
            return self.bounding_geometry.simplify(
                tolerance=self.COUNTRY_SIMPLIFICATION_TOLERANCE_ANGULAR_DEGREES,
                preserve_topology=True
            )
        return self.bounding_geometry

    @property
    def color(self):
        if self.excerpt_type == self.EXCERPT_TYPE_COUNTRY_BOUNDARY:
            return 'black'
        return 'blue'

    @property
    def extent(self):
        return self.bounding_geometry.extent

    def __str__(self):
        return self.name


def _active_user_defined_excerpts():
    return Excerpt.objects.filter(is_active=True).filter(
        bounding_geometry__isnull=False,
        excerpt_type=Excerpt.EXCERPT_TYPE_USER_DEFINED,
    )


def private_user_excerpts(user):
    return _active_user_defined_excerpts().filter(is_public=False, owner=user)


def public_user_excerpts(user):
    return _active_user_defined_excerpts().filter(is_public=True, owner=user)


def other_users_public_excerpts(user):
    return _active_user_defined_excerpts().filter(is_public=True).exclude(owner=user)

@@ -114,16 +114,52 @@
  models%0A
+from django.core.cache import cache%0A
 from dja
@@ -1304,16 +1304,17 @@
 EES = 0.
+0
 01%0A    B
@@ -1333,16 +1333,70 @@
  = 200%0A%0A
+    CACHE_TIMEOUT_IN_SECONDS = None  # cache forever%0A%0A
     def 
@@ -2065,32 +2065,181 @@
 rea%0A        %22%22%22%0A
+        cache_key = 'excerpt-buffered-%7B%7D'.format(self.pk)%0A%0A        geometry = cache.get(cache_key)%0A        if geometry:%0A            return geometry%0A%0A
         simplifi
@@ -2787,16 +2787,95 @@
 ometry)%0A
+        cache.set(cache_key, bounding_geometry, self.CACHE_TIMEOUT_IN_SECONDS)%0A
         
@@ -3030,33 +3030,37 @@
 rn self.
-bounding_geometry
+simplified_buffered()
 .simplif

simplify and cache