#!/usr/bin/env perl

$VERBOSE = 0;
if ($ARGV[0] eq "-v") { $VERBOSE = 1; shift @ARGV; }
if (@ARGV != 3) { die "generate (schema) (template) (output)\n"; }

$schema   = $ARGV[0];
$template = $ARGV[1];
$output   = $ARGV[2];

&parse_schema;
&parse_template;
exit 0;

sub parse_schema {
    open (FILE, "$schema");
    @list = <FILE>;
    close (FILE);

    &init_key ("TABLE");
    &init_key ("TITLE");
    &init_key ("FILE");
    &init_key ("FIELDS");

    foreach $line (@list) {
	chop $line;
	($key, $value) = split (" ", $line, 2);
	
	# strip white space from the following
	if ($key eq "TABLE") { ($value) = $value =~ m|\s*(\S+)\s*|; }
	if ($key eq "TYPE")  { ($value) = $value =~ m|\s*(\S+)\s*|; }

	&set_keypair ($key, $value);

	# list of the table fields
 	if ($key eq "FIELD") {
	    ($field, $name, $link, $extras) = split (/,\s+/, $value, 4);
	    # ($field) = $field =~ m|\s*(\S+)\s*|;

	    if ($VERBOSE) { printf "%-20s %-20s %-20s %-20s\n", $field, $name, $link, $extras; }
	    push @field,   $field;
	    push @name,    $name;
	    push @link,    $link;
	    push @extras,  $extras;
	}

	# list of the table restrictions
 	if ($key eq "RESTRICT") {
	    ($field) = split (/,\s+/, $value, 1);
	    # ($field) = $field =~ m|\s*(\S+)\s*|;

	    if ($VERBOSE) { printf "%-20s\n", $field; }
	    push @restrict,   $field;
	}
    }
    # define query string, add to keypairs
    &define_query_fields;
}

sub parse_template {
    open (FILE, $template);
    @list = <FILE>;
    close (FILE);

    open (FILE, ">$output");

    foreach $line (@list) {
	
	&check_keypairs;

	print FILE $line;

	# fill in table header
	if ($line =~ m|// \*\* TABLE HEADER \*\*|) {
	    &write_table_header;
	}

	# fill in table data
	if ($line =~ m|// \*\* TABLE DATA \*\*|) {
	    &write_table_data;
	}

	# fill in table query
	if ($line =~ m|// \*\* TABLE QUERY \*\*|) {
	    &write_table_query;
	}

	# fill in table restricts
	if ($line =~ m|// \*\* TABLE RESTRICTIONS \*\*|) {
	    &write_table_restrict;
	}
    }
    close (FILE);
}

sub write_table_header {

    for ($i = 0; $i < @field; $i++) {
	printf FILE "echo \"<th class=\\\"list\\\"> $name[$i] </th>\\n\";\n";
    }
}

sub write_table_restrict {

    for ($i = 0; $i < @restrict; $i++) {
	$value = $restrict[$i];
	printf FILE "\$value = \$_GET['$value'];\n";
	printf FILE "if (\$value) {\n";
	printf FILE "  if (\$WHERE) {\n";
	printf FILE "    \$WHERE = \$WHERE . \" AND $value = '\$value'\";\n";
	printf FILE "  } else {\n";
	printf FILE "    \$WHERE = \"$value = '\$value'\";\n";
	printf FILE "  }\n";
	printf FILE "}\n";
    }
}

sub write_table_data {

    for ($i = 0; $i < @field; $i++) {
	# create the link variable if this entry should be linked
	if ($link[$i]) {
	    # create the basic link 
	    printf FILE "  \$link = \"$link[$i]\" . \"?\" . \$ID['link'];\n";
	    if ($extras[$i]) {
		# examine the extras and parse the embedded fields
		@extfields = split (/,/, $extras[$i]);
		$N = @extfields;
		if ($VERBOSE) { print STDERR "N extfields: $N\n"; }
		for ($j = 0; $j < @extfields; $j++) {

		    # search for embedded table fields and replace with row[N]
		    $N = -1;
		    $extline = $extfields[$j];
		    if ($VERBOSE) { print STDERR "extfield: $extfields[$j]\n"; }
		    for ($k = 0; ($k < @field) && ($N == -1); $k++) {
			if ($extline =~ m|\$$field[$k]|) {
			    $extline =~ s|\$$field[$k]||;
			    $N = $k;
			}
		    }
		    if ($N == -1) {
			# no embedded field, print verbatim
			printf FILE "  \$link = \$link . \"&$extline\";\n";
		    } else {
			# replace embedded field with row[N]
			printf FILE "  \$link = \$link . \"&$extline\" . \$row[$N];\n";
		    }
		}

	    } 
	    # print the actual table cell line with the link...
	    printf FILE "  echo \"<td class=\\\"list\\\"><a href=\\\"\$link\\\"> \$row[$i] </a></td>\\n\";\n";
	} else {
	    # or without
	    printf FILE "  echo \"<td class=\\\"list\\\"> \$row[$i] </td>\\n\";\n";
	}
    }
}

sub write_table_query {

    for ($i = 0; $i < @field; $i++) {
	printf FILE "echo \"<td class=\\\"list\\\"> <input type=\\\"text\\\" name=\\\"$field[$i]\\\"> </td>\\n\";\n";
    }
}

sub define_query_fields {

    $FIELDS = "$field[0]";
    for ($i = 1; $i < @field; $i++) {
	$FIELDS = "$FIELDS,$field[$i]";
    }
 
    set_keypair ("FIELDS", $FIELDS);
}

sub init_key {
    my ($key)   = $_[0];

    push @key, $key;
    push @value, "";
}

sub set_keypair {
    my ($i);
    my ($key)   = $_[0];
    my ($value) = $_[1];

    for ($i = 0; $i < @key; $i++) {
	if ($key eq $key[$i]) {
	    if ($value[$i] ne "") { die "key is multiply defined\n"; }
	    $value[$i] = $value;
	    return;
	}
    }
}

sub check_keypairs {
    my ($i);
    for ($i = 0; $i < @key; $i++) {
	# if ($VERBOSE) { print "$key[$i]  -- $value[$i]\n"; }
	if ($line =~ m|\$$key[$i]|) {
	    if ($value[$i] eq "") { die "missing value for required key $key[$i]\n"; }
	    $line =~ s|\$$key[$i]|$value[$i]|g;
	}
    }
}

# we need to find the structure size, including padding 
# i'm not sure I know the answer to this: it is probably 
# the total number of bytes rounded up to the largest 
# data item in the structure (ie, 8 for a double, etc)
# if we have the size, then we can double check the structure
# against the expectation at runtime.  for the moment,
# calculate by hand and add to def.d file 

