#!/usr/bin/python
from __future__ import print_function, unicode_literals
from itertools import imap
import sys, json, operator, re

def walktree(tree, path="", parent=None) :
    if isinstance(tree, (list,dict)):   
        ixs = sorted(tree.iteritems(), key=operator.itemgetter(0)) if isinstance(tree, dict) else enumerate(tree)
        for k,v in ixs :
            for y in walktree(v, "{0}/{1!s}".format(path, k), tree) :
                yield y
    else: yield (tree, path, parent)


def settreeval(parent, path, value) :
    p = path.split("/")[-1]
    if p.isdigit():  p = int(p)
    parent[p] = value

def readjson(fname) :
    with open(fname,'r') as f: 
        return json.load(f)

def any_re(s, *res): 
    return any(re.search(r,s) for r in res)

def canonids(j) :
    slotmap = {'0000-00-0000':0} # The only pre-exisiting slotref for one past the end
    initcount = 1
    del j['version']
    for (v, p, h) in walktree(j) :
        if any_re(p, r"slots/\d+/id$", r"output/\d+/id$"):
            if v not in slotmap :
                slotmap[v] = initcount
                initcount += 1
            settreeval(h, p, slotmap[v])
    for (v, p, h) in walktree(j) :
        if any_re(p, r"parent/id$", "input/start$", r"output/range/(start|end)$", r"cursor$", r"children/\d+$") :
            settreeval(h, p, slotmap[v])
    return j

def _compare(t1, t2):
    v1,p1,_ = t1
    v2,p2,_ = t2
    if p1 != p2 :
        print(b"Structural difference: left = {0!s}, right = {1!s}".format(p1, p2))
        return False
    if v1 != v2 :
        print(b"Value difference: left = {0!s}, right = {1!s} at {2!s}".format(v1, v2, p1))
        return False
    return True
    
def compare(j1, j2) :
    return all(imap(_compare, walktree(j1), walktree(j2)))

try:
    r1 = canonids(readjson(sys.argv[1]))
except KeyError as ke:
    sys.stderr.write(b"unresolvable slot id {0} found while reading {1!r}\n".format(ke, sys.argv[1]))
    sys.exit(2)
    
try:
    r2 = canonids(readjson(sys.argv[2]))
except KeyError as ke:
    sys.stderr.write(b"unresolvable slot id {0} found while reading {1!r}\n".format(ke, sys.argv[2]))
    sys.exit(2)

res = compare(r1, r2)
if res :
    sys.exit(0)
sys.exit(1)


        
            
