#!/usr/bin/perl

#
# This script generates the property table for the integration specification.
# The script uses the definitions.xml files of the SVG 1.1 Full and SVG 1.2
# Tiny specifications as the source for the property names and links to their
# description. The final output produced is a HTML file containing a list of
# all the properties (with links) to SVG 1.1 Full and SVG 1.2 Tiny.
#
# A good understanding of how perl passes objects by reference is required as
# the script uses references to pass objects to functions. Additionally,
# knowledge in XSLT is required as XSLTs are used to pull information from the
# definition.xml files.
#
# This script was originally written by Anthony Grasso
#

#--- Static strings ------------------------------------------------------------

#
# Spec URLs.
#
$SVG_11_FULL_URL = "http\:\/\/www\.w3\.org\/TR\/SVG11\/";
$SVG_12_TINY_URL = "http\:\/\/www\.w3\.org\/TR\/SVGTiny12\/";

$SVG_11_FULL_DEFINITIONS = "../../../profiles/1.1F2/master/definitions.xml";
$SVG_12_TINY_DEFINITIONS = "../../../profiles/1.2T/master/definitions.xml";

$EXTRACT_PRES_ATTR_XSL = "./script-resources/extract_presentation_attributes.xsl";
$EXTRACT_PROP_INFO_XSL = "./script-resources/extract_property_information.xsl";

$HTML_OUTPUT_FILE = "property_table.html";

#--- Global data ---------------------------------------------------------------

#
# Enable debugging output
#
$ptm_debugging_enabled;

#
# Presentation Attribute Lookup Table
#
# Hash table to store the presentation attributes that are properties. The
# entries in this table will be of type PTM_PropAttrEntry.
#
%pres_attr_table_11f;
%pres_attr_table_12t;

#
# Main Property List
#
# Properties Lookup Table
#
%prop_table_11f;
%prop_table_12t;


#--- Data types ----------------------------------------------------------------

#
# PTM_PresAttrEntry
#
# Description:
#   This structure is used to store the presenational attribute information
#   that relate to certain properties. The category name and the URL to the
#   category definition are stored on the ppa_Category member array.
#
# Members:
#   ppm_Name        Attribute name.
#
#   ppm_Category    Category name and URL which the presentation attribute
#                   belongs to.
#
$PTM_PresAttrEntry =
{
    TEXT      => $ppa_Name,
    LOOKUP    => {%ppa_Category},
};


#--- Function definitions ------------------------------------------------------

#
# PTM_parse_presentation_attribute_information
#
# Description:
#   This function parses the lines containing the presentation attribute
#   information gathered from the XML definitions file. The parsed data is used
#   to populate the presentation attribute "pres_attr_table". A single line to
#   be parsed is of the format:
#
#   [attribute type]|[type href ]|[[attribute names]
#
#   [ segment 0    ]|[ segment 1]|[ segment 2      ]
#
# Parameters:
#   $line_ptr             - [Argument 1] Reference to the line to parse.
#
#   $pres_attr_table_ptr  - [Argument 2] Reference to the hash table to populate.
#
sub PTM_parse_presentation_attribute_information
{
    #
    # Obtain references to arguments and split the line up into segments.
    #
    my ($line_ptr, $pres_attr_table_ptr) = @_;
    my @line_segments = split(/\|/, ${$line_ptr});

    my $type_name = $line_segments[0];
    my $type_href = $line_segments[1];

    #
    # Check if we have more than a single segment in the line. If there is only
    # one segment it means only a name is supplied which is pointless as there
    # is no href or list of attribute names.
    #
    if (@line_segments < 3)
    {
        return 0;
    }

    print "Found attribute type: ".$line_segments[0]."\n";

    #
    # Get the list of presentation attributes for the particular type.
    #
    my @attr_list = split(/,/, $line_segments[2]);

    foreach $attribute (@attr_list)
    {
        #
        # Remove any inital spaces
        #
        $attribute =~ m/\s*([a-zA-Z0-9\:\-]*)/;
        $attribute = $1;

        if (!exists ${$pres_attr_table_ptr}{$attribute})
        {
            print " adding attribute to table: \'".$attribute."\' to table\n";

            $PTM_PresAttrEntry = {};
            $PTM_PresAttrEntry->{ppa_Name} = $attribute;
            $PTM_PresAttrEntry->{ppa_Category}{$type_name} = $type_href;

            ${$pres_attr_table_ptr}{$attribute} = $PTM_PresAttrEntry;
        }
        else
        {
            print " appending to current attribute entry: \'".$attribute."\'\n";

            ${$pres_attr_table_ptr}{$attribute}->{ppa_Category}{$type_name} = $type_href;
        }
    }
}


