use strict;
use Data::Dumper;
use File::Find;
use Cwd;
# Initialise filenames and check they're there


my @list;

my $gpath = $ENV{GPT_LOCATION};

if (!defined($gpath))
{
  $gpath = $ENV{GLOBUS_LOCATION};

}

if (!defined($gpath))
{
   die "GPT_LOCATION or GLOBUS_LOCATION needs to be set before running this script"
}

@INC = (@INC, "$gpath/lib/perl");

require Grid::GPT::V1::Version;
require Grid::GPT::V1::Package;
require Grid::GPT::DepIndexes;
require Grid::GPT::Setup;

my %generated_pkgs;

my $srcpkgdir = cwd();
$srcpkgdir .= '/t/depdir';
my $pkgdir = "$srcpkgdir/etc/globus_packages";


# name - package name.
# type - package type.
# libs - package libraries
# extlibs - external libraries
# setup - setup API name
# script - post install setup script
# message - post install setup message
# version - major version number.


my $runtimes = [{
                name => 'rtfoo',
                type => 'pgm',
                depends => [{
                             name => 'rtfee',
                             type => 'data',
                             depends => [{
                                          name => 'rtfum',
                                          type => 'doc',
                                         }],
                            },
                            {
                             name => 'rtfue',
                             type => 'pgm',
                            }],
               },

               {
                name => 'rtfuu',
                type => 'doc',
                depends => [{
                             name => 'rtfee',
                            },
                            {
                             name => 'rtfue',
                            }],
               }];

my $complexruntimes = [{
                name => 'crtfoo',
                type => 'pgm',
                depends => [{
                             name => 'crtfee',
                             type => 'data',
                             depends => [{
                                          name => 'crtfum',
                                          type => 'doc',
                                         }],
                            },
                            {
                             name => 'crtfix',
                             type => 'pgm_static',
                            },
                            {
                             name => 'crtfox',
                             flavor => 'noflavor',
                             type => 'pgm',
                            },
                            {
                             name => 'crtfur',
                             flavor => 'noflavor',
                             type => 'pgm_static',
                            }
                           ],
               },

               {
                name => 'crtfuu',
                type => 'doc',
                depends => [{
                             name => 'crtfee',
                            },
                            {
                             name => 'crtfue',
                            },
                            {
                             name => 'crtfewy',
                             missing => 1,
                            }],
               }];

for my $ptype ('lib', 'pgm', 'data', 'doc') {


# Were going to ignore dev packages for now.

  my $pkgtype = $ptype;
  $pkgtype = 'rtl' if $ptype eq 'lib';

  generate(version => 2, 
           deptype => "Runtime",
           type => $pkgtype,
           extlibs => "",
           libs => "-ldontcare",
           list => [{ name => "installed_runtime_$ptype",  
                      type => $pkgtype, 
                      depends => $runtimes}],
          );

  generate(version => 2,
           deptype => "$ {ptype}_runtime",
           type => $pkgtype,
           extlibs => "",
           libs => "-ldontcare",
           list => [{ name => "source_runtime_$ptype",  
                      type => 'src', 
                      depends => $runtimes}],
          );

  generate(version => 2, 
           deptype => "Runtime",
           type => $pkgtype,
           extlibs => "",
           libs => "-ldontcare",
           list => [{ name => "installed_complexruntime_$ptype",  
                      type => $pkgtype, 
                      depends => $complexruntimes}],
          );

  generate(version => 2,
           deptype => "$ {ptype}_runtime",
           type => $pkgtype,
           extlibs => "",
           libs => "-ldontcare",
           list => [{ name => "source_complexruntime_$ptype",  
                      type => 'src', 
                      depends => $complexruntimes}],
          );
}

my $compiles = [{
                 name => 'cfoo',
                 depends => [{
                              name => 'cfee',
                              depends => [{
                                           name => 'cfum',
                                          }],
                             },
                             {
                              name => 'cfue',
                             }],
                },
                {
                 name => 'cfuu',
                 depends => [{
                              name => 'cfee',
                             },
                             {
                              name => 'cfue',
                             }],
                }];

generate(version => 2,
         deptype => "Compile",
         type => 'dev',
         extlibs => "",
         libs => "-ldontcare",
         list => [{ name => "source_compile_src",  
                    type => 'src', 
                    depends => $compiles}],
          );

my $libs = [{
             name => 'lfoo',
             libs => '-lfoo',
                 depends => [{
                              name => 'lfee',
                              libs => '-lfee',
                              depends => [{
                                           name => 'lfum',
                                           libs => '-lfum',
                                           extlibs => '-lsocket'
                                          }],
                             },
                             {
                              name => 'lfue',
                              libs => '-lfue',
                              extlibs => '-lsocket'
                             }],
                },
                {
                 name => 'lfuu',
                 libs => '-lfuu',
                 depends => [{
                              name => 'lfee',
                             },
                             {
                              name => 'lfue',
                             }],
                }];

