package Dynamic::Loader;
use strict;

require Exporter;
use Carp qw/confess/;
use Env::Path;
use File::Basename;
require Data::Dumper if defined ($ENV{DEBUG});

our ($VERSION, $BINPATH, @ISA, @EXPORT);
$VERSION = '1.03';

=head1 NAME

Dynamic::Loader - call a script without to know where is his location.

=head1 VERSION

Version 0.99

=head1 SYNOPSIS

    The Dynamic::Loader manage the dynamic location of scripts and bundles. 
    Scripts and bundles are packaged in there own directory.
    The bundles and scripts locations are discribed on a named configuration file. 
    The prefix configuration directory can be specified by the $JAVAPERL environnement. 
    The default directory is $HOME/.perljava/conf, but you can specify a custom
    prefix with the $JAVAPERL/conf variable.
    
    A configuration is <name>.conf with this format:
        prefix=<absolute path>
        bin=<relative binary dir>
        lib=<relative library dir>


=head1 DEFAULT SCRIPT AND PARAMS

When C<Dynamic::Loader> is used, you can specify the script name and his options
command:
        perl -S fromjar.pl scriptname.pl --a=... --b=...


=cut

@ISA = qw(Exporter);
@EXPORT=qw($SCRIPTPATH $PATH $PERL5LIB &listScripts &getExecPrefix);
our (
     $SCRIPTPATH,
     $PATH,
     $PERL5LIB,
    );

sub import {
    my $class=shift;
    #@_ contains what could be passed on -MLoader=...; iv ever
    init();
    $class->export_to_level(1, $class, @_) ;
}

=head3 init()

setup libs and bin directories

#fix lib and script path according to what's given

=cut

sub init{
  my $perlJavaHome;
  $perlJavaHome=$ENV{PERLLOADERHOME} || $ENV{JAVAPERL};
  $perlJavaHome="$ENV{HOME}/.perljava" unless defined $perlJavaHome;
  
  #$ENV{PATH}='';
  $PATH = Env::Path->PATH;
  $SCRIPTPATH = Env::Path->SCRIPTPATH;
  $PERL5LIB = Env::Path->PERL5LIB;

  #TODO change that from ENV
  my @modules;
  my %conffiles;
  if($ENV{PERLLOADERMODULES}){
    @modules=split /:/, $ENV{PERLLOADERMODULES};
  }else{
    foreach (<$perlJavaHome/conf/*.conf>){
      open (CONFIGFILE, $_) or next;
      my %entry=();
      while (my $l = <CONFIGFILE>) {
         if ($l =~ /^([^=]+)=(.*)/) {
            my ($key, $val) = ($1, $2);
            if ($key eq "prefix"){
              $conffiles{$val}=\%entry;
              push @modules, $val ;
            }else{
              $entry{$key}=$val;
            }
         }
      }
      close CONFIGFILE;
    }
    
  }
  require Data::Dumper if defined ($ENV{DEBUG});
  printf Data::Dumper::Dumper(\%conffiles)."\n" if defined ($ENV{DEBUG});
  foreach my $pjar (@modules) {
    eval "use lib \"$pjar/$conffiles{$pjar}->{lib}\"";
  }
  #we wish to put the path from the given directory, but in the correct order, and in front of all other.
  foreach my $pjar (reverse @modules) {
    my $bin="$pjar/$conffiles{$pjar}->{bin}";
    $bin=~ s/\/\//\//g;
    $SCRIPTPATH->Prepend($bin) unless $SCRIPTPATH->Contains($bin);
    $PATH->Prepend($bin) unless $PATH->Contains($bin);
    my $lib="$pjar/$conffiles{$pjar}->{lib}";
    $lib=~ s/\/\//\//g;
    $PERL5LIB->Prepend($lib) unless $PERL5LIB->Contains($lib);
  }

}



=head3 Dynamic::Loader::listScripts([patt])

Return a list of commands following a pattern listScripts(), listScripts("*.pl"), listScripts("phe*")

The commands returned here are returned with a relative path to the package they belong to

=cut

sub listScripts{
  require File::Find::Rule;
  my $patt=shift || '*';

  my @tmp;
  foreach my $p($SCRIPTPATH->List){
    foreach ( File::Find::Rule->file()
	      ->name( $patt )
	      ->in( $p )){
      next if /\/\.svn\//;
      s/^$p([\/\\])?//;
      push @tmp, $_;
    }
  }
  return @tmp;
}


=head3 Dynamic::Loader::getScript(relative_path)

Return the complete path to the given scripts.

Contrary to listScripts(), this command must return exactly one script and will die if not;

=cut

sub getScript{
  my $relPath=shift or confess "no relative path given";
  my @tmp;
  foreach ($SCRIPTPATH->List){
    my $full="$_/$relPath";
    push  @tmp, $full if -f $full;
  }
  confess "no script found for [$relPath]" unless @tmp;
  confess "multiple scripts found (@tmp) for [$relPath]" if @tmp>1;
  return $tmp[0];
}

=head3 Dynamic::Loader::getLibs(relative_path)

Return the complete path to the given scripts + the complete perl prefix with perl5libs.

=cut


sub getLongScript{
  my $relPath=shift or confess "no relative path given";
  my $path=getScript($relPath);
  my $p5l="perl ";
  foreach ($PERL5LIB->List){
  	$p5l.="-I$_ ";
  }
  
  printf "---> $p5l$path \n" if defined ($ENV{DEBUG});
  return "$p5l$path";
}

=head3  Dynamic::Loader::getExecPrefix()

return an array to prepend to execution (perl, includes etc...)

=cut

sub getExecPrefix{
  return ($^X);
}

=head3 Dynamic::Loader::whence([pat])

return a list of commands with the full path corresponding to a pattern. Think of ls completion in bash

=cut

sub whence{
  return $SCRIPTPATH->Whence($_[0] or "*");
}

=head1 AUTHOR

Olivier Evalet, C<< <olivier.evalet at genebio.com> >>
Alexandre Masselo C<< <alex at genebio.com> >>

=head1 BUGS

Please report any bugs or feature requests to C<bug-dynamic-loader at rt.cpan.org>, or through
the web interface at L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Dynamic-Loader>.  I will be notified, and then you'll
automatically be notified of progress on your bug as I make changes.




=head1 SUPPORT

You can find documentation for this module with the perldoc command.

    perldoc Dynamic::Loader


You can also look for information at:

=over 4

=item * RT: CPAN's request tracker

L<http://rt.cpan.org/NoAuth/Bugs.html?Dist=Dynamic-Loader>

=item * AnnoCPAN: Annotated CPAN documentation

L<http://annocpan.org/dist/Dynamic-Loader>

=item * CPAN Ratings

L<http://cpanratings.perl.org/d/Dynamic-Loader>

=item * Search CPAN

L<http://search.cpan.org/dist/Dynamic-Loader>

=back


=head1 ACKNOWLEDGEMENTS


=head1 COPYRIGHT & LICENSE

Copyright 2008 Olivier Evalet, Alexandre Masselot all rights reserved.

This program is free software; you can redistribute it and/or modify it
under the same terms as Perl itself.


=cut




1; # End of Dynamic::Loader
