#!python3
# -*- coding: utf-8
__author__ = "Přemek Hnilica"
__date__ = "$May 1, 2015 1:04:50 PM$"

from xml.etree import ElementTree as et
from argparse import ArgumentParser
import os
import re
from bisect import bisect_left

# 1 - some debug messages
# 3 - more debug messages
debug = 0;

allRels = []
allRefs = {}
tagsToCopy_tourist = (
                (('kct_red', 'kct_blue', 'kct_green', 'kct_yellow'),('major', 'local', 'learning', 'ruin', 'peak', 'spring', 'interesting_object', 'horse', 'ski', 'bicycle', 'wheelchair')),
             )
             
tagsToCopy_cycle = (
                (('route',),('bicycle',)),
                (('network',),('ncn','rcn','lcn',)),
             )

outFileName = 'map/mergedMap.osm'
################ Functions ###############

def findRel(ref):
    return root.find("relation[@id='"+ref+"']")

# function for precosseing relation
# it searches some tag which needs to be copied and saves it
# node - current relation
# checker - if I have some tag to copy
# desiredTags - tags to copy
def processNode(node,checker,checkerRefs,desiredTags,desiredRefs):
#    checker = 0 - I dont have tag
#    checker = 1 - I have tag for tourist route
#    checker = 2 - O have tag for cycle route
    if debug > 2: 
      print('procesing relation: '+node.get('id'))

    relatedWays = []
    if (checker > 0):
        for child in node.getchildren():
            if (child.get("type") == "way"):
                relatedWays.append(child.get("ref"))
            elif (child.get("type") == "relation"): # because osm allows super relations (relation containing other relations)
                rel = findRel(child.get("ref"))
                if rel is not None:
                    processNode(rel,checker,checkerRefs,desiredTags,desiredRefs)
            elif (child.get("type") == "tag"): # if I reached tags, I can finish
                break
    else:
        for child in reversed(node.getchildren()): # going reverse through all children of relation
            if child.tag == "tag":
                k = child.get('k')
                v = child.get('v')
                if debug > 2: 
                  print('  found tag: '+k+'='+v)
                for group in tagsToCopy_tourist:# loop through all tag groups I want to copy
                    if(k in group[0] and v in group[1]): # if actual tag matches tags that I want to copy
                        checker = 1
                        if debug > 1:
                          print('do',desiredTags,'pridavam T',k,v)
                        desiredTags.append([k, v]) # save it
                        # Si -----------------------
                        osmc_color = (re.search(r'kct_([a-z]+)', k)).group(1) # extract OSMC color
                        if debug > 1:
                          print('do ',desiredTags,' pridavam osmc_color=',osmc_color)
                        desiredTags.append(['osmc', 'yes']) # save it
                        desiredTags.append(['osmc_color', osmc_color]) # save it
                        # Si -----------------------
                        break
                if(checker != 1):
                    for group in tagsToCopy_cycle:# loop through all tag groups I want to copy
                        if(k in group[0] and v in group[1]): # if actual tag matches tags that I want to copy
                            checker = 2
                            if debug > 1:
                              print('do',desiredTags,'pridavam C',k,v)
                            desiredTags.append([k, v]) # save it
                            break
                if (checker == 2):
                    if(k == 'ref'):
                        checkerRefs = True
                        desiredRefs = v
            else: # here I am at the end of tags, I can finish searching for tags
                if (checker > 0):
                    if (child.get("type") == "way"):
                        wayID = child.get("ref")
                        relatedWays.append(wayID)
                        if (checkerRefs):
                            if (wayID in allRefs):
                                allRefs[wayID].append(desiredRefs)
                            else:
                                allRefs[wayID] = [desiredRefs]
                    elif (child.get("type") == "relation"): # because osm allows super relations (relation containing other relations)
                        rel = findRel(child.get("ref"))
                        if rel is not None:
                            processNode(rel,checker,checkerRefs,desiredTags,desiredRefs)
    if (checker > 0): # if I have some tag to copy
        if debug > 2:
            print('found tags to copy: '+repr(desiredTags)+" to ways "+repr(relatedWays))
        for i in desiredTags: # loop through all saved tags
            newTag = True # assume I have got new tag to be added
            for j in allRels: # go through all previously saved tags
                if debug > 2:
                    print('matching '+repr(i)+' to '+repr(j[0]))
                    #print("allRels1 {"+repr(allRels)+"}\n")
                if (i == j[0]): # if I already have saved same tag
                    j[1].extend(relatedWays)
                    if debug > 2:
                        print("allRels2 {"+repr(allRels)+"}\n")
                    newTag = False # found out I already have this tag saved
                    break
            if (newTag == True): # if it is really new tag
                if debug > 2:
                    print("append allRels {"+repr(i)+"}\n")
                allRels.append([i,relatedWays[:]]) # save it
        checker = 0
        checkerRefs = False
        if debug > 2:
            for r in allRels: print("allRels{"+repr(r)+"}\n")
        
