=head1 NAME

  CFX5::Parallel::Reqs::p4_pg - P4_pg generator for CFX-5 parallel

=cut

package CFX5::Parallel::Reqs::p4_pg;

use CFX5::Parallel::Reqs::Base;
push @ISA, qw(CFX5::Parallel::Reqs::Base);

use CFX5::Config qw(%Config);
use CFX5::Output qw(:all);

use CFX5::PkgLoader qw(cfx5_require);

use CFX5::FileOps qw(append_to_file);

use strict;

sub setup {
  my $self=shift;
  my $workdir=shift;

  my @lines=$self->make_p4pg_cont();

  # we always remove and re-write
  $workdir->remove_file('p4.pg') if $workdir->have_file('p4.pg');
  my $pgfile=$workdir->creatable_file('p4.pg');
  unless (append_to_file($pgfile, @lines)) {
    _error("Error writing procgroup file: $!");
    return undef;
  }
  return $pgfile;
}

sub make_p4pg_cont {
  my $self=shift;

  # We need to consolidate partitions on the same host, to get
  # efficient use of shared memory machines, but we also need to
  # preserve the order of the hosts in the list so that any
  # non-uniform partition sizes are assigned to the correct hosts.
  my @hosts=$self->ppe()->partitions_master_first();

  # the master host gets a special entry for the first partition on
  # it, to tell it not to start any further processes.  If we can't
  # find it, this loop will not notice, but the
  # partitions_master_first call above will already have errored.

  my @lines;
  my $found_master='';

  for my $h (@hosts) {
    my $user=$Config{CFX_USER};
    if (defined $h->[1]->username()) {
      $user=$h->[1]->username();
    }

    my $exec=$h->[1]->actual_executable($self->ppe()->start_method());
    $exec='unknown' unless defined $exec;
    if ($h->[1]->use_cfx5remote()) {
      # cfx5remote_path username solver_path
      $exec=$h->[1]->fill_in_exec($h->[1]->cfx5remote_path()) . " $user $exec";
    }

    if ($h->[1]->allow_shmem()) {
      # shared memory allowed for this host - we decrement the count
      # by one for the master, but otherwise as normal
      my $c=$h->[0];
      if (!$found_master and $self->ppe()->is_master($h->[1])) {
        $c--;
        $found_master++;
      }
      push @lines, $h->[1]->pvmname() . " $c $exec\n";
    } else {
      # don't attempt to use the shared-memory mode (maybe it's not
      # supported or doesn't work), make an explicit entry for each
      # partition
      for my $i (1 .. $h->[0]) {
        if (!$found_master and $self->ppe()->is_master($h->[1])) {
          # first partition on master is not stated explicitly
          push @lines, $h->[1]->pvmname() . " 0 $exec\n";
          $found_master++;
        } else {
          push @lines, $h->[1]->pvmname() . " 1 $exec\n";
        }
      }
    }
  }

  @lines;
}

1;
