#!/usr/bin/env python

import mapnik

import sys, os

from lxml import html,etree
from optparse import OptionParser

from pprint import pprint

from pyrungps.pygpx import GPX

from pyproj import Transformer

# Set up projections
# spherical mercator (most common target map projection of osm data imported with osm2pgsql)
#merc = mapnik.Projection('+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +no_defs +over')

# long/lat in degrees, aka ESPG:4326 and "WGS 84" 
#longlat = mapnik.Projection('+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs')
# can also be constructed as:
#longlat = mapnik.Projection('+init=epsg:4326')

# ensure minimum mapnik version
if not hasattr(mapnik,'mapnik_version') and not mapnik.mapnik_version() >= 600:
    raise SystemExit('This script requires Mapnik >=0.6.0)')


def render_map(mapfile,map_uri,gpx_file,imgx,imgy):

    with open(gpx_file,'r') as f:
      data = f.read()

    xml = etree.fromstring(data)
    gpx = GPX()
    gpx.ReadTree(xml)

    bbox = gpx.bound_box()
    pprint(bbox)
    cx=(bbox[0][1]+bbox[1][1])/2
    cy=(bbox[0][0]+bbox[1][0])/2
    print(cx,cy)
    w=(bbox[1][1]-bbox[0][1])*1.2
    h=(bbox[1][0]-bbox[0][0])*1.2
    print(w,h)
    bounds = (cx-w/2,cy-h/2,cx+w/2,cy+h/2)
    print(bounds)

    m = mapnik.Map(imgx,imgy)
    mapnik.load_map(m,mapfile)

    m.background = mapnik.Color('rgb(255,255,255)')
    
    # ensure the target map projection is mercator
    #m.srs = merc.params()

    bbox = mapnik.Box2d(*bounds)

    pprint(bbox)
   
    minlat = bbox.miny
    maxlat = bbox.maxy
    minlon = bbox.minx
    maxlon = bbox.maxx

    print(minlat,maxlat,minlon,maxlon)
    
    transformer = Transformer.from_crs("EPSG:4326", "EPSG:3857", always_xy=True)
    minP=transformer.transform(minlon,minlat)
    maxP=transformer.transform(maxlon,maxlat)
    
    merc_bbox = mapnik.Box2d(minP[0],minP[1],maxP[0],maxP[1])
    m.zoom_to_box(merc_bbox)

    style = mapnik.Style()
    rule = mapnik.Rule()

    line_symbolizer = mapnik.LineSymbolizer()

    line_symbolizer.stroke = mapnik.Color('rgb(0,0,127)')
    line_symbolizer.stroke_width = 4.0
    line_symbolizer.stroke_opacity = 0.5
    
    rule.symbols.append(line_symbolizer)

    style.rules.append(rule)
    m.append_style('GPS_tracking_points', style)

    layer = mapnik.Layer('GPS_tracking_points')
    layer.datasource = mapnik.Ogr(file=gpx_file, layer='tracks')
    layer.styles.append('GPS_tracking_points')
    m.layers.append(layer)

    im = mapnik.Image(imgx,imgy)
    mapnik.render(m, im)
    im.save(map_uri,'png')
    sys.stdout.write('output image to %s!\n' % map_uri)


def render_all(db,mapfile,imgx,imgy):

    import sqlite3
    from os.path import dirname    

    conn = sqlite3.connect(db)
    conn.text_factory = str
    cur = conn.cursor()
    updcur = conn.cursor()

    cur.execute ("select id,filename from tracks where preview_name is null")
    
    list=cur.fetchall()
    
    for rec in list:        
    
      id = rec[0]
      filename = rec[1]
      preview_name = dirname(filename) + '/' + str(id) + '.png'

      print(id,filename,preview_name)

      try:      
        render_map(mapfile,preview_name.encode('utf8'),filename,imgx,imgy)
        updcur.execute("update tracks set preview_name=? where id=?", (preview_name,id))
        conn.commit()
      except:
        raise


def main():

    parser = OptionParser()
    parser.add_option("-m", "--map", dest="mapfile",
      help="use map file", metavar="MAP")
    parser.add_option("-o", "--output", dest="outfile",
      help="output image to file", metavar="OUT")
    parser.add_option("-g", "--gpx", dest="gpxfile",
      help="track to render", metavar="GPX")
    parser.add_option("-x", "--x-size", dest="x",
      help="image width", metavar="X")
    parser.add_option("-y", "--y-size", dest="y",
      help="image height", metavar="Y")
    parser.add_option("-d", "--db", dest="db",
      help="render all not process files in database", metavar="DB")
    (options, args) = parser.parse_args()

    if options.mapfile:  
      mapfile = options.mapfile
    else:
      mapfile = "/etc/mapnik-osm-carto-data/veloroad-imposm.xml"

    if options.outfile:  
      map_uri = options.outfile
    else:
      map_uri = "image.png"

    if options.x:  
      imgx = int(options.x)
    else:
      imgx= 640
    if options.y:  
      imgy = int(options.y)
    else:
      imgy= 640

    if options.db:
      render_all(options.db,mapfile,imgx,imgy) 
    else:
      if options.gpxfile:  
        gpx_file = options.gpxfile
        render_map(mapfile,map_uri,gpx_file,imgx,imgy)
      else:
        print("No input file")
        raise IOError("No input file")

if __name__ == "__main__":

    try:
        main()                    
    except:
        exit(1)    
