#!/usr/bin/env python
# -*- coding: utf-8 -*-

from nose.tools import *
import tempfile
import os, mapnik
from nose.tools import *
from utilities import execution_path

def setup():
    # All of the paths used are relative, if we run the tests
    # from another directory we need to chdir()
    os.chdir(execution_path('.'))


def test_simplest_render():
    m = mapnik.Map(256, 256)
    i = mapnik.Image(m.width, m.height)

    mapnik.render(m, i)

    s = i.tostring()

    eq_(s, 256 * 256 * '\x00\x00\x00\x00')

def test_render_image_to_string():
    i = mapnik.Image(256, 256)

    i.background = mapnik.Color('black')

    s = i.tostring()

    eq_(s, 256 * 256 * '\x00\x00\x00\xff')

    s = i.tostring('png')

def test_setting_alpha():
    w,h = 256,256
    im1 = mapnik.Image(w,h)
    # white, half transparent
    im1.background = mapnik.Color('rgba(255,255,255,.5)')

    # pure white
    im2 = mapnik.Image(w,h)
    im2.background = mapnik.Color('rgba(255,255,255,1)')
    im2.set_alpha(.5)

    eq_(len(im1.tostring()), len(im2.tostring()))


def test_render_image_to_file():
    i = mapnik.Image(256, 256)

    i.background = mapnik.Color('black')

    if mapnik.has_jpeg():
        i.save('test.jpg')
    i.save('test.png', 'png')

    if os.path.exists('test.jpg'):
        os.remove('test.jpg')
    else:
        return False

    if os.path.exists('test.png'):
        os.remove('test.png')
    else:
        return False

def get_paired_images(w,h,mapfile):
    tmp_map = 'tmp_map.xml'
    m = mapnik.Map(w,h)
    mapnik.load_map(m,mapfile)
    i = mapnik.Image(w,h)
    m.zoom_all()
    mapnik.render(m,i)
    mapnik.save_map(m,tmp_map)
    m2 = mapnik.Map(w,h)
    mapnik.load_map(m2,tmp_map)
    i2 = mapnik.Image(w,h)
    m2.zoom_all()
    mapnik.render(m2,i2)
    os.remove(tmp_map)
    return i,i2    

def test_render_from_serialization():
    try:
        i,i2 = get_paired_images(100,100,'../data/good_maps/building_symbolizer.xml')
        eq_(i.tostring(),i2.tostring())

        i,i2 = get_paired_images(100,100,'../data/good_maps/polygon_symbolizer.xml')
        eq_(i.tostring(),i2.tostring())
    except RuntimeError, e:
        # only test datasources that we have installed
        if not 'Could not create datasource' in str(e):
            raise RuntimeError(e)

grid_correct = {"keys": ["", "North West", "North East", "South West", "South East"], "data": {"South East": {"Name": "South East"}, "North East": {"Name": "North East"}, "North West": {"Name": "North West"}, "South West": {"Name": "South West"}}, "grid": ["                                                                ", "                                                                ", "                                                                ", "                                                                ", "                                                                ", "                                                                ", "                                                                ", "                                                                ", "                                                                ", "                                                                ", "                                                                ", "                                                                ", "                                                                ", "                                                                ", "                                                                ", "                                                                ", "                                                                ", "                                                                ", "                                                                ", "                                                                ", "                                                                ", "                                                                ", "                                                                ", "         !!!                                 ###                ", "        !!!!!                               #####               ", "        !!!!!                               #####               ", "         !!!                                 ###                ", "                                                                ", "                                                                ", "                                                                ", "                                                                ", "                                                                ", "                                                                ", "                                                                ", "                                                                ", "                                                                ", "        $$$$                                %%%%                ", "        $$$$$                               %%%%%               ", "        $$$$$                               %%%%%               ", "         $$$                                 %%%                ", "                                                                ", "                                                                ", "                                                                ", "                                                                ", "                                                                ", "                                                                ", "                                                                ", "                                                                ", "                                                                ", "                                                                ", "                                                                ", "                                                                ", "                                                                ", "                                                                ", "                                                                ", "                                                                ", "                                                                ", "                                                                ", "                                                                ", "                                                                ", "                                                                ", "                                                                ", "                                                                ", "                                                                "]}


def resolve(grid,x,y):
    """ Resolve the attributes for a given pixel in a grid.

    js version: 
      https://github.com/mapbox/mbtiles-spec/blob/master/1.1/utfgrid.md
    spec:
      https://github.com/mapbox/wax/blob/master/control/lib/gridutil.js

    """
    utf_val = grid['grid'][x][y]
    #http://docs.python.org/library/functions.html#ord
    codepoint = ord(utf_val)
    if (codepoint >= 93):
        codepoint-=1
    if (codepoint >= 35):
        codepoint-=1
    codepoint -= 32
    key = grid['keys'][codepoint]
    return grid['data'].get(key)


