###########################################################################
#
# MP3Plug.pm -- Plugin for MP3 files (MPEG audio layer 3).
#
# A component of the Greenstone digital library software from the New
# Zealand Digital Library Project at the University of Waikato, New
# Zealand.
#
# Copyright (C) 2001 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 MP3Plug;

use UnknownPlug;

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

use MP3::Info;

require giget;

sub BEGIN {
    @MP3Plug::ISA = ('UnknownPlug');
}

my $arguments =
    [ { 'name' => "process_exp",
	'desc' => "{BasPlug.process_exp}",
	'type' => "string",
	'deft' => &get_default_process_exp(),
	'reqd' => "no" },
      { 'name' => "assoc_images",
        'desc' => "{MP3Plug.assoc_images}",
        'type' => "flag",
        'deft' => "",
        'reqd' => "no" },
      { 'name' => "applet_metadata",
	'desc' => "{MP3Plug.applet_metadata}",
	'type' => "flag",
	'deft' => "" },
      { 'name' => "metadata_fields",
	'desc' => "{MP3Plug.metadata_fields}",
	'type' => "string",
	'deft' => "Title,Artist,Genre" } ];

my $options = { 'name'     => "MP3Plug",
		'desc'     => "{MP3Plug.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 = new UnknownPlug($pluginlist, $inputargs, $hashArgOptLists);

    return bless $self, $class;
}

sub get_default_process_exp {
    return q^(?i)\.mp3$^;
}

sub gen_mp3applet {

    my ($mp3_filename) = @_;

    my $applet_html = '
<OBJECT classid="clsid:8AD9C840-044E-11D1-B3E9-00805F499D93"
        WIDTH = "59"
        HEIGHT = "32"
        codebase="http://java.sun.com/products/plugin/1.3/jinstall-13-win32.cab#Version=1,3,0,0">
<PARAM NAME = CODE VALUE = "javazoom.jlGui.TinyPlayer" >
<PARAM NAME = ARCHIVE VALUE = "_httpcollection_/tinyplayer.jar,_httpcollection_/jl10.jar" >
<PARAM NAME="type" VALUE="application/x-java-applet;version=1.3">
<PARAM NAME="scriptable" VALUE="false">
<PARAM NAME = "skin" VALUE ="_httpcollection_/skins/Digitalized">
<PARAM NAME = "autoplay" VALUE ="yes">
<PARAM NAME = "bgcolor" VALUE ="638182">
<PARAM NAME = "audioURL" VALUE ="MP3FILENAME">
<COMMENT>
<EMBED type="application/x-java-applet;version=1.3"
       CODE = "javazoom.jlGui.TinyPlayer"
       ARCHIVE = "_httpcollection_/tinyplayer.jar,_httpcollection_/jl10.jar"
       WIDTH = "59"
       HEIGHT = "32"
       skin = "_httpcollection_/skins/Digitalized"
       autoplay = "yes"
       bgcolor = "638182"
       audioURL = "MP3FILENAME"
       scriptable=false
       pluginspage="http://java.sun.com/products/plugin/1.3/plugin-install.html">
<NOEMBED>
</COMMENT>
</NOEMBED></EMBED>
</OBJECT>
';

    $applet_html =~ s/MP3FILENAME/$mp3_filename/g;

    return $applet_html;
}



# Associate the mp3 file with the new document

