#!/usr/bin/python

"""
Build C++ code for accessing Msg contents by shortcut.
"""

import sys, re, os

DESTDIR = "."
if len(sys.argv) > 1:
    DESTDIR = sys.argv[1]

class VC:
    def __init__(self, name):
        m = re.match(r"B(\d\d)(\d\d\d)", name)
        if not m:
            raise "Invalid B local"
        self.x = int(m.group(1))
        self.y = int(m.group(2))

    def __str__(self):
        return "B%02d%03d" % (self.x, self.y)

    def __cmp__(self, o):
        c = self.x.__cmp__(o.x)
        if c != 0: return c
        return self.y.__cmp__(o.y)

class Var:
    def __init__(self, line):
        def cleanint(x):
           if x == '-': return "MISSING_INT"
           return str(int(x))

        vals = re.split(r"\s*,\s*", line[:-1].strip())

        self.name, self.type = vals[0:2]
        self.b = VC(vals[2])
        self.letr = [cleanint(x) for x in vals[3:-1]]
        self.desc = vals[-1]

    def __str__(self):
        return ", ".join([self.name, str(self.b),
                        ":".join([str(x) for x in self.letr[0:4]]),
                        ":".join([str(x) for x in self.letr[4:]]),
                        self.desc])

    def __cmp__(self, o):
        def cmpval(a, b):
            if a == "MISSING_INT" and b == "MISSING_INT":
                return 0
            if a == "MISSING_INT": return -1;
            if b == "MISSING_INT": return 1;
            return int(b) - int(a)
        for i in range(len(self.letr)):
            c = cmpval(self.letr[i], o.letr[i])
            if c != 0: return c
        return self.b.__cmp__(o.b)

vars = [Var(line) for line in sys.stdin if not re.match(r"^\s*(?:#.+)?$", line)]
vars.sort()

fh = open("%s/vars.h" % DESTDIR, "w")
print >>fh, """#ifndef DBA_MSG_VARS_H
#define DBA_MSG_VARS_H

/** @file
 * @ingroup msg
 * Shortcut IDs and functions to quickly refer to commonly used values inside a
 * dballe::msg::Msg.
 *
 * The shortcuts are defined in the file vars.csv, which maps a name to the tuple
 * (preferred C type, BLocal, Level type, L1, L2, P indicator, P1, P2).  The file
 * vars.csv is used to generate code (vars.h and vars.c) that provides a set of
 * getters and setters for every named value.
 */

#include <wreport/varinfo.h>

namespace dballe {

/**
 * Full data corresponding to a shortcut ID
 */
struct MsgVarShortcut {
    /** Variable description code */
    wreport::Varcode code;
    /** Type of the first level.  See @ref level_table. */
    int ltype1;
    /** L1 value of the level.  See @ref level_table. */
    int l1;
    /** Type of the second level.  See @ref level_table. */
    int ltype2;
    /** L2 value of the level.  See @ref level_table. */
    int l2;
    /** Time range type indicator.  See @ref trange_table. */
    int pind;
    /** Time range P1 indicator.  See @ref trange_table. */
    int p1;
    /** Time range P2 indicator.  See @ref trange_table. */
    int p2;
};

/** Array with all the full expansions of the shortcut IDs, indexed by shortcut
  * ID
  */
extern struct MsgVarShortcut shortcutTable[];

/** Resolve a var name to a var ID */
int resolve_var(const char* name);

/** Resolve a var name to a var ID, avoiding to compute the length of name */
int resolve_var_substring(const char* name, int len);
"""

for i, v in enumerate(vars):
    print >>fh, "/** %s */" % v.desc
    print >>fh, "#define DBA_MSG_%s %d" % (v.name, i)
print >>fh, "/** Number of items in dba_msg_vartable */";
print >>fh, "#define DBA_MSG_VARTABLE_SIZE %d" % i;
print >>fh, """
}

#endif
"""
fh.close()

fh = open("%s/msg-extravars.h" % DESTDIR, "w")
types = dict(int = 'int', num = 'double', str = 'const char*')
ftypes = dict(int = 'i', num = 'd', str = 'c')
for v in vars:
    print >>fh, "/** Set the value of \"%s\" from a variable of type %s */" % (v.desc, types[v.type])
    print >>fh, "inline void set_%s(%s val, int conf=-1) " % (v.name.lower(), types[v.type]),
    #print >>sys.stderr, v
    #print >>sys.stderr, "--", [ftypes[v.type], v.b.x, v.b.y] + v.letr;
    print >>fh, "{ set%s(WR_VAR(0, %d, %d), val, conf, Level(%s, %s, %s, %s), Trange(%s, %s, %s)); }" % \
        tuple([ftypes[v.type], v.b.x, v.b.y] + v.letr);

    print >>fh, "/** Set the value of \"%s\" from a wreport::Var */" % v.desc;
    print >>fh, "inline void set_%s_var(const wreport::Var& val) " % v.name.lower(),
    print >>fh, "{ set(val, WR_VAR(0, %d, %d), Level(%s, %s, %s, %s), Trange(%s, %s, %s)); }" % \
            tuple([v.b.x, v.b.y] + v.letr)

    print >>fh, "/** Get the \"%s\" physical value stored in the message */" % v.desc;
    print >>fh, "inline const wreport::Var* get_%s_var() const" % v.name.lower();
    print >>fh, "{ return find_by_id(DBA_MSG_%s); }" % \
        v.name;
fh.close()

fh = open("%s/context-extravars.h" % DESTDIR, "w")
for v in vars:
    print >>fh, "/** Set the value of \"%s\" from a variable of type %s */" % (v.desc, types[v.type])
    print >>fh, "inline void set_%s(%s val) " % (v.name.lower(), types[v.type]),
    print >>fh, "{ set%s(WR_VAR(0, %d, %d), val); }" % (ftypes[v.type], v.b.x, v.b.y)

    print >>fh, "/** Get the \"%s\" physical value stored in the message */" % v.desc;
    print >>fh, "inline const wreport::Var* get_%s() const" % v.name.lower();
    print >>fh, "{ return find(WR_VAR(0, %d, %d)); }" % (v.b.x, v.b.y)
fh.close()

fc = open("%s/vars.gperf" % DESTDIR, "w")
print >>fc, """
%define slot-name name
%define class-name MsgVarLookup
%define lookup-function-name find
%struct-type
%language=C++
%global-table
%compare-strncmp
/* Using %switch may be faster (remember to check when doing optimizations) */

%{
#include <dballe/core/defs.h>
#include <dballe/msg/vars.h>
#include <string.h>

namespace dballe {
%}

struct msgvardef { const char* name; int var; };
%%"""
for v in vars:
    print >>fc, "%s, DBA_MSG_%s" % (v.name.lower(), v.name)
print >>fc, """%%

int resolve_var(const char* name)
{
    struct msgvardef* res = MsgVarLookup::find(name, strlen(name));
	if (res == NULL)
		return -1;
	else
		return res->var;
}

int resolve_var_substring(const char* name, int len)
{
    struct msgvardef* res = MsgVarLookup::find(name, len);
	if (res == NULL)
		return -1;
	else
		return res->var;
}

"""

print >>fc, "struct MsgVarShortcut shortcutTable[] = {"
for v in vars:
    print >>fc, " { WR_VAR(0, %d, %d), %s, %s, %s, %s, %s, %s, %s }," % tuple([v.b.x, v.b.y] + v.letr)
print >>fc, "};"

print >>fc, "} // namespace dballe"

fc.close()

sys.exit()
