#!/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 ("MENU");
    &init_key ("STYLE");
    &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, $show, $link, $extras) = split (/,\s+/, $value, 5);
	    # ($field) = $field =~ m|\s*(\S+)\s*|;

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

	# list of the table fields
 	if ($key eq "BODY.HTML") {
	    push @bodyhtml, $value;
	}

	# list of the table fields
 	if ($key eq "TAIL.HTML") {
	    push @tailhtml, $value;
	}

	# 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;
	}
    }

    # check on keys
    &check_key ("MENU", "ipp.menu.dat");
    &check_key ("STYLE", "ipp.css");
    &check_key ("TABLE", "");
    &check_key ("TITLE", "");
    &check_key ("FILE", "");
    
    # these are used internally (not just a replacement)
    for ($i = 0; $i < @key; $i++) {
	if ($key[$i] eq "MENU") { $MENU = $value[$i]; }
    }

    # define query string, add to keypairs
    &define_query_fields;

    if (0) {
	print STDERR "show: $show[0]\n";
	($a, $b, $c) = &parse_label ($show[0]);
	print STDERR "a: $a, b: $b, c: $c\n";

	print STDERR "extras: $extras[0]\n";
	($a, $b, $c) = &parse_label ($extras[0]);
	print STDERR "a: $a, b: $b, c: $c\n";

	print STDERR "show: $show[1]\n";
	($a, $b, $c) = &parse_label ($show[1]);
	print STDERR "a: $a, b: $b, c: $c\n";

	print STDERR "extras: $extras[1]\n";
	($a, $b, $c) = &parse_label ($extras[1]);
	print STDERR "a: $a, b: $b, c: $c\n";
	exit 0;
    }
}

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;
	}

	# fill in body HTML
	if ($line =~ m|// \*\* BODY HTML \*\*|) {
	    &write_body_html;
	}

	# fill in tail HTML
	if ($line =~ m|// \*\* TAIL HTML \*\*|) {
	    &write_tail_html;
	}
    }
    close (FILE);
}

sub write_body_html {
    my ($i);

    if (@bodyhtml == 0) { return; }
    printf FILE "?>\n";
    
    for ($i = 0; $i < @bodyhtml; $i++) {
	printf FILE "$bodyhtml[$i]\n";
    }
    printf FILE "<?\n";
}

sub write_tail_html {
    my ($i);

    if (@tailhtml == 0) { return; }
    printf FILE "?>\n";
    
    for ($i = 0; $i < @tailhtml; $i++) {
	printf FILE "$tailhtml[$i]\n";
    }
    printf FILE "<?\n";
}

sub write_table_header {

    for ($i = 0; $i < @field; $i++) {
	if ($show[$i] eq "none")  { next; }
	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 {
    my ($i);
    my ($label, $value, $string);

    for ($i = 0; $i < @field; $i++) {
	($label, $value, $string) = &parse_label ($show[$i]);

	# create the link variable if this entry should be linked
	if ($label eq "none")  { next; }

	if (($label eq "value") && !$link[$i]) { 
	    # print value without link or image
	    if (! $value) { $value = "\$row[$i]"; }
	    print FILE "  echo \"<td class=\\\"list\\\"> $value </td>\\n\";\n";
	    next;
	}

	if (($label eq "value") && $link[$i]) {
	    # create the basic link variable
	    printf FILE "  \$link = \"$link[$i]\" . \"?menu=$MENU&\" . \$ID['link'];\n";
	    # add extra GET data to target
	    if ($extras[$i]) { &parse_extras ($extras[$i]); } 
	    # print the actual table cell line with the link...
	    if (! $value) { $value = "\$row[$i]"; }
	    printf FILE "  echo \"<td class=\\\"list\\\"><a href=\\\"\$link\\\"> $value </a></td>\\n\";\n";
	    next;
	}

	if (($label eq "image") && !$link[$i]) {
	    # print the actual table cell line with the image...
	    printf FILE "  echo \"<td class=\\\"list\\\"><img src=\\\"$value\\\"></td>\\n\";\n";
	    next;
	}

	if (($label eq "image") && $link[$i]) {
	    # create the basic link 
	    printf FILE "  \$link = \"$link[$i]\" . \"?menu=$MENU&\" . \$ID['link'];\n";
	    # add extra php data to target
	    if ($extras[$i]) { &parse_extras ($extras[$i]); } 
	    # print the actual table cell line with the link...
	    printf FILE "  echo \"<td class=\\\"list\\\"><a href=\\\"\$link\\\"> <img src=\\\"$value\\\"> </a></td>\\n\";\n";
	    next;
	}
    }
}

sub write_table_query {

    for ($i = 0; $i < @field; $i++) {
	if ($show[$i] eq "none")  { next; }
	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 parse_extras {
    my ($extras) = $_[0];
    my (@extfields);
    my ($label, $value, $outline);
    my ($i);

    # examine the extras and parse the embedded fields (comma-separated)
    @extfields = split (/,/, $extras);
    for ($i = 0; $i < @extfields; $i++) {
	($label, $value, $outline) = &parse_label ($extfields[$i]);
	printf FILE "  \$link = \$link . \"&$outline\";\n";
    }
}

# parse strings of the form label=value
# if 'value' is of the form $field, try to match with 
# a supplied DB field, and replace with $row[$n] if found
sub parse_label {
    my ($string) = $_[0];
    my ($label, $value, $outline);
    my ($N, $i);

    # unless we replace the value with the db row element, return the original string
    $outline = $string;
    $label = $string;
    $value = "";

    # search for embedded table fields and replace with row[N]
    if ($VERBOSE) { print STDERR "string: $string\n"; }
    if ($string =~ m|\S+=\S+|) {
	($label, $value) = $string =~ m|(\S+)=(\S+)|;
	if ($value =~ m|^\$|) {
	  MATCH_LABEL:
	    for ($i = 0; $i < @field; $i++) {
		if ($value =~ m|^\$$field[$i]|) {
		    $value = "\$row[$i]";
		    last MATCH_LABEL;
		}
	    }
	    $outline = "$label=$value";
	} 
    }
    return ($label, $value, $outline);
}

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;
	    if ($VERBOSE) { print STDERR "setting $key = $value\n"; }
	    return;
	}
    }
}

sub check_key {
    my ($i);
    my ($key)     = $_[0];
    my ($default) = $_[1];

    for ($i = 0; $i < @key; $i++) {
	if ($key eq $key[$i]) {
	    if ($VERBOSE) { print "found $key: $key[$i]  -- $value[$i] (def: $default)\n"; }
	    if (($default eq "") && ($value[$i] eq "")) { die "missing value for required key $key[$i]\n"; }
	    if ($value[$i] eq "") { $value[$i] = $default; }
	    return;
	}
    }
    die "unknown key $key\n";
}

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 

