#!/usr/bin/perl -w

BEGIN 
{
  use strict;
  use Getopt::Long;
  use IO::Dir;
  use File::Copy;

  sub get_yesno (  );
  sub help      (;$$);

  $| = 1;  # flush stdout
}


#####################################################################
#
# defaults
#
my $GEN_ROOT = "$ENV{SAGA_LOCATION}/share/saga/generator/";
my $TARGET   = `pwd`;
my $TYPE     = "";
my $PREFIX   = "";
my $HELP     = 0;

chomp ($TARGET);
$TARGET .= "/target";


#####################################################################
#
# get/check parameters
#
GetOptions ("dir=s"    => \$TARGET,
            "type=s"   => \$TYPE,
            "prefix=s" => \$PREFIX,
            "help"     => \$HELP)
   || exit;

if ( $HELP )
{
  help ();
}

if ( ! -d $GEN_ROOT && exists $ENV{SAGA_ROOT} )
{ 
  $GEN_ROOT = "$ENV{SAGA_ROOT}/adaptors/generator/";
}

if ( ! -d $GEN_ROOT )
{ 
  chomp ($GEN_ROOT = `pwd`);
  $GEN_ROOT .= "/../generator/skeleton/";
}

if ( ! -d $GEN_ROOT )
{
  help ("Cannot find generator support files in $GEN_ROOT.");
}

if ( $TYPE !~ /^(context|advert|file|job|replica|rpc|stream)$/io )
{
  help ("Unknown type $TYPE\n" .
        "Known types are: context, advert, file, job, replica, rpc, stream");
}


if ( $PREFIX eq "" )
{
  help ("No prefix specified.\n" .
        "Prefix should be some kind of adaptor class,\n" .
        "e.g. 'globus', 'unicore', 'posix' etc.");
}

print "\n";

$TYPE      = uc ($TYPE  );
$PREFIX    = uc ($PREFIX);

my $type   = lc ($TYPE  );
my $prefix = lc ($PREFIX);

if ( $type =~ /[^0-9a-z_]/io )
{
  die "'type' can contain only alphanumerics and underscore ($type)\n\n";
}

if ( $prefix =~ /[^0-9a-z_]/io )
{
  die "'prefix' can contain only alphanumerics and underscore ($prefix)\n\n";
}


#####################################################################
#
# determine what to do, and start to create new adaptor tree
#

my $tgt = "$TARGET/$prefix/$prefix\_$type";

print <<EOT;

  prefix:            $prefix
  type:              $type
  directory:         $tgt

EOT

if ( ! -d $TARGET )
{
  system ("mkdir -p $TARGET") == 0 or
  die "Cannot create target dir $TARGET: $!\n";
}


if ( -d $tgt )
{
  warn "Target directory $tgt exists.  Replace?\n";

  unless ( get_yesno () )
  {
    die "abort\n";
  }
  print "\n";

  system ("rm -rf $tgt") == 0
    or die "Cannot clean old target directory: $!\n";
}

system ("mkdir -p $tgt") == 0 
       or die "Cannot create target directory: $!\n";

print "  copying files:     ...\n";
system ("cp $GEN_ROOT/$type/*                             $tgt");
system ("cp $GEN_ROOT/###prefix###_###type###_adaptor.ini $tgt");


#####################################################################
#
# for the new tree: rename all files with templated name
#
my $d = IO::Dir->new ($tgt);

unless ( defined $d ) 
{
  die "Creation of adaptor faild: copy failed\n";
}

my @files = $d->read ();

$d->close ();

# ignore './' and '../'
@files = grep (!/^\.+$/, @files);

my @cleanfiles = ();

print "  fixing file names: .";
foreach my $file ( @files )
{
  my $orig = $file;

  $file =~ s/###PREFIX###/$PREFIX/g;
  $file =~ s/###TYPE###/$TYPE/g;

  $file =~ s/###prefix###/$prefix/g;
  $file =~ s/###type###/$type/g;

  if ( $orig ne $file )
  {
    print ".";
    move ("$tgt/$orig", "$tgt/$file");
  }

  push (@cleanfiles, $file);
}
print "\n";

#####################################################################
#
# for the new tree: search and replace templatized file contents
#
print "  fixing files:      .";
foreach my $file ( @cleanfiles )
{
  my $IN  = "$tgt/$file";
  my $OUT = "$tgt/$file.tmp";

  $in  = new IO::File ("< $IN")  || die "Cannot open $IN:  $!\n";
  $out = new IO::File ("> $OUT") || die "Cannot open $OUT: $!\n";;

  while ( <$in> )
  {
    my $line = $_;
    
    $line =~ s/###PREFIX###/$PREFIX/g;
    $line =~ s/###TYPE###/$TYPE/g;

    $line =~ s/###prefix###/$prefix/g;
    $line =~ s/###type###/$type/g;

    # $line = reverse ($line);

    $out->print ($line);
  }

  move ($OUT, $IN);
  print ".";
}
print "\n";

#####################################################################
#
# done
#
print <<EOT;

  You can now cd to $tgt, 
  and run 'make; make install'.  

  Note that you need to set SAGA_LOCATION before,
  and point it to your SAGA installation tree.

EOT


#####################################################################
#
# TODO: test compile of new adaptor
#


#####################################################################
#
# sub: get interactive user feedback
#
sub get_yesno ()
{
  my $answer = "n";
  
  print "[y/N] ";
  
  while ( 1 )
  {
    $answer = getc (STDIN);

    if ( $answer =~ /[yn\n]/i )
    {
      last;
    }
  }

  if ( $answer eq 'y' )
  {
    return 1;
  }

  return 0;
}

#####################################################################
#
# sub: print help message and exit
#
sub help (;$$)
{
  my $msg = shift || "";
  my $ret = shift || 0;

  if ( $msg ne "" )
  {
    $msg =~ s/\n/\n    /og;

    print <<EOT;
    
  Error:
  ------

    $msg
EOT

  }

  print <<EOT;


  Usage:
  ------
  
    $0 [options]

    This script creates stubs for new SAGA adaptors, along with 
    Makefiles and configuration files.  All methods in the resulting 
    adaptors throw a 'NotImplemented' exception, so the adaptors
    are useless.  They can serve, however, as a convenient starting 
    point for new adaptors.


  Options: 
  --------

    -t|--type=<type>
                type of adaptor to create.  Allowed vlues are the 
                names of the supported SAGA packages, which are, 
                at the moment: 'context', 'advert', 'file', 'job', 
                'replica', 'rpc' and 'stream'.

    -p|--prefix=<prefix>
                identifying name or prefix for the adaptor.  For 
                example, a globus-4-preWS adaptor should get a 
                prefix like 'globus-4-preWS' ;-)  Note that 
                prefix + type form the adaptor name, so should be 
                unique.
                
    -d|--dir=<path>
                target directory for created adaptor.  The adaptor 
                will actualy reside in
                path/prefix/prefix_type/

    -h|--help   prints this help message


  Environment:
  ------------

    SAGA_LOCATION 
               must point to a valid SAGA installation.  This script
               needs that information to pick up the adaptor skeleton
               files.

  Bugs:
  -----

    At some point in the future, this script will also try to compile
    and use the created adaptor - that is not implemented, yet.

EOT

  exit ($ret);
}

