=head1 NAME

  CFX5::Parallel::Reqs::hst - Hst generator for CFX-5 parallel

=cut

package CFX5::Parallel::Reqs::hst;

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 strict;

=head2 F<hst> file functions

The calls in this section allow the reading and writing of various
host definition files.

=head3 write_hst_file

I<Internal>

  $self->write_hst_file($file, @hosts);
  $self->write_hst_file($file, @count_host);

Writes a set of records to a file in the normal hst format.  The input
list is either a list of CFX5::Parallel::Host objects, in which case a
normal hst file is written, or a set of listrefs of the C<[I<count>,
I<host>]> form returned by C<consolidated_partitions>, in which case
the "number of processors" field is taken from the count rather than
the object.

Lists may also be a mixture of these two, each element is considered
individually - this is more a bug than a feature, and might be fixed
later.

=cut

# to allow phst.pm to override part of the file
sub speed_entry {
  my $self=shift;
  my $h=shift;
  return $h->speed();
}
sub exec_entry {
  my $self=shift;
  my $h=shift;
  my $exec=$h->actual_executable($self->ppe()->start_method());
  return $exec;
}

sub write_hst_file {
  my $self=shift;
  my $file=shift;

  my @hosts=@_;

  return '' unless CFX5::FileTests::datafile_w($file, "CFX-5 hosts file $file");

  local *HSTFILE;

  unless (open HSTFILE, ">$file") {
    _error("Unable to open CFX-5 hosts file $file for writing: $!");
    return '';
  }

  print HSTFILE scalar(@hosts), "\n";
  for my $hr (@hosts) {
    # what sort of element is this one?
    my ($h,$c);
    if (ref($hr) eq 'ARRAY') {
      # [count,host]
      $c=$hr->[0];
      $h=$hr->[1];
    } else {
      $h=$hr;
      $c=$h->processors();
    }

    unless (defined $c) {
      internal_error("Undefined processor count for host", $h->name());
    }

    print HSTFILE $h->pvmname(),"\n";
    my $exec=$self->exec_entry($h);
    if (defined $exec) {
      $exec =~ s!\\!/!g;
      print HSTFILE $exec,"\n";
    } else {
      # can't find the executable name.  We'll stop with an error
      # later, so for now, just leave a note.
      print HSTFILE "unknown\n";
    }
    print HSTFILE $self->speed_entry($h),"\n";
    print HSTFILE $c,"\n";
  }

  unless (close HSTFILE) {
    _error("Error writing to CFX-5 hosts file $file: $!");
    return '';
  }

  1;
}

=head3 write_hst

  $ppe->write_hst($file);

Creates a 'hst' file, containing the hosts included in the run.  Any
errors will be signalled with _error.

=cut

sub write_hst {
  my $self=shift;
  my $file=shift;

  my @hl=$self->ppe()->hosts();

  return $self->write_hst_file($file, @hl);
}

=head4 setup

=cut

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

  # we always remove and re-write
  $workdir->remove_file('hst') if $workdir->have_file('hst');
  my $file=$workdir->creatable_file('hst');
  unless ($self->write_hst($file)) {
    _error("Error writing hst file: $!");
    return undef;
  }
  return $file;
}


1;