my $complexlibs = [{
             name => 'lcomplexfoo',
             libs => '-lcomplexfoo',
                 depends => [{
                              name => 'lcomplexfee',
                              libs => '-lcomplexfee',
                              depends => [{
                                           name => 'lcomplexfum',
                                           libs => '-lcomplexfum',
                                           extlibs => '-lsocket',
                                           depends => [{
                                                        name => 'lcomplexfigi',
                                                        libs => '-lcomplexfigi',
                                                        extlibs => '-lsocket'
                                                       }],

                                          }],
                             },
                             {
                              name => 'lcomplexfue',
                              libs => '-lcomplexfue',
                              extlibs => '-lsocket',
                              depends => [{
                                           name => 'lcomplexfee',
                                          },
                                          {
                                           name => 'lcomplexfigi',
                                          }],
                             }],
                },
                {
                 name => 'lcomplexfuu',
                 libs => '-lcomplexfuu',
                 depends => [{
                              name => 'lcomplexfee',
                             },
                             {
                              name => 'lcomplexfoo',
                             },
                             {
                              name => 'lcomplexfigi',
                             },
                            {
                             name => 'lcomplexfewy',
                             missing => 1,
                            }],
                },
                   {
                    name => 'lcomplexfigi',
                   }];

for my $ptype ('rtl','dev') {

  my $link = $ptype eq 'rtl' ? "Runtime_Link" : "Build_Link";


  generate(version => 2, 
           deptype => $link,
           type => $ptype,
           extlibs => "",
           libs => "-ldontcare",
           list => [{ name => "installed_link_$ptype",  
                      type => $ptype, 
                      depends => $libs}],
          );

  generate(version => 2,
           deptype => "pgm_link",
           type => $ptype,
           extlibs => "",
           libs => "-ldontcare",
           list => [{ name => "source_link_$ptype",  
                      type => 'src', 
                      depends => $libs}],
          );
  generate(version => 2, 
           deptype => $link,
           type => $ptype,
           extlibs => "",
           libs => "-ldontcare",
           list => [{ name => "installed_complex_link_$ptype",  
                      type => $ptype, 
                      depends => $complexlibs}],
          );

  generate(version => 2,
           deptype => "pgm_link",
           type => $ptype,
           extlibs => "",
           libs => "-ldontcare",
           list => [{ name => "source_complex_link_$ptype",  
                      type => 'src', 
                      depends => $complexlibs}],
          );
}



my $setups = [{
                 name => 'setfoo',
                 setup => 'setfoo',
                 script => 'setup/globus/setfoo',
                 message => 'you need to run setup/globus/setfoo',
                 depends => [{
                              name => 'setfee',
                              setup => 'setfee',
                              script => 'setup/globus/setfee',
                              message => 'you need to run setup/globus/setfee',
                              depends => [{
                                           name => 'setfum',
                                           setup => 'setfum',
                                           script => 'setup/globus/setfum',
                                           message => 'you need to run setup/globus/setfum',
                                          }],
                             },
                             {
                              name => 'setfue',
                              setup => 'setfue',
                              script => 'setup/globus/setfue',
                              message => 'you need to run setup/globus/setfue',
                             }],
                },
                {
                 name => 'setfuu',
                 setup => 'setfoo',
                 script => 'setup/globus/setfuu',
                 message => 'you need to run setup/globus/setfuu',
                 depends => [{
                              setup => 'setfee',
                             },
                             {
                              setup => 'setfue',
                             },
                            {
                             setup => 'setfewy',
                             missing => 1,
                            }],
                }];


for my $ptype ('lib', 'pgm', 'data', 'doc') {


# Were going to ignore dev packages for now.

  my $pkgtype = $ptype;
  $pkgtype = 'rtl' if $ptype eq 'lib';

  generate(version => 2, 
           deptype => "Setup",
           type => 'pgm',
           extlibs => "",
           libs => "-ldontcare",
           list => [{ name => "installed_setup_$ptype",  
                      type => $pkgtype, 
                      depends => $setups}],
          );

  generate(version => 2,
           deptype => "Setup",
           type => 'pgm',
           extlibs => "",
           libs => "-ldontcare",
           list => [{ name => "source_setup_$ptype",  
                      type => 'src', 
                      depends => $setups}],
          );
}


my $setuped = new Grid::GPT::Setup(package_name => 'setfee',
                                  globusdir => $srcpkgdir);

