
#############################################################################
## $Id: Html.pm 6000 2006-05-02 13:43:59Z spadkins $
#############################################################################

package App::Serializer::Html;
$VERSION = (q$Revision: 6000 $ =~ /(\d[\d\.]*)/)[0];  # VERSION numbers generated by svn

use App;
use App::Serializer;
@ISA = ( "App::Serializer" );

use strict;

=head1 NAME

App::Serializer::Html - Interface for serialization and deserialization

=head1 SYNOPSIS

    use App;

    $context = App->context();
    $serializer = $context->service("Serializer");  # or ...
    $serializer = $context->serializer();
    $data = {
        an => 'arbitrary',
        collection => [ 'of', 'data', ],
        of => {
            arbitrary => 'depth',
        },
    };
    $html = $serializer->serialize($data);
    $data = $serializer->deserialize($html);
    print $serializer->dump($data), "\n";

=head1 DESCRIPTION

A Serializer allows you to serialize a structure of data
of arbitrary depth to a scalar and deserialize it back to the
structure.

The Html serializer uses HTML data structure syntax as the serialized
form of the data.  It uses the Data::Dumper module from CPAN to perform
the deserialization and serialization.

=cut

sub serialize {
    &App::sub_entry if ($App::trace);
    my ($self, $perl_scalar) = @_;
    my $html = <<EOF;
<html>
<head>
  <title>Data</title>
</head>
<body>
EOF
    $html .= $self->_serialize($perl_scalar);
    $html .= <<EOF;
</body>
</html>
EOF
    &App::sub_exit($html) if ($App::trace);
    return($html);
}

sub _serialize {
    &App::sub_entry if ($App::trace);
    my ($self, $perl_scalar) = @_;
    my $ref = ref($perl_scalar);
    my $html = "";
    if (!$ref) {
        $html = $perl_scalar;
    }
    elsif ($ref eq "ARRAY") {
        if ($#$perl_scalar == -1) {
            $html .= "[ empty array ]";
        }
        elsif (ref($perl_scalar->[0]) eq "ARRAY") {
            $html .= '<table border="1" cellspacing="0">' . "\n";
            my ($data);
            for (my $r = 0; $r <= $#$perl_scalar; $r++) {
                $html .= "  <tr>\n";
                my $row = $perl_scalar->[$r];
                if (ref($row) eq "ARRAY") {
                    for (my $c = 0; $c <= $#$row; $c++) {
                        $html .= "    <td>";
                        $data = $row->[$c];
                        $html .= (defined $data && $data ne "") ? $self->_serialize($data) : "&nbsp;";
                        $html .= "</td>\n";
                    }
                }
                else {
                    $html .= "    <td>";
                    $html .= $self->_serialize($row);
                    $html .= "</td>\n";
                }
                $html .= "  </tr>\n";
            }
            $html .= "</table>\n";
        }
        elsif (ref($perl_scalar->[0]) eq "HASH") {
            $html .= '<table border="1" cellspacing="0">' . "\n";

            my (%column_idx, @columns);
            for (my $r = 0; $r <= $#$perl_scalar; $r++) {
                my $row = $perl_scalar->[$r];
                if (ref($row) eq "HASH") {
                    my @row_columns = sort keys %$row;
                    for (my $c = 0; $c <= $#row_columns; $c++) {
                        if (! defined $column_idx{$row_columns[$c]}) {
                            push(@columns, $row_columns[$c]);
                            $column_idx{$row_columns[$c]} = $#row_columns;
                        }
                    }
                }
            }

            $html .= "  <tr>\n";
            for (my $c = 0; $c <= $#columns; $c++) {
                $html .= "    <th>$columns[$c]</th>\n";
            }
            $html .= "  </tr>\n";

            my ($data);
            for (my $r = 0; $r <= $#$perl_scalar; $r++) {
                $html .= "  <tr>\n";
                my $row = $perl_scalar->[$r];
                if (ref($row) eq "HASH") {
                    for (my $c = 0; $c <= $#columns; $c++) {
                        $html .= "    <td>";
                        $data = $row->{$columns[$c]};
                        $html .= (defined $data && $data ne "") ? $self->_serialize($row->{$columns[$c]}) : "&nbsp;";
                        $html .= "</td>\n";
                    }
                }
                else {
                    $html .= "    <td>";
                    $html .= $self->_serialize($row);
                    $html .= "</td>\n";
                }
                $html .= "  </tr>\n";
            }
            $html .= "</table>\n";
        }
        else {
            $html .= '<table border="1" cellspacing="0">' . "\n";
            for (my $i = 0; $i <= $#$perl_scalar; $i++) {
                $html .= "  <tr><td>$i</td><td>";
                $html .= $self->_serialize($perl_scalar->[$i]);
                $html .= "</td></tr>\n";
            }
            $html .= "</table>\n";
        }
    }
    elsif ($ref eq "HASH") {
        $html .= "<ul>\n";
        foreach my $key (sort keys %$perl_scalar) {
            $html .= "  <li><strong>$key</strong>: ";
            $html .= ref($perl_scalar->{$key}) ? $self->_serialize($perl_scalar->{$key}) : $perl_scalar->{$key};
            $html .= "</li>\n";
        }
        $html .= "</ul>\n";
    }
    else {
        $html = $perl_scalar;
    }
    &App::sub_exit($html) if ($App::trace);
    return($html);
}

sub deserialize {
    &App::sub_entry if ($App::trace);
    my ($self, $html) = @_;
    my $perl_scalar = "html";   # TBD ?!?
    &App::sub_exit($perl_scalar) if ($App::trace);
    return($perl_scalar);
}

sub serialized_content_type {
    'text/html';
}

1;

