# This script produces a sample SVG demonstrating all filters in a filters file.
#
# It takes two inputs: the sample file with the object that will be cloned and filtered, and
# the file with filters (such as Inkscape's share/filters/filters.svg).
#
# Run it thus:
#
#    python3 samplify.py sample.svg filters.svg > out.svg
#
# It requires 'inkscape' in executable path for dimension queries.

import sys, os, string, subprocess
from lxml import etree

if len(sys.argv) < 3:
    sys.stderr.write ("Usage: python3 samplify.py sample.svg filters.svg > out.svg\n")
    sys.exit(1)

# namespaces we need to be aware of
NSS = {
u'sodipodi' :u'http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd',
u'cc'       :u'http://web.resource.org/cc/',
u'svg'      :u'http://www.w3.org/2000/svg',
u'dc'       :u'http://purl.org/dc/elements/1.1/',
u'rdf'      :u'http://www.w3.org/1999/02/22-rdf-syntax-ns#',
u'inkscape' :u'http://www.inkscape.org/namespaces/inkscape',
u'xlink'    :u'http://www.w3.org/1999/xlink',
u'xml'      :u'http://www.w3.org/XML/1998/namespace'
}

# helper function to add namespace URI to a name
def addNS(tag, ns=None):
    val = tag
    if ns!=None and len(ns)>0 and ns in NSS and len(tag)>0 and tag[0]!='{':
        val = "{%s}%s" % (NSS[ns], tag)
    return val

# attributes and elements we will use, prepared with their namespace
a_href = addNS('href', 'xlink')
a_menu = addNS('menu', 'inkscape')
a_tooltip = addNS('menu-tooltip', 'inkscape')
a_label = addNS('label', 'inkscape')
e_text = addNS('text', 'svg')
e_tspan = addNS('tspan', 'svg')
e_flowRoot = addNS('flowRoot', 'svg')
e_flowPara = addNS('flowPara', 'svg')
e_flowSpan = addNS('flowSpan', 'svg')
e_g = addNS('g', 'svg')
e_use = addNS('use', 'svg')
e_defs = addNS('defs', 'svg')
e_filter = addNS('filter', 'svg')
e_rect = addNS('rect', 'svg')
e_svg = addNS('svg', 'svg')
e_switch = addNS('switch', 'svg')


tstream = open(sys.argv[1], 'rb')
tdoc = etree.parse(tstream)

fstream = open(sys.argv[2], 'rb')
fdoc = etree.parse(fstream)

menus = []

for defs in fdoc.getroot().getchildren():
    for fi in defs.getchildren():
        if fi.tag == e_filter and fi.attrib[a_menu] not in menus:
            menus.append(fi.attrib[a_menu])

menu_shifts = {}
for m in menus:
    menu_shifts[m] = 0

menus.sort()

#print menus

def copy_element (a):
    b = etree.Element(a.tag, nsmap=NSS)
    for i in a.items():
        b.set(i[0], i[1])
    b.text = a.text
    b.tail = a.tail
    return b

#query inkscape about the bounding box of obj
q = {'x':0,'y':0,'width':0,'height':0}
file = sys.argv[1]
id = tdoc.getroot().attrib["id"]
for query in q.keys():
    f = subprocess.Popen(["inkscape", "--query-%s"%query, "--query-id=%s"%id, "%s"%file], stdout=subprocess.PIPE)
    q[query] = float(f.stdout.read())

# add some margins
q['width'] = q['width'] * 1.3
q['height'] = q['height'] * 1.3

#print q    

root = tdoc.getroot()
tout = etree.ElementTree(copy_element(root))
newroot = tout.getroot()
for ch in root.getchildren():
    chcopy = ch.__deepcopy__(-1)
    newroot.append(chcopy)
    if ch.tag == e_defs:
        for defs in fdoc.getroot().getchildren():
            for fi in defs.getchildren():
                ficopy = fi.__deepcopy__(-1)
                newroot.getchildren()[-1].append(ficopy)
    if ch.tag == e_g:
        newroot.getchildren()[-1].attrib["id"] = "original"
        for menu in menus:
            text = etree.Element(e_text, nsmap=NSS)
            text.attrib['x']=str(q['x'] - q['width'] * 0.2)
            text.attrib['y']=str( q['y'] + q['height'] * (menus.index(menu) + 1.4) )
            text.attrib['style']="font-size:%d;text-anchor:end;" % (q['height']*0.2)
            text.text = menu
            newroot.append(text)
        for defs in fdoc.getroot().getchildren():
            for fi in defs.getchildren():
                if fi.tag != e_filter:
                    continue
                clone = etree.Element(e_use, nsmap=NSS)
                clone.attrib[a_href]='#original'
                clone.attrib["style"]='filter:url(#'+fi.attrib["id"]+')'
                menu = fi.attrib[a_menu]
                clone.attrib["transform"] = 'translate('+str( q['width'] * menu_shifts[menu] )+', '+str( q['height'] * (menus.index(menu) + 1) )+')'
                newroot.append(clone)

                text = etree.Element(e_text, nsmap=NSS)
                text.attrib['x']=str( q['x'] + q['width'] * (menu_shifts[menu] + 0.5) )
                text.attrib['y']=str( q['y'] + q['height'] * (menus.index(menu) + 1.86) )
                text.attrib['style']="font-size:%d;text-anchor:middle;" % (q['height']*0.08)
                text.text = fi.attrib[a_label]
                newroot.append(text)

                if a_tooltip not in fi.keys():
                    print("no menu-tooltip for", fi.attrib["id"])
                    sys.exit()

                text = etree.Element(e_text, nsmap=NSS)
                text.attrib['x']=str( q['x'] + q['width'] * (menu_shifts[menu] + 0.5) )
                text.attrib['y']=str( q['y'] + q['height'] * (menus.index(menu) + 1.92) )
                text.attrib['style']="font-size:%d;text-anchor:middle;" % (q['height']*0.04)
                text.text = fi.attrib[a_tooltip]
                newroot.append(text)

                menu_shifts[menu] = menu_shifts[menu] + 1
        break

total_width = max(menu_shifts.values()) * q['width']    
total_height = (len(menus) + 1) * q['height']
tout.getroot().attrib['width'] = str(total_width)
tout.getroot().attrib['height'] = str(total_height)

print(etree.tostring(tout, encoding='UTF-8'))

