# ===========================================================================
# Copyright (C) 2006 Ancient World Mapping Center
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
# 
# About Pleiades
# --------------
#
# Pleiades is an international research network and associated web portal and
# content management system devoted to the study of ancient geography. 
#
# See http://icon.stoa.org/trac/pleiades/wiki.
#
# Funding for the creation of this software was provided by a grant from the 
# U.S. National Endowment for the Humanities (http://www.neh.gov).
# ===========================================================================

from zope.interface import Interface, implements

from Products.Five import BrowserView
from Products.PleiadesGeocoder.interfaces import IGeoCollectionSimple


class IGeoInfosetView(Interface):

    def forRSS(maxitems):
        """Returns an iterator over GeoRSS compatible data.
        
        Arguments
        ---------
        maxitems : int (optional)
            Iteration will be truncated at specified number.
        """

    def forKML():
        """Returns an iterator over KML compatible data."""


def coords_to_kml(geom):
    gtype = geom['type']
    if gtype == 'Point':
        coords = (geom['coordinates'],)
    elif gtype == 'Polygon':
        coords = geom['coordinates'][0]
    else:
        coords = geom['coordinates']
    if len(coords[0]) == 2:
        tuples = ('%f,%f,0.0' % c for c in coords)
    elif len(coords[0]) == 3:
        tuples = ('%f,%f,%f' % c for c in coords)
    else:
        raise ValueError, "Invalid dimensions"
    return ' '.join(tuples)

def coords_to_georss(geom):
    gtype = geom['type']
    if gtype == 'Point':
        coords = (geom['coordinates'],)
    elif gtype == 'Polygon':
        coords = geom['coordinates'][0]
    else:
        coords = geom['coordinates']
    tuples = ('%f %f' % (c[1], c[0]) for c in coords)
    return ' '.join(tuples)


class GeoInfosetView(BrowserView):

    """View of content that supports GeoRSS and KML output.
    """
    implements(IGeoInfosetView)

    def __init__(self, context, request):
        self.context = context
        self.request = request
        self.collection = IGeoCollectionSimple(self.context)

    def forRSS(self, maxitems=-1):
        """Get a sequence of informative dicts"""
        collection = self.collection
        if maxitems < 0:
            for item in collection.geoItems():
                info = item.__geo_interface__
                info.update({
                    'hasPoint': int(item.geom_type == 'Point') ,
                    'hasLineString': int(item.geom_type == 'LineString'),
                    'hasPolygon': int(item.geom_type == 'Polygon'),
                    'coords_georss': coords_to_georss(info['geometry']),
                    })
                yield info
        else:
            i = 0
            for item in collection.geoItems():
                if i >= maxitems:
                    raise StopIteration
                info = item.__geo_interface__
                info.update({
                    'hasPoint': int(item.geom_type == 'Point') ,
                    'hasLineString': int(item.geom_type == 'LineString'),
                    'hasPolygon': int(item.geom_type == 'Polygon'),
                    'coords_georss': coords_to_georss(info['geometry']),
                    })
                yield info
                i += 1

    def forKML(self):
        """Get a sequence of informative dicts"""
        collection = self.collection
        for item in collection.geoItems():
            info = item.__geo_interface__
            info.update({
                'hasPoint': int(item.geom_type == 'Point') ,
                'hasLineString': int(item.geom_type == 'LineString'),
                'hasPolygon': int(item.geom_type == 'Polygon'),
                'coords_kml': coords_to_kml(info['geometry'])
                })
            yield info


def get_coords(coord_string, geomtype='point'):
    values = [float(v) for v in coord_string.split()]
    nvalues = len(values)
    npoints = nvalues/3
    coords = []
    for i in range(npoints):
        coords.append((values[3*i+1], values[3*i], values[3*i+2]))
    if geomtype == 'point':
        return coords[0]
    elif geomtype == 'line':
        return tuple(coords)
    elif geomtype == 'polygon':
        return (tuple(coords),)


class GeoMembersInfosetView(BrowserView):

    """View of content that supports GeoRSS and KML output.
    """
    implements(IGeoInfosetView)

    def forRSS(self, maxitems=-1):
        """Get a sequence of informative dicts"""
        folder = self.context
        infos = []
        for ob in folder.listFolderContents():
            id = ob.getId()
            member = folder.portal_membership.getMemberById(id)
            if not member:
                continue
            
            gtype = member.getProperty('geometryType', None)
            gcoords = member.getProperty('spatialCoordinates', '')            
            if not gtype or not gcoords:
                # member is not georeferenced
                continue
            
            geom_type = gtype.capitalize()
            if geom_type == 'Line':
                geom_type = 'LineString'

            info = {
                'geometry': {
                    'type': geom_type,
                    'coordinates': get_coords(gcoords),
                    }
                }
 
            gc = info['geometry']['coordinates']
            coords_georss = '%f %f' % (gc[1], gc[0])

            info.update({
                'id': id,
                'properties': {
                    'title': member.getProperty('fullname'),
                    'description' : member.getProperty('description'),
                    'location' : member.getProperty('location'),
                    'language' : member.getProperty('language'),
                    'link' : "%s/author/%s" % (folder.portal_url(), id),
                    },
                'hasPoint': int(geom_type == 'Point'),
                'hasLineString': int(geom_type == 'LineString'),
                'hasPolygon': int(geom_type == 'Polygon'),
                'coords_georss': coords_georss,
                })
            
            # Work around OpenLayers bug
            if len(info['properties']['description']) < 1:
                info['properties']['description'] = 'No description'
            if len(info['properties']['title']) < 1:
                info['properties']['title'] = 'No title'
            yield info

    def forKML(self):
        """Get a sequence of informative dicts"""
        folder = self.context
        infos = []
        for ob in folder.listFolderContents():
            id = ob.getId()
            member = folder.portal_membership.getMemberById(id)
            if not member:
                continue
            gtype = member.getProperty('geometryType', None)
            gcoords = member.getProperty('spatialCoordinates', '')            
            if not gtype or not gcoords:
                # member is not georeferenced
                continue
            
            geom_type = gtype.capitalize()
            if geom_type == 'Line':
                geom_type = 'LineString'

            info = {
                'geometry': {
                    'type': geom_type,
                    'coordinates': get_coords(gcoords),
                    }
                }
 
            info.update({
                'id': id,
                'properties': {
                    'title': member.getProperty('fullname'),
                    'description' : member.getProperty('description'),
                    'location' : member.getProperty('location'),
                    'language' : member.getProperty('language'),
                    'link' : "%s/author/%s" % (folder.portal_url(), id),
                    },
                'hasPoint': int(geom_type == 'Point'),
                'hasLineString': int(geom_type == 'LineString'),
                'hasPolygon': int(geom_type == 'Polygon'),
                'coords_kml': coords_to_kml(info['geometry']),
                })
            
            # Work around OpenLayers bug
            if len(info['properties']['description']) < 1:
                info['properties']['description'] = 'No description'
            if len(info['properties']['title']) < 1:
                info['properties']['title'] = 'No title'
            yield info