$setuped->finish();

my $complexsrc = [{
             name => 'complexsrcfoo',
             libs => '-lcomplexsrcfoo',
                 depends => [{
                              name => 'complexsrcfee',
                              libs => '-lcomplexsrcfee',
                              depends => [{
                                           name => 'complexsrcfum',
                                           libs => '-lcomplexsrcfum',
                                           extlibs => '-lsocket',
                                           depends => [{
                                                        name => 'complexsrcfigi',
                                                        libs => '-lcomplexsrcfigi',
                                                        extlibs => '-lsocket'
                                                       }],

                                          }],
                             },
                             {
                              name => 'complexsrcfue',
                              libs => '-lcomplexsrcfue',
                              extlibs => '-lsocket'
                             }],
                },
                {
                 name => 'complexsrcfuu',
                 libs => '-lcomplexsrcfuu',
                 depends => [{
                              name => 'complexsrcfee',
                             },
                             {
                              name => 'complexsrcfue',
                             },
                             {
                              name => 'complexsrcfigi',
                             },
                            {
                             name => 'complexsrcfewy',
                             missing => 1,
                            }],
                },
                   {
                    name => 'complexsrcfigi',
                   }];

  generate(version => 2,
           deptype => "lib_link",
           type => 'src',
           extlibs => "",
           libs => "-ldontcare",
           list => [{ name => "complexsrctop",  
                      type => 'src', 
                      depends => $complexsrc}],
          );

sub generate {
  my (%args) = @_;
  my ($version, $type, $deptype, $list, $libs, $extlibs) = ($args{'version'},
                                           $args{'type'},
                                           $args{'deptype'},
                                           $args{'list'},
                                           $args{'libs'},
                                           $args{'extlibs'},
                                          );
  for my $o (@$list) {
    genpkg(version =>$version, 
           type => $type, 
           deptype =>$deptype,
           libs =>$libs,
           extlibs =>$extlibs,
           obj => $o);

    next if ! defined $o->{'depends'};

    generate(version =>$version, 
             type => $type,
             deptype =>$deptype,
             libs =>$libs,
             extlibs =>$extlibs,
             list => $o->{'depends'});
    }
}