sub associate_mp3_file {
    my $self = shift (@_);
    my $filename = shift (@_);   # filename with full path
    my $file = shift (@_);       # filename without path
    my $doc_obj = shift (@_);
    
    my $verbosity = $self->{'verbosity'};
    my $outhandle = $self->{'outhandle'};

    # check the filename is okay
    return 0 if ($file eq "" || $filename eq "");

    # Add the file metadata
    my $assoc_url = $file;
#    $assoc_url =~ s/ /%20/g; # probably need to do more escaping than this!!
    $assoc_url =~ s/ /_/g; # workaround for now
    my $dst_file = $file;
    $dst_file =~ s/ /_/g;

    # Add the file as an associated file ...
    my $section = $doc_obj->get_top_section();
    my $mime_type = $self->{'mime_type'} || "audio/mp3";
    my $assoc_field = $self->{'assoc_field'} || "mp3";
    my $assoc_name = $file;
    $assoc_name =~ s/\.mp3$//;

    $doc_obj->associate_file($filename, $dst_file, $mime_type, $section);
    $doc_obj->add_metadata ($section, "Source", $file);
    $doc_obj->add_metadata ($section, $assoc_field, $assoc_name);
    $doc_obj->add_metadata ($section, "srcurl", $assoc_url);

    my $mp3_info = get_mp3info($filename);
    my $mp3_tags = get_mp3tag($filename);

    my $metadata_fields = $self->{'metadata_fields'};

    if ($metadata_fields eq "*") {
	# Locate all info and tag metadata

	foreach my $ki ( keys %$mp3_info ) {
	    my $mp3_metavalue = $mp3_info->{$ki};

	    if ($mp3_metavalue !~ m/^\s*$/s) {
		my $mp3_metaname = "mp3:".lc($ki);
		$doc_obj->add_metadata ($section, $mp3_metaname, $mp3_metavalue);
	    }
	}

	foreach my $kt ( keys %$mp3_tags ) {
	    my $mp3_metavalue = $mp3_tags->{$kt};
	    
	    if ($mp3_metavalue !~ m/^\s*$/s) {
		my $kt_len = length($kt);
		my $kt_initial_cap = uc(substr($kt,0,1)).lc(substr($kt,1,$kt_len-1));
		my $mp3_metaname = "mp3:".$kt_initial_cap;
		
		$doc_obj->add_metadata ($section, $mp3_metaname, $mp3_metavalue);
	    }
	}
    }
    else {

	# Restrict metadata to that specifically given
	foreach my $field (split /,/, $metadata_fields) {

	    # check info
	    if (defined $mp3_info->{$field}) {

		my $mp3i_metavalue = $mp3_info->{$field};
		
		if ($mp3i_metavalue !~ m/^\s*$/s) {
		    my $mp3i_metaname = "mp3:".lc($field);
		    $doc_obj->add_metadata ($section, $mp3i_metaname, $mp3i_metavalue);
		}
	    }

	    # check tags
	    if (defined $mp3_tags->{uc($field)}) {

		my $mp3t_metavalue = $mp3_tags->{uc($field)};
		
		if ($mp3t_metavalue !~ m/^\s*$/s) {
		    my $mp3t_metaname = "mp3:".$field;
		    
		    $doc_obj->add_metadata ($section, $mp3t_metaname, $mp3t_metavalue);
		}
	    }
	    
	}
    }

    $doc_obj->add_metadata ($section, "FileFormat", "MP3");
    
    $doc_obj->add_metadata ($section, "srclink", 
			    "<a href=\"_httpprefix_/collect/[collection]/index/assoc/[assocfilepath]/[srcurl]\">");
    $doc_obj->add_metadata ($section, "srcicon", "_iconmp3_");
    $doc_obj->add_metadata ($section, "/srclink", "</a>");

    my $applet_metadata = $self->{'applet_metadata'};
    if (defined $applet_metadata && $applet_metadata ) {
	my $applet_html 
	    = gen_mp3applet("_httpprefix_/collect/[collection]/index/assoc/[assocfilepath]/[srcurl]");
	$doc_obj->add_metadata ($section, "mp3applet", $applet_html);
    }

    my $assoc_images = $self->{'assoc_images'};
    if (defined $assoc_images && $assoc_images) {
	my @search_terms = ();

	my $title  = $mp3_tags->{'TITLE'};
	my $artist = $mp3_tags->{'ARTIST'};

	if (defined $title && $title ne "") {

	    push(@search_terms,$title);

	    if (defined $artist && $artist ne "") {
		push(@search_terms,$artist);
	    }
	}
	else {
	    push(@search_terms,$assoc_name);
	}

	push(@search_terms,"song");

	my $output_dir = $filename;
	$output_dir =~ s/\.\w+$//;

	my ($imgref_urls) = giget(\@search_terms,$output_dir);

	my $gi_base = gi_url_base();
	my $gi_query_url = gi_query_url(\@search_terms);

	$doc_obj->add_metadata ($section, "giquery", "<a href=\"$gi_base$gi_query_url\" target=giwindow>");
	$doc_obj->add_metadata ($section, "/giquery", "</a>");

	for (my $i=1; $i<=2; $i++) {
	    my $img_filename = "$output_dir/img_$i.jpg";
	    my $dst_file = "img_$i.jpg";

	    if (-e $img_filename) {
		$doc_obj->associate_file($img_filename, $dst_file, "image/jpeg", $section);

		my $srcurl = "src=\"_httpprefix_/collect/[collection]/index/assoc/[assocfilepath]/$dst_file\"";

		$doc_obj->add_metadata ($section, "img$i", 
					"<img $srcurl>");
		$doc_obj->add_metadata ($section, "smallimg$i", 
					"<img $srcurl width=100>");

		my $imgref_url = $imgref_urls->[$i-1];

		$doc_obj->add_metadata ($section, "imgref$i", "<a href=\"$imgref_url\" target=giwindow>");
		$doc_obj->add_metadata ($section, "/imgref$i", "</a>");
	    }

	}


    }

    return 1;
}



