package manifest;


use XMLParser;
use strict;
no strict 'refs'; # allow filehandles to be variables and viceversa


our $self;

sub new {
    my ($class) = shift (@_);

    $self = {} ;

    $self->{'index'} = {};
    $self->{'reindex'} = {};
    $self->{'delete'} = {};

    return bless $self, $class;
}

sub parse
{
    my ($self) = shift (@_);
    my ($filename) = @_;

    my $parser = new XML::Parser('Style' => 'Stream',
                                 'Handlers' => {'Char' => \&Char,
                                                'XMLDecl' => \&XMLDecl,
                                                'Entity' => \&Entity,
                                                'Doctype' => \&Doctype,
                                                'Default' => \&Default
                                                });

    $parser->parsefile($filename);
}

sub StartDocument {$self->xml_start_document(@_);}
sub XMLDecl {$self->xml_xmldecl(@_);}
sub Entity {$self->xml_entity(@_);}
sub Doctype {$self->xml_doctype(@_);}
sub StartTag {$self->xml_start_tag(@_);}
sub EndTag {$self->xml_end_tag(@_);}
sub Text {$self->xml_text(@_);}
sub PI {$self->xml_pi(@_);}
sub EndDocument {$self->xml_end_document(@_);}
sub Default {$self->xml_default(@_);}

# This Char function overrides the one in XML::Parser::Stream to overcome a
# problem where $expat->{Text} is treated as the return value, slowing
# things down significantly in some cases.
sub Char {
    use bytes;  # Necessary to prevent encoding issues with XML::Parser 2.31+
    $_[0]->{'Text'} .= $_[1];
    return undef;
}

# Called at the beginning of the XML document.
sub xml_start_document {
    my $self = shift(@_);
    my ($expat) = @_;

}

# Called for XML declarations
sub xml_xmldecl {
    my $self = shift(@_);
    my ($expat, $version, $encoding, $standalone) = @_;
}

# Called for XML entities
sub xml_entity {
  my $self = shift(@_);
  my ($expat, $name, $val, $sysid, $pubid, $ndata) = @_;
}

# Called for DOCTYPE declarations - use die to bail out if this doctype
# is not meant for this plugin
sub xml_doctype {
    my $self = shift(@_);
    my ($expat, $name, $sysid, $pubid, $internal) = @_;
    die "Manifest Cannot process XML document with DOCTYPE of $name";
}

# Called for every start tag. The $_ variable will contain a copy of the
# tag and the %_ variable will contain the element's attributes.
sub xml_start_tag {
    my $self = shift(@_);
    my ($expat, $element) = @_;

    if ($_ =~ m/^<(Index|Reindex|Delete)>$/) {
	my $tag = $1;
	if (defined $self->{'file-type'}) {
	    print STDERR "Warning: Malformed XML manifest.  ";
	    print STDERR "$tag nested inside ", $self->{'file-type'}, "\n";
	    print STDERR "         Changing file-type scope to $tag\n";
	}

	$self->{'file-type'} = lc($tag);
    }
    elsif ($_ eq "<Filename>") {
	$self->{'filename'} = "";
    }
}

# Called for every end tag. The $_ variable will contain a copy of the tag.
sub xml_end_tag {
    my $self = shift(@_);
    my ($expat, $element) = @_;

    if ($_ =~ m/^<\/(Index|Reindex|Delete)>$/) {
	$self->{'file-type'} = undef;
    }
    elsif ($_ eq "</Filename>") {
	my $file_type = $self->{'file-type'};
	my $filename = $self->{'filename'};

	$self->{$file_type}->{$filename} = 1;

	$self->{'filename'} = undef;
    }

}

# Called just before start or end tags with accumulated non-markup text in
# the $_ variable.
sub xml_text {
    my $self = shift(@_);
    my ($expat) = @_;

    if (defined $self->{'filename'}) {
	my $text = $_;
	chomp($text);

	$text =~ s/^\s+//;
	$text =~ s/\s+$//;	
	
	$self->{'filename'} .= $text if ($text !~ m/^\s*$/);
    }
}

# Called for processing instructions. The $_ variable will contain a copy
# of the pi.
sub xml_pi {
    my $self = shift(@_);
    my ($expat, $target, $data) = @_;
}

# Called at the end of the XML document.
sub xml_end_document {
    my $self = shift(@_);
    my ($expat) = @_;

}

# Called for any characters not handled by the above functions.
sub xml_default {
    my $self = shift(@_);
    my ($expat, $text) = @_;
}


1;
