#! /usr/bin/env python
import re, sys, os

def read_method_list(fname):
    ml = {}
    md = open(fname)
    for line in md:
        if line.startswith("%%"):
            break
    for line in md:
        if line.startswith("%%"):
            break
        if not line.startswith('"'):
            continue
        name, has_result = line.split(",")
        name = name.strip().strip('"');
        has_result = (has_result.strip() == "true")
        ml[name] = has_result
    return ml

funcdef_search = re.compile(r"FUNCTION\(([^)]+)\)").search
procdef_search = re.compile(r"PROCEDURE\(([^)]+)\)").search

def read_defined_methods(fname):
    fd = {}
    for line in open(fname):
        if line.startswith("#"):
            continue
        m = funcdef_search(line)
        if m:
            fd[m.group(1)] = True
            continue
        m = procdef_search(line)
        if m:
            fd[m.group(1)] = False
            continue
    return fd

funcref_search = re.compile(r"START_CALL\(([^)]+)\)").search
procref_search = re.compile(r"START_NOTIFY\(([^)]+)\)").search

def read_referenced_methods(fname):
    fr = {}
    for line in open(fname):
        if line.startswith("#"):
            continue
        m = funcref_search(line)
        if m:
            fr[m.group(1)] = True
            continue
        m = procref_search(line)
        if m:
            fr[m.group(1)] = False
            continue
    return fr

callref_search = re.compile(r'guitarix.call\s*\(\s*("(?P<n1>[^"]+)"|'+"'(?P<n2>[^']+)')").finditer
notifyref_search = re.compile(r'guitarix.notify\s*\(\s*("(?P<n1>[^"]+)"|'+"'(?P<n2>[^']+)')").finditer

def read_referenced_methods_web(basedir):
    fw = {}
    for f in os.listdir(basedir):
        if not f.endswith(".js"):
            continue
        buf = open(os.path.join(basedir,f)).read()
        for m in callref_search(buf):
            name = m.group('n1') or m.group('n2')
            fw[name] = True
        for m in notifyref_search(buf):
            name = m.group('n1') or m.group('n2')
            fw[name] = False
    return fw

def printlist(title, s):
    if not s:
        return
    print
    print title
    for v in s:
        print " ", v

def main():
    base = os.path.dirname(sys.argv[0])
    def mkp(f):
        return os.path.join(base, "..", f)
    ml = read_method_list(mkp("src/gx_head/engine/jsonrpc_methods.gperf_tmpl"))
    fd = read_defined_methods(mkp("src/gx_head/engine/jsonrpc.cpp"))
    fr = read_referenced_methods(mkp("src/gx_head/gui/machine.cpp"))
    fw = read_referenced_methods_web(mkp("webui/source"))

    assert not (set(fd) - set(ml))
    assert not ((set(fr) | set(fw)) - set(ml))

    printlist("function referenced only in webui", set(fw) - set(fr))
    printlist("functions not referenced:", set(ml) - (set(fr) | set(fw)))
    printlist("functions not defined:",  set(ml) - set(fd))
    printlist("functions referenced but not defined:", (set(fr) | set(fw)) - set(fd))

if __name__ == "__main__":
    main()