sub genpkg {
  my (%args) = @_;
  my ($version, $type, $deptype, $libs, $extlibs, $obj) = ($args{'version'},
                                                           $args{'type'},
                                                           $args{'deptype'},
                                                           $args{'libs'},
                                                           $args{'extlibs'},
                                                           $args{'obj'}
                                                          );

  return if defined $obj->{'missing'};
  $version = $obj->{'version'} if defined $obj->{'version'};
  $type = $obj->{'type'} if defined $obj->{'type'};
  return if defined $generated_pkgs{"$obj->{'name'}-$type"};
  $generated_pkgs{"$obj->{'name'}-$type"} = $obj;

  my $ver = new Grid::GPT::V1::Version(type => 'aging',
                               major => $version,
                               minor => 0,
                               age => 0);


  my $pkg = new Grid::GPT::V1::Package(
                                   Name => $obj->{'name'},
                                   Version => $ver,
                                   Format_Version =>"0.01",
                                   doctype =>'gpt_package_metadata',
                                   system =>"globus_package.dtd",
                                   Description =>"This is the brand new package foo.
      
      Its really cool!",
                                   Functional_Group =>'I/Am/Somebody/Because/I/Belong',
                                   Version_Stability =>"experimental",
                                   Package_Type => $type,
                                 );

  for my $d (@{$obj->{'depends'}}) {
    my ($dversion, $dtype) = ($version, $type);
    $dversion = $d->{'version'} if defined $d->{'version'};
    $dtype = $d->{'type'} if defined $d->{'type'};
    $dtype = 'pgm' if $dtype eq 'pgm_static';
    $deptype = "Runtime" if $deptype =~ m!_runtime! and $type ne 'src';
    $deptype = "Runtime_Link" if $deptype =~ m!pgm_link! and $type eq 'rtl';
    $deptype = "Build_Link" if $deptype =~ m!pgm_link! and $type eq 'dev';
    my $flavor = $deptype =~ m!_[Ll]ink! ? 'bitter' : 'noflavor';
    if (defined ($generated_pkgs{"$d->{'name'}}-$type"})) {
      my $gend = $generated_pkgs{"$d->{'name'}-$type"};
      $dversion = $gend->{'version'} if ! defined $d->{'version'};
      $dtype = $gend->{'type'} if ! defined $d->{'type'};
    }
    my $dver = new Grid::GPT::V1::Version(type => 'simple',
                               major => $dversion,
                               minor => 0,
                               age => 0);

    my $dep;
    if ($deptype eq 'Setup') {
      if ($type eq 'src') {
        $pkg->{'Source_Dependencies'} = new Grid::GPT::DepIndexes
          if ! defined $pkg->{'Source_Dependencies'};
        $dep = new Grid::GPT::V1::SourceDependency(name => $d->{'setup'},
                                                   type => 'Setup',
                                                   versions => [$dver],
                                                   pkg_type => $dtype
                                                  );
        $pkg->{Source_Dependencies}->add_dependency($dep);
      } else {
        $pkg->{'Binary_Dependencies'} = new Grid::GPT::DepIndexes
          if ! defined $pkg->{'Binary_Dependencies'};
        $dep = new Grid::GPT::V1::BinaryDependency(name => $d->{'setup'},
                                                   type => 'Setup',
                                                   versions => [$dver],
                                                   pkg_type => 'pgm',
                                                   my_pkg_type => $pkg->{'Package_Type'},
                                                  );
        $pkg->{Binary_Dependencies}->add_dependency($dep);
      
      }
    } elsif ($type eq 'src') {

      $dtype = undef if $deptype !~ m!_runtime!;

      $dep = new Grid::GPT::V1::SourceDependency(name => $d->{'name'},
                                           type => $deptype,
                                           versions => [$dver],
                                           pkg_type => $dtype);
      if (!defined ($pkg->{'Source_Dependencies'})) {
        $pkg->{'Source_Dependencies'} = new Grid::GPT::DepIndexes;
      }
      $pkg->{'Source_Dependencies'}->add_dependency($dep);
    } else {
      $dep = new Grid::GPT::V1::BinaryDependency(name => $d->{'name'},
                                           type => $deptype,
                                           flavor => $flavor,
                                           versions => [$dver],
                                           pkg_type => $dtype);
      if (!defined ($pkg->{'Binary_Dependencies'})) {
        $pkg->{'Binary_Dependencies'} = new Grid::GPT::DepIndexes;
      }
      $pkg->{'Binary_Dependencies'}->add_dependency($dep);
    }

  }

  if ($type eq 'src' or $type eq 'dev') {
    $pkg->{'cflags'} = "-g";
    $pkg->{'external_includes'} = "-I/usr/local/include";

    die "$obj->{'name'} is screwed |$extlibs|$libs|\n" 
      if ! defined $extlibs or ! defined $libs;
    $pkg->{'external_libs'} = $extlibs;
    $pkg->{'external_libs'} = $obj->{'extlibs'}
      if defined $obj->{'extlibs'};
    $pkg->{'pkg_libs'} = $libs;
    $pkg->{'pkg_libs'} = $obj->{'libs'}
      if defined $obj->{'libs'};

#    print Dumper $pkg;
  }

  $pkg->{'With_Flavors'} = 'yes' if $type eq 'src';

  my $flavor;
  $flavor = $obj->{'flavor'} if defined $obj->{'flavor'};
  $flavor = 'bitter' if $type ne 'src' and ! defined $flavor;
  $flavor = 'noflavor' if defined $obj->{'setup'};
  $pkg->{'Flavor'} = $flavor;

#  print "$flavor, $type, $obj->{'name'}\n";

  $pkg->{'Setup_Name'} = $obj->{'setup'} if defined $obj->{'setup'};

  $pkg->{'Setup_Version'} = $ver if defined $obj->{'setup'};

  $pkg->{'Post_Install_Message'} = $obj->{'message'} 
    if defined $obj->{'message'};

  $pkg->{'Post_Install_Program'} = $obj->{'script'}
    if defined $obj->{'script'};

  $pkg->{'pkg_libs'} = $obj->{'libs'} if defined $obj->{'libs'};

  $pkg->{'external_libs'} = $obj->{'extlibs'} if defined $obj->{'extlibs'};

  if ($type eq 'src') {
#    print "generating $srcpkgdir/$obj->{'name'}_src.gpt\n";
    $pkg->output_metadata_file("$srcpkgdir/$obj->{'name'}_src.gpt");
  } else {
    mkinstalldir("$pkgdir/$obj->{'name'}");
#    print "generating $pkgdir/$obj->{'name'}/pkg_data_bitter_$type.gpt\n";
    $pkg->output_metadata_file("$pkgdir/$obj->{'name'}/pkg_data_$ {flavor}_$type.gpt");
  }


  # name, type, depends, script, message, libs, extlibs

}
sub mkinstalldir {
  my $dir = shift;
  my @dirlist = split m!/!, $dir;
  my $subdir= "";
  for my $d (@dirlist) {
    $subdir .= "/$d";
    if (! -d $subdir) {
      my $result = `mkdir $subdir`;
    }
  }
}
