#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# vim: ts=2 sw=2 et ai


###############################################################################
# Copyright (c) 2012,2013 Andreas Vogel andreas@wellenvogel.net
#  parts of this software are based on tiler_tools (...)
#  the license terms (see below) apply to the complete software the same way
#
###############################################################################
# Copyright (c) 2011, Vadim Shlyakhov
#
#  Permission is hereby granted, free of charge, to any person obtaining a
#  copy of this software and associated documentation files (the "Software"),
#  to deal in the Software without restriction, including without limitation
#  the rights to use, copy, modify, merge, publish, distribute, sublicense,
#  and/or sell copies of the Software, and to permit persons to whom the
#  Software is furnished to do so, subject to the following conditions:
#
#  The above copyright notice and this permission notice shall be included
#  in all copies or substantial portions of the Software.
#
#  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
#  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
#  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
#  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
#  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
#  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
#  DEALINGS IN THE SOFTWARE.
###############################################################################

import os
import sys
import xml.sax as sax
from optparse import OptionParser
import math
import traceback

info="""
parse a directory hierarchy created with mobac (output OSMTracker) and the associated mobac profile.
and create an avnav.xml file
The directory structure must be z/x/y.png. Tiles must be 256x256 (no check)
Tile numbering is expected to be y=0 upper left.
When reading the profile we try to map each of the "layers" found inside to one of our layers.
This requires to be carefull when creating them, to always use the same min/max zoom for a group of them
as we will directly move them into one of our layers.
"""

OVERVIEW="avnav.xml"
#an xml description of the layers we generated - following the TMS spec
overview_xml='''<?xml version="1.0" encoding="UTF-8" ?>
 <TileMapService version="1.0.0" >
   <Title>avnav tile map service</Title>
   <TileMaps>
   %(tilemaps)s
   </TileMaps>
 </TileMapService>
 '''
overview_tilemap_xml='''
    <TileMap 
       title="%(title)s" 
       srs="OSGEO:41001" 
       profile="%(profile)s" 
       href="%(url)s" 
       minzoom="%(minZoom)d"
       maxzoom="%(maxZoom)d">
       %(bounding)s
       <TileFormat width="%(tileSize)d" height="%(tileSize)d" mime-type="x-png" extension="png" %(zoomOffset)s/>
       %(layerboundings)s     
    </TileMap>
       
'''


boundingbox_xml='''
<BoundingBox minlon="%(minlon).11G" minlat="%(minlat).11G" maxlon="%(maxlon).11G" maxlat="%(maxlat).11G"
   title="%(title)s"/>
'''


zoom_boundings_entry='''
<BoundingBox minx="%(minx)s" maxx="%(maxx)s" miny="%(miny)s" maxy="%(maxy)s">
</BoundingBox>
'''

zoom_boundings_zoom='''
<ZoomBoundings zoom="%(zoom)s">
%(boundings)s
</ZoomBoundings>
'''
zoom_boundings='''
<LayerZoomBoundings>
%(boundings)s
</LayerZoomBoundings>
'''

options=None
upzoom=1 #how many additional layers to be created for a single source gemf file

def log(s):
  print("LOG: %s"%(s,))

def debug(num,txt):
  if (num <= options.verbose):
    print("DEBUG %s"%(txt,))
    
#convert tile numbers to lat/lon
#see:http://wiki.openstreetmap.org/wiki/Slippy_map_tilenames#X_and_Y
#This returns the NW-corner of the square
def num2deg(xtile, ytile, zoom):
  n = 2.0 ** zoom
  lon_deg = xtile / n * 360.0 - 180.0
  lat_rad = math.atan(math.sinh(math.pi * (1 - 2 * ytile / n)))
  lat_deg = math.degrees(lat_rad)
  return (lat_deg, lon_deg)

class Tileset(object):
  def __init__(self,name,zoom,minx,miny,maxx,maxy):
    self.name=name
    self.zoom=zoom
    self.minx=minx
    self.miny=miny
    self.maxx=maxx
    self.maxy=maxy


class Tilegroup(object):
  def __init__(self,name):
    self.elements=[]
    self.name=name
    self.minzoom=-1
    self.maxzoom=0
    
  #boundings is zoom,name,minx,miny,maxx,maxy (tilenumbers)
  def addElement(self,element):
    if self.minzoom == -1 or element.zoom < self.minzoom:
      self.minzoom=element.zoom
    if element.zoom > self.maxzoom:
      self.maxzoom=element.zoom
    self.elements.append(element)
  def getMaxZoomElements(self):
    rt=[]
    for el in self.elements:
      if el.zoom==self.maxzoom:
        rt.append(el)
    return rt
  def getZoomElements(self,zoom):
    rt=[]
    for el in self.elements:
      if el.zoom==zoom:
        rt.append(el)
    return rt
      

class Layer(object):
  def __init__(self,name,minzoom,maxzoom,baseurl=""):
    self.tlist=[]
    self.minzoom=minzoom
    self.maxzoom=maxzoom
    self.name=name
    self.baseurl=baseurl
  #add ad group if their minzoom/maxzoom fits
  #return true/false  
  def addEntry(self,tilegroup):
    if tilegroup.minzoom != self.minzoom:
      return False
    if tilegroup.maxzoom != self.maxzoom:
      return False
    self.tlist.append(tilegroup)
    return True
  def getMaxZoomElements(self):
    rt=[]
    for tg in self.tlist:
      rt+=tg.getMaxZoomElements()
    return rt
  def getZoomElements(self,zoom):