# Blosxom Plugin: storyfilter
# Author: Mike Downey
# Version: 0.23

package storyfilter; # Needs to be loaded after the 'meta' plugin

# usage: add keyword=xyz to the query string to display any stories
# which contain that keyword in in the meta-keywords variable.
# Keywords are saved to a disk cache as and when they are viewed.
# if $categoryiskeyword == 1 then /keyword works as well
# ?refresh=y refreshes keyword cache for any currently displayed stories
# (same as using $refresh = 1)

# using /category stops $breadcrumbs and $menu from showing the proper subcategories
# because of the way it clears the $path variable

# -------- Configure variables --------

my $keywordfile = "$blosxom::plugin_state_dir/keyword.cache";

my $categoryiskeyword = 0;	# allows /keyword as well as ?keyword=
my $autokeywords = 1;		# picks keywords from categories
my $refresh = 1;		# refreshes any entries as they are displayed

# -------------------------------------

use CGI qw/:standard/;

my %keyword_stories;
my $keywordfilter;
my $filechanged = 0;
my $localkeywords;

$keywordlinks;

sub start {

	# Read in the keyword cache
	open KWF, $keywordfile;
	while(my $line=<KWF>){
		chomp $line;
		my ($fn,$kw) = split ("#",$line);
		$keyword_stories{$fn}=$kw;
	}
	close KWF;

	# get the keyword to filter on from CGI
	$keywordfilter = CGI::param("keyword");


	# if the path is a single word (no subcategories), doesn't contain a . (ie not a story)
	# and no keyword is selected then use that as a keyword
	# This bit breaks the 'menu' plugin and stops it showing the correct subcategories
	if (($blosxom::path_info !~ m#/|\.#) && !$keywordfilter && $categoryiskeyword){
		$keywordfilter=$blosxom::path_info;
		$blosxom::path_info=""; 		# Naughty! these variables should be read-only!
	}

	# decides whether we refresh the cache for visible stories
	$refresh ||= (CGI::param("refresh") eq "y");

	1;
}

sub filter {
	my ($pkg, $files_ref) = @_;
	my $storypath,@pathelements;

	# Rebuild entire cache file if required
	if ( (CGI::param("refresh") eq "full") or !(-e $keywordfile) ){
		foreach $storyfn (keys %$files_ref){
			my $keywordlist = "";

			if ($autokeywords){
				# now need to extract the path from the full pathname
				($storypath = $storyfn) =~ s/$blosxom::datadir//;
				@pathelements = split("/",$storypath);
				delete $pathelements[-1];
				# and add each part of the path to the keywords file
				foreach $storypath (@pathelements){
					$keywordlist .= $storypath.",";
				}
			}
			# now for the tricky bit: extracting the keywords from the meta tag
			open STF, $storyfn;
			my $line = <STF>; # skip the first line
			while ($line = <STF>){
				chomp $line;
				if (substr($line,0,5) ne "meta-")
					{last;} # skip to next story if no meta.
				if (substr($line,0,14) eq "meta-keywords:"){
					$keywordlist .= (split(": ",$line))[1];
				}

			}
			close STF;
			$keyword_stories{$storyfn}=$keywordlist;
		}
		$filechanged = 1;	# re-write file at end
	}

	if ($keywordfilter){
		my $storyfn;

		# if we want to filter on a keyword, go ahead and do it
		foreach $storyfn (keys %$files_ref){
			if (!($keyword_stories{$storyfn} =~ /$keywordfilter/))
				{ delete $files_ref->{$storyfn}; }
		}
	}

	1;
}

# for each story, take the keywords and add to the cache array
sub story {

	my($pkg, $path, $filename, $story_ref, $title_ref, $body_ref) = @_;

	if (!$filename)			# There seems to be a bug somewhere where deleting from
		{			# the $files_ref in filter may cause the final post to be
		$$story_ref = '';	# duplicated but only in the top level category and with
		return 1;		# a unix date of 0 (1-1-1970). This work-around prevents it.
		}
	
	# Add the path elements to the meta::keywords
	if ($blosxom::path && $autokeywords)
		{ ($localkeywords = $meta::keywords.$blosxom::path) =~ s#/#,#g; }

	# Add the keywords to the cache array (only if we need to)
	if (defined $localkeywords){
		my $storyfilename = "$blosxom::datadir$path/$filename.txt";
		if ((!$keyword_stories{$storyfilename}) or $refresh) {
			$keyword_stories{$storyfilename}=$localkeywords;
			$filechanged = 1;
		}
	}

	# Build up the keyword links
	my @words = split (",",$localkeywords);
	my %wordlinks, $word;
	foreach $word (@words){
		if ($word) # ignore blank lines
			{$wordlinks{$word} = "<a href=\"$blosxom::url?keyword=$word\">$word</a>";}
	}
	if ($localkeywords) 
		{$keywordlinks = "Keywords: ".join(" ", values %wordlinks);}

	$localkeywords="";
	
	1;
}


sub last {
	my $fn,$kw;
	if ($filechanged) {
		open KWF,"> $keywordfile";
		foreach $kw (keys %keyword_stories)
			{print KWF "$kw#$keyword_stories{$kw}\n";}
		close KWF;
	}
	1;
}

1;

__END__

