use Config;
use File::Basename qw(basename dirname);
chdir(dirname($0));
($file = basename($0)) =~ s/\.PL$//;
$file =~ s/\.pl$//
        if ($Config{'osname'} eq 'VMS' or
            $Config{'osname'} eq 'OS2');  # "case-forgiving"
open OUT,">$file" or die "Can't create $file: $!";
chmod(0755, $file);
print "Extracting $file (with variable substitutions)\n";

print OUT <<"!GROK!THIS!";
$Config{'startperl'} -w
    eval 'exec perl -S \$0 "\$@"'
        if 0;

!GROK!THIS!

print OUT <<'!NO!SUBS!';

# refer to the bottom of this file for documentation
BEGIN {
	require File::Spec;
	# update search paths
	if ( not $ENV{'CIPRES_ROOT'} ) {
		print "Environment variable \$CIPRES_ROOT not set.\n";
		pod2usage( 1 );
	}
	my $libpath = File::Spec->catdir(
		$ENV{'CIPRES_ROOT'},
		'lib/perl/lib'
	);
	push @INC, $libpath;
}

use Config;
use strict;
use warnings;
use Getopt::Long;
use Cipres::IDL;
use IO::File;
use Pod::Usage;

my $rev = '$Rev: 3470 $';
$rev =~ s/^\D+(\d{4})\D+$/$1/;
our $VERSION='0.01' . '_' . $rev;

################################################################################
# global vars
my ( 
	@I, 
	$M, 
	$CipresImpl, 
	$CipresIOR, 
	$ORBport, 
	$BOAclients, 
	$CipresNoNs, 
	$Handle, 
	$logfile 
);

################################################################################
# get command line args
GetOptions( 
    'I=s'          => \@I, 
    'CipresIOR=s'  => \$CipresIOR,
    'CipresImpl=s' => \$CipresImpl,
    'M=s'          => \$M,
    'help|h|?'     => sub { &version; pod2usage(2) },
    'man'          => sub { pod2usage( '-exitstatus' => 0, '-verbose' => 2 ) },
    'ORBport=i'    => \$ORBport,
    'BOAclients=i' => \$BOAclients,
    'version|v'    => sub { &version; exit 0 },
    'CipresNoNs'   => \$CipresNoNs,
    'logfile=s'    => \$logfile,
);

################################################################################
# create log handle
if ( $logfile ) {
	$Handle = IO::File->new;
	$Handle->open(">> $logfile");
}
else {
	$Handle = \*STDOUT;
}
$Handle->autoflush( 1 );

################################################################################
# print header
&version;

################################################################################
# check command line args
$Handle->print('Checking command line arguments..................');
die "\nThe -CipresImpl flag needs to be used. Fatal error" if not $CipresImpl;
die "No user class (-M) supplied. Fatal error" if not $M;
$Handle->print("ok\n");

################################################################################
# Adding command line supplied paths to @INC
$Handle->print('Updating search paths............................');
my @paths;
for ( @I ) {
    if ( -d $_ ) {
        push @paths, $_;    
    }
    else {
        die "\nDirectory \"$_\" not found or not readable. Fatal error";
    }
}
$Handle->print("ok\n");

################################################################################
# populate search path for non-par "use lib LIST" construct
$Handle->print('Inspecting updated search paths..................');
eval { push @INC, @paths };
die "\nCouldn't update search paths: $@" if $@;
$Handle->print("ok\n\t\@INC now is:\n");
$Handle->print("\t\t", $_, "\n") for @INC;

################################################################################
# load base class
$Handle->print('Attempting to load service base class............');
my $base = 'Cipres::CorbaService';
eval "require $base";
die "\nCouldn't load \"$base\" base class: $@" if $@;
$Handle->print("ok\n");

################################################################################
# load user supplied service class
$Handle->print('Loading user supplied implementation class.......');
eval "require $M";
die "\nCan't instantiate user supplied class (-M) $M. Fatal error: $@" if $@;
$Handle->print("ok\n");

################################################################################
# implementation wrapper class
$CipresImpl = $base . '::' . $CipresImpl;

################################################################################
# run
$Handle->print("---------------------------------------------------\n\n");
$Handle->print("Starting \"$CipresImpl\" implemented by \"$M\"\n\n");
my ( $ior, $obj ) = $CipresImpl->new( 
    '-impl'      => $M,
    '-argv'      => \@ARGV,
    '-port'      => $ORBport,
    '-clients'   => $BOAclients,
    '-loghandle' => $Handle,
);  

################################################################################
# write IOR to file
$Handle->print("\n---------------------- IOR ------------------------\n");
$Handle->print( $ior );
$Handle->print("\n---------------------------------------------------\n\n");
if ( $CipresIOR ) {
    my $fh = IO::File->new;
    $fh->open("> $CipresIOR") or die $!;
    $fh->autoflush( 1 );
    $fh->print(  $ior );
    $fh->print(  "\n" );
    $fh->print(  $$   );
    $fh->print(  "\n" );
    $fh->close;
    $Handle->print("Printed IOR to file $CipresIOR\n\n");
}
$obj->RUN;

################################################################################
sub version {
	print( "$0 v.$VERSION\n" );
}

__END__

=head1 NAME

xixi - hosts cipres service implementation classes

=head1 SYNOPSIS

 xixi -CipresImpl <service name> -M <implementation module> [-I <path>]
      [-CipresIOR <file name>] [-logfile <file name>] [-help|-h|-?] 
      [-man] [-version|-v] [--] [<implementation args>]

=head1 OPTIONS

=head2 Required wrapper arguments

=over

=item B<-CipresImpl> C<service name>

Required. "service name" is a CIPRES service interface (e.g. TreeRefine).
                
=item B<-M> C<package name>

Required. "package name" is a perl5 package name (e.g. My::TreeRefine).

=back
        
=head2 Optional wrapper arguments

=over

=item B<-I> C<path>

Optional. "path" is a perl5 search path to add to @INC. Can be supplied multiple
times.
                
=item B<-CipresIOR> C<file name>

Optional. "file name" is a file to write the IOR string to.

=item B<-logfile> C<file name>

Optional. Redirects logging messages to "file name".
                
=item B<-help>, B<-h>, B<-?>

Print brief help message and quit.

=item B<-man>

Print documentation and quit.
            
=item B<-version>, B<-v>

Print version number and quit.

=back
        
=head2 Optional ORB arguments

=over

=item B<-ORBport> C<port>

This server-side option sets the port that the server will listen on. Without 
it, a system-allocated port is used. 
                               
=item B<-BOAclients> C<max-connects>

Like -ORBport, this is really a BOA option. It limits the number of connections 
the server will maintain.

=back
        
=head2 Optional implementation arguments

=over

=item B<--> C<implementation args>

Optional. All arguments after the first double dash ('--') are passed verbatim
(as an array) to the implementation module's "new" constructor. 

To pass named arguments, simply space separate them, i.e., if the constructor
accepts arguments like so:

 my $CipresImpl = Impl::TreeRefine->new(
 	'-arg1' => 'val1',
 );

These would be specified as:
                
 xixi -CipresImpl TreeRefine -M Impl::TreeRefine -- -arg1 val1

=back

!NO!SUBS!
