/usr/local/CPAN/Video-PlaybackMachine/Video/PlaybackMachine/FillProducer/Chooser.pm


package Video::PlaybackMachine::FillProducer::Chooser;

####
#### Video::PlaybackMachine::FillProducer::Chooser
####
#### $Revision: 357 $
####
#### Picks content in random or quasi-random order. Does not pick
#### anything twice until all have been chosen. Will preferentially display
#### new content.
####

use strict;
use warnings;
use IO::Dir;
use File::stat;
use Log::Log4perl;

############################# Class Constants ###########################

############################## Class Methods ############################

##
## new()
##
## Arguments: (hash)
##   DIRECTORY: string -- Directory from which we should choose things
##   FILTER: regexp -- Regular expression matching things we should return
##
sub new
{
	my $type = shift;
	my (%in) = @_;
	my $self = {
		DIRECTORY => $in{DIRECTORY},
		FILTER    => $in{FILTER},
		SEEN      => {},
		ITEMS     => [],
		LOGGER    =>
		  Log::Log4perl->get_logger('Video::PlaybackMachine::Filler::Chooser'),
	};
	bless $self, $type;
}

############################# Object Methods ##############################

##
## choose()
##
## Returns an item from a randomly-selected list. Items which have
## appeared during program run are played sooner.
##
sub choose
{
	my $self = shift;

	$self->_reload_items();

	return shift @{ $self->{'ITEMS'} };

}

##
## is_available()
##
## Returns true if calling choose() would return an item.
##
sub is_available
{
	my $self = shift;

	$self->_reload_items();
	return @{ $self->{'ITEMS'} } > 0;
}

##
## Loads any new items (i.e. files)
##
sub _reload_items
{
	my $self      = shift;
	my @new_items = $self->_get_new_items();
	$self->{'ITEMS'} = [ @new_items, @{ $self->{'ITEMS'} } ];

	if ( @{ $self->{'ITEMS'} } == 0 )
	{
		$self->{'SEEN'}  = {};
		$self->{'ITEMS'} = [ $self->_get_new_items() ];
	}

	return 1;
}

sub _get_new_items
{
	my $self = shift;

	-d $self->{'DIRECTORY'}
	  or do
	{
		$self->{'LOGGER'}
		  ->warn("Directory '$self->{'DIRECTORY'}' does not exist");
		return;
	};
	my $dh = IO::Dir->new( $self->{'DIRECTORY'} )
	  or die "Couldn't open directory $self->{'DIRECTORY'}: $!; stopped";
	my @files = ();
	while ( my $file = $dh->read() )
	{
		$file =~ /\.^/ and next;
		if ( $self->{'FILTER'} )
		{
			$file =~ /$self->{'FILTER'}/ or next;
		}
		my $full_file = "$self->{'DIRECTORY'}/$file";
		-f $full_file or next;
		$self->{'SEEN'}{$full_file}++ and next;
		push( @files, $full_file );
	}

	return $self->_random_sort(@files);
}

sub _random_sort
{
	my $self = shift;
	my (@items) = @_;

	my %st = ();
	my $getval = sub {
		my ($x) = @_;

		if ( !exists $st{$x} )
		{
			$st{$x} = rand();
		}
		return $st{$x};
	};
	return sort { $getval->($a) <=> $getval->($b) } @items;

}

1;