Index: trunk/gsdl/perllib/plugins/StructuredHTMLPlug.pm
===================================================================
--- trunk/gsdl/perllib/plugins/StructuredHTMLPlug.pm	(revision 10271)
+++ trunk/gsdl/perllib/plugins/StructuredHTMLPlug.pm	(revision 10271)
@@ -0,0 +1,423 @@
+###########################################################################
+#
+# StructuredHTMLPlug.pm -- html plugin with extra facilities for teasing out 
+# hierarchical structure (such as h1, h2, h3 tags) in an HTML document
+#
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 New Zealand Digital Library Project
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+package StructuredHTMLPlug;
+
+use HTMLPlug;
+use ImagePlug;
+
+sub BEGIN {
+    @ISA = ('HTMLPlug');
+}
+
+my $arguments =
+    [ { 'name' => "check_toc",
+	'desc' => "StructuredHTMLPlug.check_toc'}",
+	'type' => "flag",
+	'reqd' => "no"},
+      { 'name' => "title_header",
+	'desc' => "{StructuredHTMLPlug.title_header}",
+	'type' => "regexp",
+	'reqd' => "no"},
+      { 'name' => "level1_header",
+	'desc' => "{StructuredHTMLPlug.level1_header}",
+	'type' => "regexp",
+	'reqd' => "no"},
+      { 'name' => "level2_header",
+	'desc' => "{StructuredHTMLPlug.level2_header}",
+	'type' => "regexp",
+	'reqd' => "no"},
+      { 'name' => "level3_header",
+	'desc' => "{StructuredHTMLPlug.level3_header}",
+	'type' => "regexp",
+	'reqd' => "no"},
+      { 'name' => "toc_header",
+	'desc' => "{StructuredHTMLPlug.toc_header}",
+	'type' => "regexp",
+	'reqd' => "no"},
+      { 'name' => "tof_header",
+	'desc' => "{StructuredHTMLPlug.tof_header}",
+	'type' => "regexp",
+	'reqd' => "no"}];
+
+my $options = { 'name'     => "StructuredHTMLPlug",
+		'desc'     => "{StructuredHTMLPlug.desc}",
+		'abstract' => "no",
+		'inherits' => "yes",
+		'args'     => $arguments };
+
+sub new {
+    my ($class) = shift (@_);
+    my ($pluginlist,$inputargs,$hashArgOptLists) = @_;
+    push(@$pluginlist, $class);
+    
+    if(defined $arguments){ push(@{$hashArgOptLists->{"ArgList"}},@{$arguments});}
+    if(defined $options) { push(@{$hashArgOptLists->{"OptList"}},$options)};
+    
+    #my $self = (defined $hashArgOptLists)? new ConvertToPlug($pluginlist,$inputargs,$hashArgOptLists): new ConvertToPlug($pluginlist,$inputargs);
+    my $self = (defined $hashArgOptLists)? new HTMLPlug($pluginlist,$inputargs,$hashArgOptLists): new HTMLPlug($pluginlist,$inputargs);
+    
+    print STDERR "*** StrucHTML = $self->{'assoc_files'}\n";
+
+    return bless $self, $class;
+
+}
+
+#sub new
+#{
+#    my $class = shift (@_);
+#    my $self = new HTMLPlug ($class, @_);
+#    $self->{'plugin_type'} = "StructuredHTMLPlug";
+#    
+#    # 14-05-02 To allow for proper inheritance of arguments - John Thompson
+#    my $option_list = $self->{'option_list'};
+#    push( @{$option_list}, $options );
+
+#    if (!parsargv::parse(\@_, 
+#			 q^check_toc^,\$self->{'check_toc'},
+#			 q^title_header/.*/^,\$self->{'title_header'},
+#		         q^toc_header/.*/^,\$self->{'toc_header'},
+#			 q^tof_header/.*/^,\$self->{'tof_header'},
+#			 q^level1_header/.*/^,\$self->{'level1_header'},
+#			 q^level2_header/.*/^,\$self->{'level2_header'},
+#			 q^level3_header/.*/^,\$self->{'level3_header'}, 
+#			 "allow_extra_options")) {
+#	
+#	#my $self = new HTMLPlug($class, @_);
+#	print STDERR "\nIncorrect options passed to $plugin_name, ";
+#	print STDERR "check your collect.cfg configuration file\n";
+#	$self->print_txt_usage("");  # Use default resource bundle
+#	die "\n";
+#    }
+#    return bless $self, $class;
+#}
+
+
+sub read {
+    my $self = shift (@_);  
+    my ($pluginfo, $base_dir, $file, $metadata, $processor, $maxdocs, $gli) = @_;
+
+    my $filename = $file;
+    $filename = &util::filename_cat ($base_dir, $file) if $base_dir =~ /\w/;
+
+    if ($filename =~ m/\.html?$/) {
+	my $poss_doc_filename = $filename;
+	$poss_doc_filename =~ s/\.html?$/.doc/;
+
+	if (-e $poss_doc_filename) {
+	    # this file has already been processed by Word plugin
+	    return 0;
+	}
+    }
+    return $self->SUPER::read(@_);
+}
+
+sub process {
+    my $self = shift (@_);
+    my ($textref, $pluginfo, $base_dir, $file, $metadata, $doc_obj) = @_;
+    my $outhandle = $self->{'outhandle'};
+
+    print $outhandle "StructuredHTMLPlug: processing $file\n"
+        if $self->{'verbosity'} > 1;
+
+    my @head_and_body = split(/<body/i,$$textref);
+    my $head = shift(@head_and_body);
+    my $body_text = join("<body", @head_and_body);
+
+    # get rid of TOC and TOF sections and their title
+    # If check_toc is enables, it means to get rid of toc and tof contents.
+    if ($self->{'check_toc'}){
+	#line-height:150%;mso-ansi-language:FR'>Contents<o:p></o:p></span></b></p>
+	# get rid of Table of Contents title and Table of Figures 
+	$body_text =~ s/<p[^>]*><b><span[^>]*>(Table of Content.|Content.)<o:p><\/o:p><\/span><\/b><\/p>//isg;
+	$body_text =~ s/<p[^>]*><b><span[^>]*>(Table of Figure.|Figure.)<o:p><\/o:p><\/span><\/b><\/p>//isg;
+	$body_text =~ s/<p class=(($self->{'toc_header'})[^>]*)>(.+?)<\/p>//isg;
+	$body_text =~ s/<p class=(($self->{'tof_header'})[^>]*)>(.+?)<\/p>//isg;
+    }
+
+    if ($self->{'title_header'}){
+	$self->{'title_header'} =~ s/^(\()(.*)(\))/$2/is;
+	$body_text =~ s/<p class=(($self->{'title_header'})[^>]*)>(.+?)<\/p>/<p class=$1><title>$3<\/title><\/p>/isg;
+    }
+    if ($self->{'level1_header'}){
+	$self->{'level1_header'} =~ s/^(\()(.*)(\))/$2/is;
+	$body_text =~ s/<p class=(($self->{'level1_header'})[^>]*)>(.+?)<\/p>/<p class=$1><h1>$3<\/h1><\/p>/isg;
+    }
+    if ($self->{'level2_header'}){
+	$self->{'level2_header'} =~ s/^(\()(.*)(\))/$2/is;
+	$body_text =~ s/<p class=(($self->{'level2_header'})[^>]*)>(.+?)<\/p>/<p class=$1><h2>$3<\/h2><\/p>/isg;
+    }
+    
+    if ($self->{'level3_header'}){
+	$self->{'level3_header'} =~ s/^(\()(.*)(\))/$2/is;
+	$body_text =~ s/<p class=(($self->{'level3_header'})[^>]*)>(.+?)<\/p>/<p class=$1><h3>$3<\/h3><\/p>/isg;
+    }
+        
+    # Tidy up extra new lines
+    $body_text =~ s/(<p[^>]*><span[^>]*><o:p>&nbsp;<\/o:p><\/span><\/p>)//isg;
+    $body_text =~ s/(<p[^>]*><o:p>&nbsp;<\/o:p><\/p>)//isg;
+
+    my $body = "<body".$body_text;
+    
+    my $section_text = $head;
+    $section_text .= "<!--\n<Section>\n-->\n";
+
+    # split HTML text on <h1>, <h2> etc tags
+    my @h_split = split(/<h/i,$body);
+ 
+    my $hnum = 0;
+
+    my $sectionh1 = 0;
+    $section_text .= shift(@h_split);
+
+    my $hc;
+    foreach $hc ( @h_split )
+    {
+	if ($hc =~ m/^([1-3])\s*.*?>(.*)$/s)
+	{
+	    my $new_hnum = $1;
+	    my $hc_after = $2;
+	    
+	    if ($hc_after =~ m/^(.*?)<\/h$new_hnum>/is)
+	    {
+		my $h_text = $1;
+		$hc =~ s/^(\&nbsp\;)+/\&nbsp\;/g;
+		# boil HTML down to some interesting text
+		$h_text =~ s/^[1-3]>//;
+		$h_text =~ s/<\/?.*?>//sg;
+		$h_text =~ s/\s+/ /sg;
+		$h_text =~ s/^\s$//s;
+		$h_text =~ s/(&nbsp;)+\W*/&nbsp;/sg;
+
+		if ($h_text =~ m/\w+/)
+		{
+		    if ($new_hnum > $hnum)
+		    {
+			# increase section nesting
+			$hnum++;
+			while ($hnum < $new_hnum)
+			{
+			    my $spacing = "  " x $hnum;
+			    $section_text .= "<!--\n";
+			    $section_text .= $spacing."<Section>\n";
+			    $section_text .= "-->\n";
+			    $hnum++;
+			}
+		    }
+		    else # ($new_hnum <= $hnum)
+		    {
+			# descrease section nesting
+			while ($hnum >= $new_hnum)
+			{
+			    my $spacing = "  " x $hnum;
+			    $section_text .= "<!--\n";
+			    $section_text .= $spacing."</Section>\n";
+			    $section_text .= "-->\n";
+			    $hnum--;
+			}
+			$hnum++;
+		    }
+
+		    my $spacing = "  " x $hnum;		    
+		    $section_text .= "<!--\n";
+		    $section_text .= $spacing."<Section>\n";
+		    $section_text .= $spacing."  <Description>\n";
+		    $section_text .= $spacing."    <Metadata name=\"Title\">$h_text</Metadata>";
+		    $section_text .= $spacing."  </Description>\n";
+		    $section_text .= "-->\n";
+		    
+		    print $outhandle $spacing."$h_text\n"
+			if $self->{'verbosity'} > 2;
+
+		    $sectionh1++ if ($hnum==1);
+		}
+	    }
+	    else {
+###		print STDERR "***** hc = <h$hc\n\n";
+		
+	    }
+	    # $section_text .= "<!-- \n</Section>\n-->\n";
+	    #print STDERR "***HC = $hc\n";
+	    $section_text .= "<h$hc";
+	}
+	else
+	{
+	    $section_text .= "<h$hc";
+	}
+    }
+
+    while ($hnum >= 1)
+    {
+	my $spacing = "  " x $hnum;
+	$section_text .= "<!--\n";
+	$section_text .= $spacing."</Section>\n";
+	$section_text .= "-->\n";
+	$hnum--;
+    }
+
+    $section_text .= "<!--\n</Section>\n-->\n";
+
+    $$textref = $section_text;
+
+# should be textref not testref???
+#    $$testref =~ s/<h(\d+)>(.*?)<\/h$1>/<Section><Metadata name=\"Title\">$1<\/Metadata></Section><h$1><\/h$1>/gi;
+
+    if ($sectionh1>0)
+    {
+	print $outhandle "  Located section headings ..."
+	    if $self->{'verbosity'} > 1;
+    }
+    print $outhandle "  Passing on the HTMLPlug\n"
+	if $self->{'verbosity'} > 1;
+
+    $$textref =~ s/<!\[if !vml\]>/<![if vml]>/g;
+
+    $$textref =~ s/(&nbsp;)+/&nbsp;/sg;    
+
+##    $$textref =~ s/<o:p>&nbsp;<\/o:p>//g; # used with VML to space figures?
+    
+    $self->SUPER::process(@_);
+
+    # associate original file with doc object
+    my $cursection = $doc_obj->get_top_section();
+    my $filename = &util::filename_cat($base_dir, $file);
+    if (-e $filename)
+    {
+	print $outhandle "  Adding associated Word document\n"
+	    if $self->{'verbosity'} > 1;
+	
+	$doc_obj->associate_file($filename, "doc.doc", undef, $cursection);
+
+	my $doclink = "<a href=_httpcollection_/index/assoc/[archivedir]/doc.doc>";
+	$doc_obj->add_utf8_metadata ($cursection, "srclink",  $doclink);
+	$doc_obj->add_utf8_metadata ($cursection, "srcicon",  "_icondoc_");
+	$doc_obj->add_utf8_metadata ($cursection, "/srclink", "</a>");
+
+	my $file_size = -s $filename;
+	if ($file_size>1024)
+	{
+	    my $fs_kbytes = sprintf("%d",$file_size/1024);
+	    $doc_obj->add_utf8_metadata ($cursection, "filesize", "$fs_kbytes Kb");
+	}
+	else
+	{
+	    $doc_obj->add_utf8_metadata ($cursection, "filesize", "$file_size bytes");
+	}
+
+	if ($file_size > 200000)
+	{
+	    $doc_obj->add_utf8_metadata ($cursection, "fswarning", "1");
+	}
+    }
+}
+
+
+sub resize_if_necessary
+{
+    my ($self,$front,$back,$base_dir,$href) = @_;
+
+    # dig out width and height of image, if there
+    my $img_attributes = "$front back";
+    my ($img_width)  = ($img_attributes =~ m/\s+width=\"?(\d+)\"?/i);
+    my ($img_height) = ($img_attributes =~ m/\s+height=\"?(\d+)\"?/i);
+
+    # derive local filename for image based on its URL
+    my $img_filename = $href;
+    $img_filename =~ s/^[^:]*:\/\///;
+    $img_filename = &util::filename_cat($base_dir, $img_filename);
+       
+    # Replace %20's in URL with a space if required. Note that the filename
+    # may include the %20 in some situations
+    if ($img_filename =~ /\%20/) {
+	if (!-e $img_filename) {
+	    $img_filename =~ s/\%20/ /g;
+	}
+    }
+    if ((-e $img_filename) && (defined $img_width) && (defined $img_height)) {
+	# get image info on width and height
+
+	my $outhandle = $self->{'outhandle'};
+	my $verbosity = $self->{'verbosity'};
+
+	my ($image_type, $actual_width, $actual_height, $image_size) 
+	    = &ImagePlug::identify($img_filename, $outhandle, $verbosity);
+
+	print STDERR "**** $actual_width x $actual_height";
+	print STDERR " (requested: $img_width x $img_height)\n";
+
+	if (($img_width < $actual_width) || ($img_height < $actual_height)) {
+	    print $outhandle "Resizing $img_filename\n" if ($verbosity > 0);
+
+	    # derive new image name based on current image
+	    my ($tailname, $dirname, $suffix)
+		= &File::Basename::fileparse($input_filename, "\\.[^\\.]+\$");
+
+	    my $resized_filename 
+		= &util::filename_cat($dirname, $tailname."_resized".$suffix);
+
+	    print STDERR "**** suffix = $suffix\n";
+
+	    # Generate smaller image with convert
+	    my $newsize = "$img_widthx$image_height";
+	    my $command = "convert -interlace plane -verbose "
+		."-geometry $newsize \"img_$filename\" \"$resized_filename\"";
+	    print $outhandle "ImageResize: $command\n" if ($verbosity > 2);
+	    my $result = '';
+	    print $outhandle "ImageResize result: $result\n" if ($verbosity > 2);
+
+	}
+    }
+
+    return $href;
+}
+
+
+
+
+sub replace_images {
+    my $self = shift (@_);
+    my ($front, $link, $back, $base_dir, 
+	$file, $doc_obj, $section) = @_;
+    # remove quotes from link at start and end if necessary
+    if ($link=~/^\"/) {
+	$link=~s/^\"//;$link=~s/\"$//;
+	$front.='"';
+	$back="\"$back";
+    }
+
+    $link =~ s/\n/ /g;
+
+    my ($href, $hash_part, $rl) = $self->format_link ($link, $base_dir, $file);
+
+##    $href = $self->resize_if_necessary($front,$back,$base_dir,$href);
+
+    my $middle = $self->add_file ($href, $rl, $hash_part, $base_dir, $doc_obj, $section);
+
+    return $front . $middle . $back;
+}
+
+
+1;