#
# PTM_parse_property_information
#
# Description:
#   This function parses the lines containing the property information gathered
#   from the XML definitions file. The parsed data is used to populate the
#   property table "prop_table". A single line to be parsed is of the format:
#
#   [property name]|[property href ]
#
#   [ segment 0   ]|[ segment 1    ]
#
# Parameters:
#   $line_ptr         - [Argument 1] Reference to the line to parse.
#
#   $prop_table_ptr   - [Argument 2] Reference to the property table to populate.
#
sub PTM_parse_property_information
{
    #
    # Obtain references to arguments and split the line up into segments and
    # append the segments to the list.
    #
    my ($line_ptr, $prop_table_ptr) = @_;
    my @line_segments = split(/\|/, ${$line_ptr});

    print " adding property: \'".$line_segments[0]."\' to table\n";

    ${$prop_table_ptr}{$line_segments[0]} = $line_segments[1];
}


#
# PTM_write_html_doc_head
#
sub PTM_write_html_doc_head
{
    print HTML_FH   "<html xmlns=\"http\:\/\/www\.w3\.org\/1999\/xhtml\" >\n",
                    "  <head>\n",
                    "    <title>SVG Property Table</title>\n",
                    "    <link rel=\"stylesheet\" href=\"style\/svg-style\.css\" type=\"text\/css\" media=\"all\" />\n",
                    "  </head>\n",
                    "  <body>\n";
}

#
# PTM_write_html_doc_end
#
sub PTM_write_html_doc_end
{
    print HTML_FH   "  </body>\n",
                    "</html>";
}

#
# PTM_write_html_table_head
#
sub PTM_write_html_table_head
{
    print HTML_FH   "    <table border=\"1\" cellpadding=\"5\" cellspacing=\"0\" >\n",
                    "      <tbody>\n",
                    "        <tr>\n",
                    "          <th rowspan=\"2\">Property</th>\n",
                    "          <th rowspan=\"2\">Type</th>\n",
                    "          <th colspan=\"2\">Attribute</th>\n",
                    "        </tr>\n",
                    "        <tr>\n",
                    "          <th>SVG 1.1</th>\n",
                    "          <th>SVG 1.2</th>\n",
                    "        </tr>\n";
}

#
# PTM_write_html_table_end
#
sub PTM_write_html_table_end
{
    print HTML_FH   "      </tbody>\n",
                    "    </table>\n";
}