# binary search over a sorted list
def index(list, x):
    i = bisect_left(list, x)
    if i != len(list) and list[i] == x:
        return i
    else:
        return -1
                

################## Program ###################

parser = ArgumentParser(description="OSM copy tags from relations to ways")
parser.add_argument("filename")
args = parser.parse_args()


# Divide file into 3 files - nodes, ways, relations
print ("Splitting source file into temporary files...")
outFile = open(outFileName,'w')
testString = '<way id='
with open(args.filename, 'r') as inFile:
    for line in inFile:
        if testString in line:  #if found first different line
            if testString == '</osm>':    # If reached end of the file
                outFile.write(line)
                break
            elif testString == '<relation id=':   #if I am aready looking for relations
                testString = '</osm>'   #set search string
                outFile.close()
                outFile = open('relations.xml','w') # set relations as outFile
                outFile.write("<osm>\n")
            else:   # if I am still looking for ways
                outFile.close()
                outFile = open('ways.xml','w')  #set ways as outFile
                testString = '<relation id='    #set search string
        outFile.write(line) #write line to out File

outFile.close()

print("Done")
sourceWaysFileSize80 = os.path.getsize('ways.xml')
sourceWaysFileSize20 = sourceWaysFileSize80 * 0.2
sourceWaysFileSize40 = sourceWaysFileSize80 * 0.4
sourceWaysFileSize60 = sourceWaysFileSize80 * 0.6
sourceWaysFileSize80 = sourceWaysFileSize80 * 0.8
sourceNodesFileSize = os.path.getsize(outFileName)


print("Looking for tags to copy within relations...")
doc = et.parse('relations.xml')
root = doc.getroot()

for node in root: # going through all relations
    processNode(node,0,False,[],None)
   
print("Done")

print("Sorting lists...")
for rel in allRels:
    rel[1].sort()
print("Done")

if debug > 0:
  for r in allRels:
    print("allRels{"+repr(r)+"}\n")

## Merge the documents again
status = 2 # for status printing (20%,40%,60%,80%)
print("Writing final result...")
outFile = open(outFileName,'a')
        
with open('ways.xml','r') as inFile:
    counter = 0
    way_id = None
    for line in inFile:
        if ('<way id="' in line): # if I am in way
            outFile.write(line) # first write it to file
            way_id = (re.search(r'\d+', line)).group(0) # extract its ID
        elif ('<tag k="' in line):
            if way_id is not None: # I have relation ID to check
                for way in allRels:
                    my_id = index(way[1],way_id)
                    if (my_id != -1): # if there is some relation tag to copy to this way
                        outFile.write('<tag k="'+way[0][0]+'" v="'+way[0][1]+'"/>\n')# write it here
                if (way_id in allRefs):
                    for a in allRefs[way_id]:
                        outFile.write('<tag k="ref" v="'+a+'"/>\n')# write it here
                    #TODO here I can remove allRefs[way_id] from dict?
                way_id = None
            outFile.write(line) # and then write the tag
        else:
            outFile.write(line) # some nd or other info that has to be just copied
        # some status printout
        counter += 1
        if ((counter % 10000) == 0):
            if ((status == 8) and ((os.path.getsize(outFileName) - sourceNodesFileSize) > sourceWaysFileSize80)):
                print("80% processed ")
                status = 10
            elif ((status == 6) and ((os.path.getsize(outFileName) - sourceNodesFileSize) > sourceWaysFileSize60)):
                print("60% processed")
                status = 8
            elif ((status == 4) and ((os.path.getsize(outFileName) - sourceNodesFileSize) > sourceWaysFileSize40)):
                print("40% processed")
                status = 6
            elif ((status == 2) and ((os.path.getsize(outFileName) - sourceNodesFileSize) > sourceWaysFileSize20)):
                print("20% processed")
                status = 4

with open('relations.xml','r') as f:
    next(f) # I dont want to print that (manually added) <osm>
    for line in f:
        outFile.write(line)

outFile.close()

print("Done")

print("Removing temporary files...")
os.remove('ways.xml')
os.remove('relations.xml')
print("Done")
