#!/usr/bin/env python3

import json
import sys
import re
import os.path

if len(sys.argv) != 3:
    sys.stderr.write("Filter failed! Please report bug.\n")
    sys.exit(1)

filename = sys.argv[1]
filetype = sys.argv[2]

i_fp = None
if os.path.exists(filename):
    i_fp = open(filename, "r")
else:
    sys.stderr.write("Filter failed! Cannot open file %s!" % filename)
    sys.exit(1)

outfile = filename.replace("csv", "json").replace(".tmp", "")
o_fp = open(outfile, "w")

def tryint(s):
    o = s
    try:
        o = int(s)
    except:
        t = s.replace(" ", "")
        try:
            t = int(t)
            elems = [ int(e) for e in s.split(" ") if len(e) > 0 ]
            o = elems
        except: pass
    return o

def fill_table(lines, headlist):
    out = []
    for l in lines:
        elems = [ tryint(e) for e in re.split("\s*,\s*", l) if len(e) > 0 ]
        t = {}
        for h, v in zip(headlist, elems):
            if type(v) == "str":
                t.update({h : v.replace(" STAT", "")})
            else:
                t.update({h : v})
        #print("%%TABLE: %s " % str(t))
        out.append(t)
    return out

def fill_struct(lines):
    struct = {}
    for l in lines:
        elems = [ tryint(e) for e in re.split("\s*,\s*", l) if len(e) > 0 ]
        if len(elems) == 2:
            struct.update({ elems[0] : elems[1] })
        else:
            struct.update({ elems[0] : elems[1:] })
        #print("%%STRUCT: %s " % str(struct))
    return struct

tables = {}
groups = []

if filetype == "perfctr" or filetype == "topology":
    inp = i_fp.read().strip().split("\n")
    out = {}
    tmp = {}
    name = None
    i = 0
    while i<len(inp):
        l = inp[i]
        if l.startswith("STRUCT") or l.startswith("TABLE") or i == len(inp)-1:
            if name and len(tmp) > 0:
                out[name] = tmp
                #sys.stderr.write(json.dumps(out)+"\n")
                tmp = {}
                name = ""
        if l.startswith("STRUCT"):
            llist = l.split(",")
            name = llist[1]
            lines = int(llist[2])
            s = fill_struct(inp[i+1:i+lines+1])
            info_struct = s;
            info_name = name
            tables.update({name: s})
            i += lines-1
        elif l.startswith("TABLE"):
            #sys.stderr.write(l+"\n")
            name = None
            gid = None
            grp = None
            gname = None
            reg = None
            regname = None
            head = inp[i+1]
            hlist = [ e for e in re.split("\s*,\s*", head) if len(e) > 0 ]
            llist = [ e for e in re.split("\s*,\s*", l) if len(e) > 0 ]
            if len(llist) == 3:
                tabname = llist[1]
                lines = int(llist[2])
            elif len(llist) == 4:
                tabname = llist[1]
                grp = llist[2]
                lines = int(llist[3])
            elif len(llist) == 5:
                regname = llist[1]
                tabname = llist[2]
                grp = llist[3]
                lines = int(llist[4])
            if filetype == "perfctr":
                m = re.match("(Group \d+) (.+)", tabname)
                if m:
                    gid, gname = m.groups()
                if regname:
                    m = re.match("Region (.+)", regname)
                    if m:
                        gid = m.group(1) + " " + gid

            t = fill_table(inp[i+2:i+lines+2], hlist)
            if grp and gname:
                if grp not in tables:
                    tables[grp] = {}
                    groups.append(grp)
                tables[grp].update({gname : t})
            elif gid and gname:
                if gid not in tables:
                    tables[gid] = {}
                    groups.append(grp)
                tables[gid].update({gname : t})
            else:
                tables.update({tabname : t})
            i += lines-1
        i += 1

    if filetype == "perfctr":
        cpulist = []
        gpulist = []

        for elems in tables[groups[0]]["Raw"]:
            for k in elems:
                m = re.match("HWThread (\d+)", k)
                if m:
                    cpulist.append(int(m.group(1)))
                m = re.match("GPU (\d+)", k)
                if m:
                    gpulist.append(int(m.group(1)))

        for g in groups:
            counters = []
            metrics = []
            for tabkey in tables[g]:
                if not "STAT" in tabkey:
                    for line in tables[g][tabkey]:
                        for k in line:
                            if k == "Counter": counters.append(line[k])
                            if k == "Metric": metrics.append(line[k])
            group = {}
            for tabkey in tables[g]:
                if g not in group:
                    group[g] = {}
                group[g][tabkey] = {}
                if "Raw" in tabkey and not "STAT" in tabkey:
                    for c in counters:
                        event = None
                        values = []
                        for line in tables[g][tabkey]:
                            if line["Counter"] == c:
                                event = line["Event"]
                                values = []
                                for k in line:
                                    if k != "Counter" and k != "Event":
                                        if line[k] != "-":
                                            values.append(float(line[k]))
                                        else:
                                            values.append(float('nan'))
                                group[g][tabkey][c] = {"Event" : event, "Values" : values}
                                break
                elif "Metric" in tabkey and not "STAT" in tabkey:
                    for m in metrics:
                        values = []
                        for line in tables[g][tabkey]:
                            if line["Metric"] == m:
                                values = []
                                for k in line:
                                    if k != "Metric":
                                        if line[k] != "-":
                                            values.append(float(line[k]))
                                        else:
                                            values.append(float('nan'))
                                group[g][tabkey][m] = {"Values" : values}
                                break
                else:
                    new = {}
                    for line in tables[g][tabkey]:
                        key = None
                        tmp = {}
                        if "Counter" in line:
                            key = line["Counter"]
                        elif "Metric" in line:
                            key = line["Metric"]
                        for k in line:
                            if line[k] != key:
                                v = line[k]
                                try:
                                    if v != "-":
                                        v = float(v)
                                    else:
                                        v = float('nan')
                                except: pass
                                tmp.update({k: v})
                        new[key] = tmp
                    group[g][tabkey] = new

            out[g] = group
        tables["Info"].update({"CPU list" : list(set(cpulist))})
        if len(gpulist) > 0:
            tables["Info"].update({"GPU list" : list(set(gpulist))})
        out["Info"] = tables["Info"]
    else:
        out = tables
    o_fp.write(json.dumps(out, indent=4, sort_keys=True)+"\n")
else:
    sys.stderr.write("Filter failed! Unknown application type %s!" % filetype)
    i_fp.close()
    o_fp.close()
    sys.exit(1)

i_fp.close()
o_fp.close()
os.remove(filename)