#
# PTM_write_html_table_single_entry
#
sub PTM_write_html_table_single_entry
{
    my ($prop_key_ptr, $prop_table_ptr, $pres_attr_table_ptr, $url_ptr) = @_;

    my $prop_name = ${$prop_key_ptr};
    my $url_11f = "SVG11";
    my $url_12t = "SVGT12";
    my $link_style_11f = "svg11-no-link";
    my $link_style_12t = "svgt12-no-link";
    my $pres_attr_cat_11f = "<span class=\"svg11-na\">N/A</span>";
    my $pres_attr_cat_12t = "<span class=\"svg12-na\">N/A</span>";
    my $pres_attr_cat = "";

    if (exists ${$pres_attr_table_ptr}{${$prop_key_ptr}})
    {
        my @pres_attr_cat_list_sorted = sort(keys(%{${$pres_attr_table_ptr}{${$prop_key_ptr}}->{ppa_Category}}));
        my $list_itr = 0;

        for (; $list_itr < @pres_attr_cat_list_sorted;)
        {
            #
            # Generate a comma separated list of presentation attributes. However,
            # only write a comma out after the first line is processed.
            #
            if ($list_itr > 0)
            {
                $pres_attr_cat = $pres_attr_cat.", ";
            }

            $pres_attr_cat = $pres_attr_cat."<a href=\"${$url_ptr}${$pres_attr_table_ptr}{${$prop_key_ptr}}->{ppa_Category}{$pres_attr_cat_list_sorted[$list_itr]}\">$pres_attr_cat_list_sorted[$list_itr]</a>";

            $list_itr++;
        }
    }

    if (${$url_ptr} eq $SVG_11_FULL_URL)
    {
        $link_style_11f = "svg11-link";

        if ($pres_attr_cat ne "")
        {
            $pres_attr_cat_11f = $pres_attr_cat;
        }

        if (${$prop_table_ptr}{${$prop_key_ptr}} eq "")
        {
            goto print_attribte_row_heading;
        }

        $url_11f = "<a href=\"${$url_ptr}${$prop_table_ptr}{${$prop_key_ptr}}\">SVG11</a>";
    }
    else
    {
        $link_style_12t = "svgt12-link";

        if ($pres_attr_cat ne "")
        {
            $pres_attr_cat_12t = $pres_attr_cat;
        }

        if (${$prop_table_ptr}{${$prop_key_ptr}} eq "")
        {
            goto print_attribte_row_heading;
        }

        $url_12t = "<a href=\"${$url_ptr}${$prop_table_ptr}{${$prop_key_ptr}}\">SVGT12</a>";
    }

print_attribte_row_heading:
    print HTML_FH   "        <tr id=\"property_$prop_name\">\n",
                    "          <td>\n",
                    "            <span class=\"attr-name\">$prop_name</span>\n",
                    "            <br/>\n",
                    "            [<span class=\"$link_style_11f\">$url_11f</span>, <span class=\"$link_style_12t\">$url_12t</span>]\n",
                    "          </td>\n",
                    "          <td><span class=\"property\">property</span></td>\n",
                    "          <td>$pres_attr_cat_11f</td>\n",
                    "          <td>$pres_attr_cat_12t</td>\n",
                    "        </tr>\n";
}

