#!/usr/bin/perl -w

use strict;
use warnings;

my @vars;
while (<>)
{
	chop;
	next if /^\s*(?:#.+)?$/;
	s/^\s*//;
	s/\s*$//;
	my @vals = split(/\s*,\s*/);
	die "Invalid B local at line $." if ($vals[2] !~ /B(\d\d)(\d\d\d)/);
	push @vars, [@vals[0, 1], $1, $2, @vals[3..9]];
}

@vars = sort { 
	for my $i (4..9, 2, 3)
	{
		my $t = $a->[$i] <=> $b->[$i];
		return $t if ($t != 0);
	}
	return 0;
} @vars;

open OUT, ">vars.h" or die "Cannot write to vars.h: $!";
print OUT q|#ifndef DBA_MSG_VARS_H
#define DBA_MSG_VARS_H

#ifdef  __cplusplus
extern "C" {
#endif

/** @file
 * @ingroup msg
 * Shortcut IDs and functions to quickly refer to commonly used values inside a
 * ::dba_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 <dballe/msg/msg.h>

/**
 * Full data corresponding to a shortcut ID
 */
struct _dba_msg_var {
	/** Variable description code */
	dba_varcode code;
	/** Type of the level.  See @ref level_table. */
	int ltype;
 	/** L1 value of the level.  See @ref level_table. */
	int l1;
 	/** 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;
};
/** @copydoc _dba_msg_var */
typedef struct _dba_msg_var* dba_msg_var;

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

|;
my $i = 0;
for my $v (@vars)
{
	printf OUT "/** %s */\n", $v->[10];
	printf OUT "#define DBA_MSG_%s %d\n", $v->[0], $i++;
}
my %types = ( 'int' => 'int', 'num' => 'double', 'str' => 'const char*' );
my %ftypes = ( 'int' => 'i', 'num' => 'd', 'str' => 'c' );
for my $v (@vars)
{
	printf OUT "/** Set the value of \"%s\" from a variable of type %s */\n", $v->[10], $types{$v->[1]};
	printf OUT "inline static dba_err dba_msg_set_%s(dba_msg msg, %s val, int conf) ", lc $v->[0], $types{$v->[1]};
	printf OUT "{ return dba_msg_set%s(msg, DBA_VAR(0, %d, %d), val, conf, %d, %d, %d, %d, %d, %d); }\n",
		$ftypes{$v->[1]}, (@$v)[2..9];

	printf OUT "/** Set the value of \"%s\" from a ::dba_var */\n", $v->[10];
	printf OUT "inline static dba_err dba_msg_set_%s_var(dba_msg msg, dba_var val) ", lc $v->[0];
	printf OUT "{ return dba_msg_set(msg, val, DBA_VAR(0, %d, %d), %d, %d, %d, %d, %d, %d); }\n", (@$v)[2..9];

	printf OUT "/** Get the \"%s\" physical value stored in the message */\n", $v->[10];
	printf OUT "inline static dba_var dba_msg_get_%s_var(dba_msg msg) ", lc $v->[0];
	printf OUT "{ dba_msg_datum d = dba_msg_find_by_id(msg, DBA_MSG_%s); return d == NULL ? NULL : d->var; }\n",
		$v->[0];
}
printf OUT "/** Number of items in dba_msg_vartable */\n";
printf OUT "\n#define DBA_MSG_VARTABLE_SIZE %d\n", $i;
print OUT q|
#ifdef  __cplusplus
}
#endif

#endif
|;
close OUT;

open OUT, ">vars.c" or die "Cannot write to vars.c: $!";
print OUT q|#include <dballe/msg/vars.h>

struct _dba_msg_var dba_msg_vartable[] = {
|;

for my $v (@vars)
{
	printf OUT " { DBA_VAR(0, %d, %d), %d, %d, %d, %d, %d, %d },\n", (@$v)[2..9];
}
	
printf OUT q|};
|;
close OUT;

exit 0

# vim:set ts=4 sw=4:
