
=head1 NAME

Palm::Progect::VersionDelegator - Delegate to specific Progect db driver based on version

=head1 SYNOPSIS

    package Palm::Progect::Record;
    use vars qw(@ISA);

    @ISA = qw(Palm::Progect::Record);

    1;

=head1 DESCRIPTION

Delegate to specific database driver based on database version.  If
version is not specified, then it will delegate to the database driver
with the highest number.

For instance to create a version 0.18 Record, the user can do the following:

    my $record = Palm::Progect::Record->new(
        raw_record => $some_raw_data,
        version    => 18,
    );

Behind the scenes, this call will be translated into the equivalent of:

    require 'Palm/Progect/DB_18/Record.pm';
    my $record = Palm::Progect::DB_18::Record->new(
        raw_record => $some_raw_data,
    );

=cut

package Palm::Progect::VersionDelegator;

use strict;
use 5.004;
use File::Spec;
use Carp;

sub new {
    my $proto      = shift;
    my $this_class = ref $proto || $proto;

    my @base_class  = split /::/, $this_class; # e.g. ('Palm', 'Progect')
    my $module_name = pop @base_class;         # e.g. 'Record'

    my %args = @_;

    my $version = delete $args{'version'} || 0;

    my $version_class = '';
    if ($version > 0) {
        $version_class = 'DB_' . $version;
    }
    else {
        # Latest version was requested.
        $version_class = 'DB_' . _latest_version(File::Spec->join(@base_class));
    }

    my $module_path  = File::Spec->join(@base_class,$version_class, $module_name . '.pm');
    my $module_class = join '::', @base_class, $version_class, $module_name;

    require $module_path;

    return $module_class->new(%args);
}

# Cache the latest version to avoid repeatedly searching
# through the filesystem

# Find latest version of module
# find directories matching DB_yy
# and pick the one where yy is the greatest

my %Latest_Version;
sub _latest_version {
    my $base_class_path = shift;

    if (! exists $Latest_Version{$base_class_path}) {


        local *DIR;

        my $max_version          = 0;
        my $max_version_filename = '';

        foreach my $inc (@INC) {
            my $path = File::Spec->join($inc, $base_class_path);

            next unless -d $path;

            if (opendir DIR, $path) {
                my @subdirs = readdir(DIR);
                close DIR;

                foreach my $subdir (@subdirs) {
                    next unless -d File::Spec->join($path, $subdir);
                    next unless $subdir =~ /^DB_(\d+)$/;

                    my $subdir_version = $1;

                    next unless $subdir_version > $max_version;

                    $max_version          = $subdir_version;
                }
            }
        }
        $Latest_Version{$base_class_path} = $max_version;
    }

    return $Latest_Version{$base_class_path};
}

1;

__END__

=head1 AUTHOR

Michael Graham E<lt>mag-perl@occamstoothbrush.comE<gt>

Copyright (C) 2002 Michael Graham.  All rights reserved.
This program is free software.  You can use, modify,
and distribute it under the same terms as Perl itself.

The latest version of this module can be found on http://www.occamstoothbrush.com/perl/

=head1 SEE ALSO

C<progconv>

L<Palm::PDB(3)>

http://progect.sourceforge.net/

=cut