#
# PTM_write_html_table_merge_entry
#
sub PTM_write_html_table_merge_entry
{
    my ($prop_key_ptr) = @_;

    my $prop_name = ${$prop_key_ptr};
    my $url_11f = "SVG11";
    my $url_12t = "SVGT12";
    my $pres_attr_cat_11f = "<span class=\"svg11-na\">N/A</span>";
    my $pres_attr_cat_12t = "<span class=\"svg12-na\">N/A</span>";

    if (exists $pres_attr_table_11f{${$prop_key_ptr}})
    {
        my @pres_attr_cat_list = sort(keys(%{$pres_attr_table_11f{${$prop_key_ptr}}->{ppa_Category}}));
        my $list_itr = 0;

        $pres_attr_cat_11f = "";

        for (; $list_itr < @pres_attr_cat_list;)
        {
            #
            # Generate a comma separated list of presentation attributes. However,
            # only write a comma out after the first line is processed.
            #
            if ($list_itr > 0)
            {
                $pres_attr_cat_11f = $pres_attr_cat_11f.", ";
            }

            $pres_attr_cat_11f = $pres_attr_cat_11f."<a href=\"$SVG_11_FULL_URL$pres_attr_table_11f{${$prop_key_ptr}}->{ppa_Category}{$pres_attr_cat_list[$list_itr]}\">$pres_attr_cat_list[$list_itr]</a>";

            $list_itr++;
        }
    }

    if (exists $pres_attr_table_12t{${$prop_key_ptr}})
    {
        my @pres_attr_cat_list = sort(keys(%{$pres_attr_table_12t{${$prop_key_ptr}}->{ppa_Category}}));
        my $list_itr = 0;

        $pres_attr_cat_12t = "";

        for (; $list_itr < @pres_attr_cat_list;)
        {
            #
            # Generate a comma separated list of presentation attributes. However,
            # only write a comma out after the first line is processed.
            #
            if ($list_itr > 0)
            {
                $pres_attr_cat_12t = $pres_attr_cat_12t.", ";
            }

            $pres_attr_cat_12t = $pres_attr_cat_12t."<a href=\"$SVG_12_TINY_URL$pres_attr_table_12t{${$prop_key_ptr}}->{ppa_Category}{$pres_attr_cat_list[$list_itr]}\">$pres_attr_cat_list[$list_itr]</a>";

            $list_itr++;
        }
    }

    if ($prop_table_11f{${$prop_key_ptr}} ne "")
    {
        $url_11f = "<a href=\"$SVG_11_FULL_URL$prop_table_11f{${$prop_key_ptr}}\">SVG11</a>";
    }

    if ($prop_table_12t{${$prop_key_ptr}} ne "")
    {
        $url_12t = "<a href=\"$SVG_12_TINY_URL$prop_table_12t{${$prop_key_ptr}}\">SVGT12</a>";
    }

    print HTML_FH   "        <tr id=\"property_$prop_name\">\n",
                    "          <td>\n",
                    "            <span class=\"attr-name\">$prop_name</span>\n",
                    "            <br/>\n",
                    "            [<span class=\"svg11-link\">$url_11f</span>, <span class=\"svgt12-link\">$url_12t</span>]\n",
                    "          </td>\n",
                    "          <td><span class=\"property\">property</span></td>\n",
                    "          <td>$pres_attr_cat_11f</td>\n",
                    "          <td>$pres_attr_cat_12t</td>\n",
                    "        </tr>\n";

}


#--- Main program operation ----------------------------------------------------

#
# Turn off debugging initially.
#
$ptm_debugging_enabled = 0;

if ($ARGV[0] eq "debug")
{
    $ptm_debugging_enabled = 1;
}

#
# The xslt output will be one long line with delimiters. An in the line '&'
# indicates a new line of data and a '|' indicates a segment of data. The
# initial XSLT output (single line) is gathered and stored in @xslt_output. The
# output is then split into single data lines according to the placement of the
# '&' and stored in @xslt_entries. Each entry is then processed. This procedure
# is performed each time an XSLT script is used to extract data from the
# definitions.xml files.
#

#
# Gather the <attributecategory> data to populate the presentation attribute
# lookup tables.
#
my @xslt_output = ();
my @xslt_entries = ();

print "\nPopulating presentation attribute lookup tables.\n";

open my $CMD_FH, "xsltproc --novalid $EXTRACT_PRES_ATTR_XSL $SVG_11_FULL_DEFINITIONS | " or die "cannot run command: $!";
@xslt_output = <$CMD_FH>;
close $CMD_FH;

@xslt_entries = split(/\&/, $xslt_output[0]);

foreach $line (@xslt_entries)
{
    PTM_parse_presentation_attribute_information(\$line, \%pres_attr_table_11f);
}


@xslt_output = ();
@xslt_entries = ();

open my $CMD_FH, "xsltproc --novalid $EXTRACT_PRES_ATTR_XSL $SVG_12_TINY_DEFINITIONS | " or die "cannot run command: $!";
@xslt_output = <$CMD_FH>;
close $CMD_FH;

@xslt_entries = split(/\&/, $xslt_output[0]);

foreach $line (@xslt_entries)
{
    PTM_parse_presentation_attribute_information(\$line, \%pres_attr_table_12t);
}


#
# Gather the <property> data that is defined and populate the attribute lookup
# tables.
#
print   "\nPopulating property tables.\n";

@xslt_output = ();
@xslt_entries = ();

open my $CMD_FH, "xsltproc --novalid $EXTRACT_PROP_INFO_XSL $SVG_11_FULL_DEFINITIONS | " or die "cannot run command: $!";
@xslt_output = <$CMD_FH>;
close $CMD_FH;