def test_render_grid():
    ds = mapnik.MemoryDatasource()
    context = mapnik.Context()
    context.push('Name')
    f = mapnik.Feature(context,1)
    f['Name'] = 'South East'
    f.add_geometries_from_wkt('POINT (143.10 -38.60)')
    ds.add_feature(f)

    f = mapnik.Feature(context,2)
    f['Name'] = 'South West'
    f.add_geometries_from_wkt('POINT (142.48 -38.60)')
    ds.add_feature(f)

    f = mapnik.Feature(context,3)
    f['Name'] = 'North West'
    f.add_geometries_from_wkt('POINT (142.48 -38.38)')
    ds.add_feature(f)

    f = mapnik.Feature(context,4)
    f['Name'] = 'North East'
    f.add_geometries_from_wkt('POINT (143.10 -38.38)')
    ds.add_feature(f)

    s = mapnik.Style()
    r = mapnik.Rule()
    symb = mapnik.MarkersSymbolizer()
    symb.width = mapnik.Expression('10')
    symb.height = mapnik.Expression('10')
    symb.allow_overlap = True
    r.symbols.append(symb)
    s.rules.append(r)
    lyr = mapnik.Layer('Places')
    lyr.datasource = ds
    lyr.styles.append('places_labels')
    m = mapnik.Map(256,256)
    m.append_style('places_labels',s)
    m.layers.append(lyr)
    ul_lonlat = mapnik.Coord(142.30,-38.20)
    lr_lonlat = mapnik.Coord(143.40,-38.80)
    m.zoom_to_box(mapnik.Box2d(ul_lonlat,lr_lonlat))
    grid = mapnik.render_grid(m,0,key='Name',resolution=4,fields=['Name'])
    eq_(grid,grid_correct)
    eq_(resolve(grid,0,0),None)

    # check every pixel of the nw symbol
    expected = {"Name": "North West"}

    # top row
    eq_(resolve(grid,23,9),expected)
    eq_(resolve(grid,23,10),expected)
    eq_(resolve(grid,23,11),expected)

    # core
    eq_(resolve(grid,24,8),expected)
    eq_(resolve(grid,24,9),expected)
    eq_(resolve(grid,24,10),expected)
    eq_(resolve(grid,24,11),expected)
    eq_(resolve(grid,24,12),expected)
    eq_(resolve(grid,25,8),expected)
    eq_(resolve(grid,25,9),expected)
    eq_(resolve(grid,25,10),expected)
    eq_(resolve(grid,25,11),expected)
    eq_(resolve(grid,25,12),expected)

    # bottom row
    eq_(resolve(grid,26,9),expected)
    eq_(resolve(grid,26,10),expected)
    eq_(resolve(grid,26,11),expected)

def test_render_points():

    if not mapnik.has_cairo(): return

    # create and populate point datasource (WGS84 lat-lon coordinates)
    ds = mapnik.MemoryDatasource()
    context = mapnik.Context()
    context.push('Name')
    f = mapnik.Feature(context,1)
    f['Name'] = 'Westernmost Point'
    f.add_geometries_from_wkt('POINT (142.48 -38.38)')
    ds.add_feature(f)

    f = mapnik.Feature(context,2)
    f['Name'] = 'Southernmost Point'
    f.add_geometries_from_wkt('POINT (143.10 -38.60)')
    ds.add_feature(f)

    # create layer/rule/style
    s = mapnik.Style()
    r = mapnik.Rule()
    symb = mapnik.PointSymbolizer()
    symb.allow_overlap = True
    r.symbols.append(symb)
    s.rules.append(r)
    lyr = mapnik.Layer('Places','+proj=latlon +datum=WGS84')
    lyr.datasource = ds
    lyr.styles.append('places_labels')
    # latlon bounding box corners
    ul_lonlat = mapnik.Coord(142.30,-38.20)
    lr_lonlat = mapnik.Coord(143.40,-38.80)
    # render for different projections 
    projs = { 
        'latlon': '+proj=latlon +datum=WGS84',
        'merc': '+proj=merc +datum=WGS84 +k=1.0 +units=m +over +no_defs',
        'google': '+proj=merc +ellps=sphere +R=6378137 +a=6378137 +units=m',
        'utm': '+proj=utm +zone=54 +datum=WGS84'
        }
    for projdescr in projs.iterkeys():
        m = mapnik.Map(1000, 500, projs[projdescr])
        m.append_style('places_labels',s)
        m.layers.append(lyr)
        p = mapnik.Projection(projs[projdescr])
        m.zoom_to_box(p.forward(mapnik.Box2d(ul_lonlat,lr_lonlat)))
        # Render to SVG so that it can be checked how many points are there with string comparison
        svg_file = os.path.join(tempfile.gettempdir(),'%s.svg')
        mapnik.render_to_file(m, svg_file)
        num_points_present = len(ds.all_features())
        svg = open(svg_file,'r').read()
        num_points_rendered = svg.count('<image ')
        eq_(num_points_present, num_points_rendered, "Not all points were rendered (%d instead of %d) at projection %s" % (num_points_rendered, num_points_present, projdescr)) 

if __name__ == "__main__":
    setup()
    [eval(run)() for run in dir() if 'test_' in run]