#-*- coding: utf-8 -*-
u"""

.. moduleauthor:: Martí Congost <marti.congost@whads.com>
"""
from time import time
from simplejson import loads
from urllib import urlopen
from cocktail.iteration import first
from cocktail.events import event_handler
from cocktail.translations import translations
from cocktail import schema
from cocktail.persistence import datastore
from woost.models import Extension

translations.define("LocationsExtension",
    ca = u"Localitats",
    es = u"Localidad",
    en = u"Locations"
)

translations.define("LocationsExtension.update_frequency",
    ca = u"Freqüència d'actualització",
    es = u"Frecuencia de actualización",
    en = u"Update frequency"
)

translations.define("LocationsExtension.update_frequency-explanation",
    ca = u"El nombre de dies entre actualitzacions de la llista de localitats."
         u" Deixar en blanc per desactivar les actualitzacions.",
    es = u"El número de días entre actualizaciones de la lista de localidades."
         u" Dejar en blanco para desactivar las actualizaciones.",
    en = u"Number of days between updates to the list of locations. "
         u"Leave blank to disable updates."
)

translations.define("LocationsExtension.updated_location_types",
    ca = u"Tipus de localització a obtenir",
    es = u"Tipos de localización a obtener",
    en = u"Location types included in updates"
)

translations.define("LocationsExtension.updated_subset",
    ca = u"Subconjunt de localitats a actualitzar",
    es = u"Subconjunto de localidades a actualizar",
    en = u"Subset of locations included in updates"
)

translations.define("LocationsExtension.updated_subset-explanation",
    ca = u"Llistat de codis qualificats de localitat (per exemple, EU-ES-CT, "
         u"EU-ES-CV per seleccionar Catalunya i la Comunitat Valenciana).",
    es = u"Listado de códigos cualificados de localidad (por ejemplo, "
         u"EU-ES-CT, EU-ES-CV para seleccionar Cataluña y la Comunidad "
         u"Valenciana).",
    en = u"List of qualified location codes (ie. EU-ES-CT, EU-ES-CV to "
         u"select Catalonia and the Valencian Country)."
)

SECONDS_IN_A_DAY = 60 * 60 * 24


class LocationsExtension(Extension):

    def __init__(self, **values):
        Extension.__init__(self, **values)
        self.extension_author = u"Whads/Accent SL"
        self.set("description",
            u"""Proporciona accés a la llista de països del món i les seves
            regions, actualitzada a través d'Internet.""",
            "ca"
        )
        self.set("description",            
            u"""Proporciona acceso a la lista de países del mundo y sus
            regiones, actualizada a través de Internet.""",
            "es"
        )
        self.set("description",
            u"""Provides a list of world countries and their regions, 
            automatically updated from the Internet.""",
            "en"
        )

    last_update = None

    members_order = [
        "service_uri",
        "update_frequency",
        "updated_location_types",
        "updated_subset"
    ]

    service_uri = schema.String(
        required = True,
        default = "http://services.woost.info/locations",
        text_search = False
    )

    update_frequency = schema.Integer(
        min = 1,
        default = 15
    )

    updated_location_types = schema.Collection(
        edit_inline = True,
        default = [
            "continent",
            "country",
            "autonomous_community",
            "province",
            "town"
        ],
        items = schema.String(
            required = True,
            enumeration = [
                "continent", 
                "country", 
                "autonomous_community",
                "province",
                "town"
            ],            
            translate_value = lambda value, language = None, **kwargs:
                "" if not value 
                else translations(
                    "woost.extensions.locations.location_types." + value,
                    language,
                    **kwargs
                )
        ),
        text_search = False
    )

    updated_subset = schema.Collection(
        items = schema.String(
            required = True
        ),
        edit_control = "cocktail.html.TextArea"
    )

    @event_handler
    def handle_loading(cls, event):
        
        from woost.extensions.locations import location, strings

        now = time()
        ext = event.source

        if ext.last_update is None \
        or (
            ext.update_frequency is not None
            and now - ext.last_update >= ext.update_frequency * SECONDS_IN_A_DAY
        ):
            ext.sync_locations()
            ext.last_update = now
            datastore.commit()

    def sync_locations(self):
        """Populate the locations database with the data provided by the web
        service.
        """
        text_data = urlopen(self.service_uri).read()
        json_data = loads(text_data)

        for record in json_data:
            self._process_record(record)

    def _process_record(self, record, parent = None, context = None):
        
        from woost.extensions.locations.location import Location

        context = context.copy() if context else {}
        code = record["code"]
        location = None

        if "full_code" in context:
            context["full_code"] += "-" + code
        else:
            context["full_code"] = code

        if self._should_add_location(record, parent, context):

            # Update an existing location
            if parent: 
                location = first(
                    child
                    for child in parent.locations
                    if child.code == code
                )
            else:
                location = first(Location.select([
                    Location.parent.equal(None),
                    Location.code.equal(code)
                ]))

            # Create a new location
            if location is None:
                location = Location()
                location.parent = parent
                location.code = code
                location.insert()

            location.location_type = record["type"]

            for lang, value in record["name"].iteritems():
                if isinstance(value, str):
                    value = value.decode("utf-8")
                location.set("location_name", value, lang)

        # Process child records
        children = record.get("locations")
        if children:
            for child_record in children:
                self._process_record(child_record, location, context)

    def _should_add_location(self, record, parent, context):

        # Filter by tree subset
        if self.updated_subset:
            if not context.get("inside_subset") \
            and context["full_code"] not in self.updated_subset:
                return False
            else:
                context["inside_subset"] = True

        # Filter by location type
        if record["type"] not in self.updated_location_types:
            return False

        return True