@xslt_entries = split(/\&/, $xslt_output[0]);

foreach $line (@xslt_entries)
{
    PTM_parse_property_information(\$line, \%prop_table_11f);
}


@xslt_output = ();
@xslt_entries = ();

open my $CMD_FH, "xsltproc --novalid $EXTRACT_PROP_INFO_XSL $SVG_12_TINY_DEFINITIONS | " or die "cannot run command: $!";
@xslt_output = <$CMD_FH>;
close $CMD_FH;

@xslt_entries = split(/\&/, $xslt_output[0]);

foreach $line (@xslt_entries)
{
    PTM_parse_property_information(\$line, \%prop_table_12t);
}


#
# Get an ordered list of the properties in the hash table.
#
my @prop_list_11f_sorted = sort(keys(%prop_table_11f));
my @prop_list_12t_sorted = sort(keys(%prop_table_12t));

if ($ptm_debugging_enabled == 1)
{
    print "\n";
    print "Entries in 11f list: ".@prop_list_11f_sorted."\n";
    print "Entries in 12t list: ".@prop_list_12t_sorted."\n";
    print "\n";
}

open HTML_FH, ">", $HTML_OUTPUT_FILE or die "Cannot open file for writing: $!\n";

PTM_write_html_doc_head();

PTM_write_html_table_head();

#
# Merge the two tables together.
#
my $list_11f_itr = 0;
my $list_12t_itr = 0;
my $cmp_result = 0;

while ($list_11f_itr < @prop_list_11f_sorted && $list_12t_itr < @prop_list_12t_sorted)
{
    #
    # $a cmp $b returns: 1 when $a > $b, -1 when $a < $b, and 0 when $a == $b.
    #
    $cmp_result = $prop_list_11f_sorted[$list_11f_itr] cmp $prop_list_12t_sorted[$list_12t_itr];
    if ($ptm_debugging_enabled == 1)
    {
        print "Comparing ".$prop_list_11f_sorted[$list_11f_itr]." and ".$prop_list_12t_sorted[$list_12t_itr]."... ";
    }

    #
    # If this case is true the 11F table entry > 12T table entry. The 12T table
    # entry needs to be processed and the iterator incremented because it is
    # behind.
    #
    if ($cmp_result == 1)
    {
        PTM_write_html_table_single_entry(\$prop_list_12t_sorted[$list_12t_itr], \%prop_table_12t, \%pres_attr_table_12t, \$SVG_12_TINY_URL);
        if ($ptm_debugging_enabled == 1)
        {
            print $prop_list_11f_sorted[$list_11f_itr]." > ".$prop_list_12t_sorted[$list_12t_itr]."\n";
        }
        $list_12t_itr++;
    }

    #
    # If this case is true the 11F table entry < 12T table entry The 11F table
    # entry needs to be processed and the iterator incremented because it is
    # behind.
    #
    if ($cmp_result == -1)
    {
        PTM_write_html_table_single_entry(\$prop_list_11f_sorted[$list_11f_itr], \%prop_table_11f, \%pres_attr_table_11f, \$SVG_11_FULL_URL);
        if ($ptm_debugging_enabled == 1)
        {
            print $prop_list_11f_sorted[$list_11f_itr]." < ".$prop_list_12t_sorted[$list_12t_itr]."\n";
        }
        $list_11f_itr++;
    }

    #
    # If this case is true the 11F table entry == 12T table entry. The two
    # entries are merged and both the 11F and 12T iterators are incremented.
    #
    if ($cmp_result == 0)
    {
        PTM_write_html_table_merge_entry(\$prop_list_11f_sorted[$list_11f_itr]);
        if ($ptm_debugging_enabled == 1)
        {
            print $prop_list_11f_sorted[$list_11f_itr]." == ".$prop_list_12t_sorted[$list_12t_itr]."\n";
        }
        $list_11f_itr++;
        $list_12t_itr++;
    }
}


PTM_write_html_table_end();

PTM_write_html_doc_end();

close HTML_FH;