###########################################################################
#
# SplitPlug.pm - a plugin for splitting input files into segments that
#                will then be individually processed.
#
#
# Copyright 2000 Gordon W. Paynter (gwp@cs.waikato.ac.nz)
# Copyright 2000 The New Zealand Digital Library Project
#
# A component of the Greenstone digital library software
# from the New Zealand Digital Library Project at the 
# University of Waikato, New Zealand.
#
# 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.
#
###########################################################################


# SplitPlug is a plugin for splitting input files into segments that will
# then be individually processed.  

# This plugin should not be called directly.  Instead, if you need to
# process input files that contain several documents, you should write a
# plugin with a process function that will handle one of those documents
# and have it inherit from SplitPlug.  See ReferPlug for an example.


package SplitPlug;

use BasPlug;
use util;


# SplitPlug is a sub-class of BasPlug.
sub BEGIN {
    @ISA = ('BasPlug');
}

sub new {
    my ($class) = @_;
    $self = new BasPlug($class, @_);

    if (!parsargv::parse(\@_, 
			 q^split_exp/.*/^, \$self->{'split_exp'},
			 "allow_extra_options")) {
	print STDERR "\nIncorrect options passed to $class.";
	print STDERR "\nCheck your collect.cfg configuration file\n";
	die "\n";
    }

    return bless $self, $class;
}

sub init {
    my $self = shift (@_);
    my ($verbosity, $outhandle) = @_;

    $self->BasPlug::init($verbosity, $outhandle);

    if ((!defined $self->{'process_exp'}) || ($self->{'process_exp'} eq "")) {

	$self->{'process_exp'} = $self->get_default_process_exp ();
	if ($self->{'process_exp'} eq "") {
	    warn ref($self) . " Warning: Non-recursive plugin has no process_exp\n";
	}
    }


    # set split_exp to default unless explicitly set
    if (!$self->{'split_exp'}) {
	$self->{'split_exp'} = $self->get_default_split_exp ();
    }

}

# This plugin recurs over the segments it finds
sub is_recursive {
    return 1;
}

# By default, we split the input text at blank lines
sub get_default_split_exp {
    return q^\n\s*\n^;
}


# The read function opens a file and splits it into parts. 
# Each part is sent to the process function
#
# Returns: Number of document objects created (or undef if it fails)

sub read {
    my $self = shift (@_);
    my ($pluginfo, $base_dir, $file, $metadata, $processor, $maxdocs) = @_;
    my $outhandle = $self->{'outhandle'};
    my $verbosity = $self->{'verbosity'};

    # Figure out the exact filename of this file (and maybe block it)
    my $filename = &util::filename_cat($base_dir, $file);
    my $block_exp = $self->{'block_exp'};
    return 0 if $self->{'block_exp'} ne "" && $filename =~ /$self->{'block_exp'}/;
    if ($filename !~ /$self->{'process_exp'}/ || !-f $filename) {
	return undef;
    }
    my $plugin_name = ref ($self);
    $file =~ s/^[\/\\]+//; # $file often begins with / so we'll tidy it up
    
    my ($language, $encoding);
    if ($self->{'input_encoding'} eq "auto") {
	# use textcat to automatically work out the input encoding and language
	($language, $encoding) = $self->get_language_encoding ($filename);
	
    } elsif ($self->{'extract_language'}) {
	# use textcat to get language metadata
	($language, $extracted_encoding) = $self->get_language_encoding ($filename);
	$encoding = $self->{'input_encoding'};
	
	if ($extracted_encoding ne $encoding && $self->{'verbosity'}) {
	    print $outhandle "$plugin_name: WARNING: $file was read using $encoding encoding but ";
	    print $outhandle "appears to be encoded as $extracted_encoding.\n";
	}
	
    } else {
	$language = $self->{'default_language'};
	$encoding = $self->{'input_encoding'};
    }

    # Read in file ($text will be in utf8)
    my $text = "";
    $self->read_file ($filename, $encoding, \$text);

    if ($text !~ /\w/) {
	my $outhandle = $self->{'outhandle'};
	print $outhandle "$plugin_name: ERROR: $file contains no text\n" 
	    if $self->{'verbosity'};
	return 0;
    }
    
    
    # Split the text into several smaller segments
    my $split_exp = $self->{'split_exp'};
    my @segments = split(/$split_exp/, $text);
    print $outhandle "SplitPlug found " . (scalar @segments) . " documents in $filename\n" 
	if $self->{'verbosity'};

    # Process each segment in turn
    my ($count, $segment, $segtext, $status, $id);
    $segment = 0;
    $count = 0;
    foreach $segtext (@segments) {
	$segment++;
	
	# create a new document
	my $doc_obj = new doc ($filename, "indexed_doc");
	$doc_obj->set_OIDtype ($processor->{'OIDtype'});
	$doc_obj->add_utf8_metadata($doc_obj->get_top_section(), "Language", $language);
	$doc_obj->add_utf8_metadata($doc_obj->get_top_section(), "Encoding", $encoding);

	# Calculate a "base" document ID.
	if (!defined $id) {
	    $doc_obj->set_OID();
	    $id = $doc_obj->get_OID();
	}
    
	# include any metadata passed in from previous plugins 
	# note that this metadata is associated with the top level section
	$self->extra_metadata ($doc_obj, $doc_obj->get_top_section(), $metadata);

	# do plugin specific processing of doc_obj
	print $outhandle "segment $segment - ";
	$status = $self->process (\$segtext, $pluginfo, $base_dir, $file, $metadata, $doc_obj);
	if (!defined $status) {
	    print $outhandle "WARNING - no plugin could process segment $segment of $file\n" 
		if ($verbosity >= 2);
	    next;
	}
	$count += $status;

	# do any automatic metadata extraction
	$self->auto_extract_metadata ($doc_obj);

	# add an OID
	$self->set_OID($doc_obj, $id, $segment);

	
	# process the document
	$processor->process($doc_obj);
    }

    # Return number of document objects produced
    return $count; 
}

sub set_OID {
    my $self = shift (@_);
    my ($doc_obj, $id, $segment_number) = @_;
    
    $doc_obj->set_OID($id . "s" . $segment_number);
}

1;
