import sys
import cPickle as pickle
from summarize import SUMMARY_VERSION, getperinterfacemetrics
import json

# Generate the job schema definition based on the pickle schema and enriched with
# information about the data sources - note this info needs to be maintained!

def generate_schema_defn(job):

    schema = {}

    interfacemetrics = getperinterfacemetrics()

    for k in job.schemas.keys():
        if k in interfacemetrics:
            schema[k] = {}
        else:
            schema[k] = {'*': {}}

        for e, t in job.schemas[k].iteritems():

            if t.is_control:
                continue

            info = {}
            if k == "block":
                info["source"] = {"type": "sysfs", "name": "/sys/block/*/stat" }
            if k == "cpu":
                info["source"] = {"type": "procfs", "name": "/proc/stat" }
            if k == "ps":
                if e == "ctxt" or e == "processes":
                    info["source"] = { "type": "procfs", "name": "/proc/stat" }
                else:
                    info["source"] = { "type": "procfs", "name": "/proc/loadavg" }
            if k == "panfs":
                if e == "kernel_slab_size":
                    info["source"] = { "type": "procfs", "name": "/proc/slabinfo" }
                else:
                    info["source"] = { "type": "process", "name": "panfs_stat" }
            if k == "irq":
                info["source"] = {"type": "procfs", "name": "/proc/interrupts" }
            if k == "llite":
                info['source'] = {'type': 'procfs', "name": "/proc/fs/lustre/llite"}
            if k == "lnet":
                info['source'] = {'type': 'procfs', "name": "/proc/sys/lnet/stats"}
            if k == "mem":
                info["source"] = {"type": "sysfs", "name": "/sys/devices/system/node/node*/meminfo" }
            if k == "net":
                info["source"] = {"type": "sysfs", "name": "/sys/class/net/*/statistics" }
            if k == "nfs":
                if e == "kernel_slab_size":
                    info["source"] = { "type": "procfs", "name": "/proc/slabinfo" }
                else:
                    info["source"] = { "type": "procfs", "name": "/proc/self/mountstats" }
            if k == "numa":
                info["source"] = {"type": "sysfs", "name": "/sys/devices/system/node/node*/numastat" }
            if k == "sched":
                info["source"] = { "type": "procfs", "name": "/proc/schedstat" }
            if k == "sysv_shm":
                info["source"] = { "type": "procfs", "name": "/proc/sysvipc/shm" }
            if k == "tmpfs":
                info["source"] = { "type": "syscall", "name": "statfs" }
            if k == "vfs":
                if e == "dentry_use":
                    info["source"] = { "type": "procfs", "name": "/proc/sys/fs/dentry-state" }
                else:
                    info["source"] = { "type": "procfs", "name": "/proc/sys/fs/inode-state" }
            if k == "vm":
                info["source"] = { "type": "procfs", "name": "/proc/vmstat" }

            info['type'] = "counter" if t.is_event else "instant"
            info['unit'] = "" if t.unit == None else t.unit

            if k in interfacemetrics:
                schema[k][e] = info
            else:
                schema[k]['*'][e] = info

    return schema

def autogeneratedocs(srcdef):
    out = dict(srcdef)
    if srcdef['type'] == 'counter':
        out['type'] = 'rate'
        out['unit'] = srcdef['unit'] + "/s"
    if "documentation" not in out and "source" in out:
        out["documentation"] = out['source']['type'] + " metric read from " + out['source']['name']

    return out

def generatesummaryschema(jobschema):

    schema = {}
    schema['_id'] = "summary-" + SUMMARY_VERSION
    schema['summary_version'] = SUMMARY_VERSION

    schema['definitions'] = {}

    # Merge job schema - some fields will be overwritten later
    for k,v in jobschema.iteritems():
        schema['definitions'][k] = {}
        for e,t in v.iteritems():
            if 'type' in t:
                schema['definitions'][k][e] = autogeneratedocs(t)
            else:
                schema['definitions'][k][e] = {}
                for e1, t1 in t.iteritems():
                    if 'type' in t1:
                        schema['definitions'][k][e][e1] = autogeneratedocs(t1)
                    else:
                        print "todo ", t
                


    # Add summary-specific entities
    schema['definitions']['FLOPS'] = { 'type': "rate", "unit": "ops/s", "documentation": "Generated from the available FLOPS hardware counters present on the cores" }
    schema['definitions']['Error'] = { 'type': "metadata", "documentation": "List of the processing errors encountered during job summary creation" }
    schema['definitions']['complete'] = { 'type': "metadata", "documentation": "Whether the raw data was available for all nodes that the job was assigned" }
    schema['definitions']['nHosts'] = { 'type': "discrete", "unit": "1", "documentation": "Number of hosts with raw data" }
    schema['definitions']['cpicore'] = { 'type': "ratio", "unit": "1", "documentation": "Number of clock ticks per instruction" }
    schema['definitions']['cpiref'] = { 'type': "ratio", "unit": "1", "documentation": "Number of reference clock ticks per instruction" }
    schema['definitions']['cpldref'] = { 'type': "ratio", "unit": "1", "documentation": "Number of clock ticks per L1D cache load using the reference CPU clock."}
    schema['definitions']['membw'] = { 'type': "rate", "unit": "B/s", "documentation": "Total rate of data transferred to and from main memory." }

    print json.dumps(schema, indent=4)
    sys.exit(0)

def main():

    jobschema = {}

    for filename in sys.argv[1:]:
        with open(filename, "rb") as f:
            j = pickle.load(f)
            jobschema.update(generate_schema_defn(j))

    generatesummaryschema(jobschema)

if __name__ == "__main__":
    main()