# The MP3Plug read() function is based on UnknownPlug read().  This
# function does all the right things to make general options work for
# a given plugin. 

my $mp3_doc_count = 0; ## is this used anywhere now !!???

sub read {
    my $self = shift (@_);
    my ($pluginfo, $base_dir, $file, $metadata, $processor, $maxdocs, $total_count, $gli) = @_;

    my $outhandle = $self->{'outhandle'};

    #check for associate_ext, blocking etc
    my ($block_status,$filename) = $self->read_block(@_);    
    return $block_status if ((!defined $block_status) || ($block_status==0));

    print STDERR "<Processing n='$file' p='MP3Plug'>\n" if ($gli);
    print $outhandle "MP3Plug processing \"$filename\"\n"
	    if $self->{'verbosity'} > 1;

    #if there's a leading directory name, eat it...
    $file =~ s/^.*[\/\\]//;
    
    # create a new document
    my $doc_obj = new doc ($filename, "indexed_doc");
    $mp3_doc_count++;
    
##    $doc_obj->set_OIDtype ($processor->{'OIDtype'});  
    if ($processor->{'OIDtype'} =~ /^(assigned|dirname)$/) {
	$doc_obj->set_OIDtype ($processor->{'OIDtype'}, $processor->{'OIDmetadata'});
    }
    else {
	$doc_obj->set_OIDtype ("incremental");    # this is done to avoid hashing content of file
    }
    $doc_obj->add_utf8_metadata($doc_obj->get_top_section(), "Plugin", "$self->{'plugin_type'}");
    $doc_obj->add_utf8_metadata($doc_obj->get_top_section(), "FileSize", (-s $filename));

    # associate the file with the document
    if (associate_mp3_file($self, $filename, $file, $doc_obj) != 1)
    {
	print "MP3Plug: couldn't process \"$filename\"\n";
	return 0;
    }

    #create an empty text string so we don't break downstream plugins 
    my $text = &gsprintf::lookup_string("{BasPlug.dummy_text}",1);
    if ($self->{'assoc_images'}) {
	$text .= "[img1]<br>";
	$text .= "[img2]<br>";
    }
    # include any metadata passed in from previous plugins 
    my $section = $doc_obj->get_top_section();
    $self->extra_metadata ($doc_obj, $section, $metadata);

    $self->title_fallback($doc_obj,$section,$file);

    # do plugin specific processing of doc_obj
    return undef unless defined ($self->process (\$text, $pluginfo, $base_dir, 
						 $file, $metadata, $doc_obj));

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

    # add an OID
    $doc_obj->set_OID();
    $doc_obj->add_utf8_text($section, $text);

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

    $self->{'num_processed'} ++;
    return 1;
}


sub title_fallback
{
    my $self = shift (@_);
    my ($doc_obj,$section,$file) = @_;

    if (!defined $doc_obj->get_metadata_element ($section, "Title")) {
	my $mp3_title = $doc_obj->get_metadata_element ($section, "mp3:Title");
	if (defined $mp3_title) {
	    $doc_obj->add_metadata ($section, "Title", $mp3_title);
	}
	else {
	    &BasPlug::title_fallback($self, $doc_obj, $section, $file);
	}
    }
}


1;











