#!/usr/bin/python

import sys,os,re,string,os.path,glob

if not os.path.exists("ocr-utils"):
    sys.stderr.write("must be run from top level of ocropus installation")
    sys.exit(1)

sources = glob.glob("*/*.h") + glob.glob("*/*.cc")

class UnionFind:
    def __init__(self):
        self.num_weights = {}
        self.parent_pointers = {}
        self.num_to_objects = {}
        self.objects_to_num = {}
        self.__repr__ = self.__str__
    def insert_objects(self, objects):
        for object in objects:
            self.find(object);
    def find(self, object):
        if not object in self.objects_to_num:
            obj_num = len(self.objects_to_num)
            self.num_weights[obj_num] = 1
            self.objects_to_num[object] = obj_num
            self.num_to_objects[obj_num] = object
            self.parent_pointers[obj_num] = obj_num
            return object
        stk = [self.objects_to_num[object]]
        par = self.parent_pointers[stk[-1]]
        while par != stk[-1]:
            stk.append(par)
            par = self.parent_pointers[par]
        for i in stk:
            self.parent_pointers[i] = par
        return self.num_to_objects[par]
    def union(self, object1, object2):
        o1p = self.find(object1)
        o2p = self.find(object2)
        if o1p != o2p:
            on1 = self.objects_to_num[o1p]
            on2 = self.objects_to_num[o2p]
            w1 = self.num_weights[on1]
            w2 = self.num_weights[on2]
            if w1 < w2:
                o1p, o2p, on1, on2, w1, w2 = o2p, o1p, on2, on1, w2, w1
            self.num_weights[on1] = w1+w2
            del self.num_weights[on2]
            self.parent_pointers[on2] = on1
    def __str__(self):
        sets = {}
        for i in xrange(len(self.objects_to_num)):
            sets[i] = []
        for i in self.objects_to_num:
            sets[self.objects_to_num[self.find(i)]].append(i)
        out = []
        for i in sets.itervalues():
            if i:
                out.append(repr(i))
        return ', '.join(out)

def unique(l):
    h = {}
    for k in l: h[k] = 1
    return h.keys()

edges = []
for file in sources:
    text = open(file,"r").read()
    text = re.sub(r'/\*.*?\*/',' ',text)
    text = re.sub(r'//.*?\n',' ',text)
    text = re.sub("\n"," ",text)
    print file
    for cls in re.findall(r'(?:\s|^)((?:class|struct)\s[^.*/!]*?)[{;]',text):
        print cls
        m = re.search(r'(?:class|struct)\s+(\S+)\s*:\s*(.*)',cls)
        if m:
            derived = m.group(1).strip()
            for base in re.split(r'\s*,\s*',m.group(2)):
                base = re.sub(r'\s*public\s*','',base.strip())
                base = re.sub(r'colib::','',base)
                derived = re.sub(r'colib::','',derived)
                base = re.sub(r'\s*virtual\s*','',base)
                derived = re.sub(r'\s*virtual\s*','',derived)
                edges.append((derived,base))
                sys.stderr.write("%s: %s %s\n"%(file,derived,base))

edges = unique(edges)
objects = unique([k for k,v in edges] + [v for k,v in edges])

uf = UnionFind()
for derived,base in edges:
    uf.find(derived)
    uf.find(base)
    uf.union(derived,base)

sets = {}
for derived,base in edges:
    key = uf.find(derived)
    sets[key] = sets.get(key,[]) + [(derived,base)]

dir = "doc/hierarchy"

def graph(stream,name,edges):
    stream.write("""
    digraph "%s"
    {
        rankdir = "LR";
        size = "8,20";
        ratio = compress;
    """ % name)
    for derived,base in edges:
        stream.write('"%s"'%derived+"->"+'"%s"'%base+";\n")

    stream.write("""
    }
    """)

html = open(dir+"/index.html","w")
count = 1
for key in sets.keys():
    set = sets[key]
    prefix = dir+("/graph%03d"%count)
    stream = open(prefix+".dot","w")
    graph(stream,"graph%d"%count,set)
    stream.close()
    os.system("dot -Tpng %s.dot -o %s.png"%(prefix,prefix))
    html.write("<h2>Diagram %d</h2>\n"%count)
    html.write("<p>\n")
    html.write("<img src='graph%03d.png'\n"%count)
    html.write("<p>\n")
    count += 1
html.close()
