=head1 NAME

  CFX5::Simulation::Configuration::ANSYS - Ansys solver control

=head1 SYNOPSIS

This object is used by L<CFX5::Simulation::Configuration>, to manage the process of setting
up an ANSYS solver run.

=head1 DESCRIPTION

$Id$

=cut

package CFX5::Simulation::Configuration::ANSYS;

use base 'CFX5::Simulation::Subtask';

use strict;
use CFX5::Output qw(:all error_text);
use CFX5::FileTests;
use CFX5::Commands;

use CFX5::PathManip qw(dirname basename fullpath join_file normalize_filename);
use CFX5::FileOps qw(create_empty_file create_directory
		     append_to_file set_file_contents copy_file move_file
		     link_files concatenate_files);

use CFX5::Config qw(%Config export_conf);

use CFX5::CCLI;

use CFX5::Simulation::Util '_check_defined';

use CFX5::PkgLoader qw(cfx5_require);

use Carp;

=head3 ANSYS

=cut


sub _Do {
  my $self=shift;

  # make sure we've got something sensible here
  my $do=shift;
  internal_error("First argument must be 0 or 1 or 2")
    unless defined $do and ($do eq 0 or $do eq 1 or $do eq 2);

  return 1 unless $self->is_mfx_run() && $self->start_ansys();

  my @ans_cmd=();

  # Call this so that the ccl is returned to the solver manager
  $self->ansys_install_root();

  if ($do) {
    my $err=0;

    unless (defined $self->ansys_install_root()) {
      _error("Ansys installation root not set");
      return 0;
    }

    # Prevent dialogs
    $ENV{ANS_CONSEC}="YES";
    $ENV{ANSCMD_NODIAG}=1;

    if (-e $self->ansys_port_file()) {
      _error("Ansys port file already exists");
      $err=1;
    }

    if (-e join_file($self->ansys_workdir(),$self->ansys_jobname().".lock")) {
      _error("Ansys lock file exists");
      $err=1;
    }
    if ($err) {
      return 0;
    }

    my $workDir = $self->ansys_workdir() ;
    my $inpFile = $self->processed_ansys_input() ;
    my $outFile = $self->ansys_output() ;
    unless ($Config{windows_nt}) {
      $workDir = "\"$workDir\"" ;
      $inpFile = "\"$inpFile\"" ;
      $outFile = "\"$outFile\"" ;
    }

    my $ansys_exe = $self->ansys_exe();
    unless (-e "$ansys_exe")
    {
      _error("$ansys_exe " . "does not exist");
      exit(2);
    }

    unless (-r "$ansys_exe") {
      _error("$ansys_exe " . "is not readable");
      exit(2);
    }

    unless (-x "$ansys_exe") {
      _error("$ansys_exe " . "is not executable");
      exit(2);
    }

    if ($Config{windows_nt}) {
      push @ans_cmd, "cmd.exe";
      push @ans_cmd, "/c";
    }

    push @ans_cmd, "$ansys_exe";
    push @ans_cmd, "-p", $self->ansys_license() if defined $self->ansys_license();
    if ($Config{windows_nt}) {
      push @ans_cmd, "-b"
    }
    push @ans_cmd, "-dir", $workDir,
                   "-j", $self->ansys_jobname(),
                   "-mfm", "ANSYS";
    if ($Config{windows_nt}) {
      push @ans_cmd, "-i", $inpFile;
      push @ans_cmd, "-o", $outFile;
    } else {
      push @ans_cmd, "<", $inpFile;
      push @ans_cmd, ">", $outFile;
    }
    push @ans_cmd, split(/ /, $self->ansys_args()) if defined $self->ansys_args();

    if (defined $self->outfile()) {
      $self->OutFileHeader("Starting ANSYS Solver");
      _debug("ANSYS Command line:");
      _debug(join("\n", @ans_cmd)."\n");
    }

    $self->ansys_pid(CFX5::Commands::bg_cmd(@ans_cmd));

    unless (defined $self->ansys_pid()) {
      _error("Failed to start ANSYS: $!");
      return 0;
    }
    $self->ansys_running(1);

    # Wait for port file. Timeout after 15 minutes.
    my $timeout=0;
    while ($timeout<900 and not $self->stop_now()) {
      return 0 unless $self->check_status();
      last if -e $self->ansys_port_file();
      sleep 10;
      $timeout+=10;
    }

    unless (open(IN, $self->ansys_port_file())) {
      _error("Could not open ".$self->ansys_port_file().":$!");
      return 0;
    }

    my $port=<IN>;
    chomp($port);
    $port=~s/ *([0-9]*) */$1/;

    $self->ansys_port($port);
    $self->ansys_host();
    unless ($self->start_cfx()) {
       my $outfile=$self->outobj();
       my $fh=$outfile->open();
       print $fh "ANSYS solver listening on ".$self->ansys_port()."@".$self->ansys_host()."\n\n";
       $outfile->close();

       print "Started ANSYS solver, listening on ".$self->ansys_port()."@".$self->ansys_host()."\n" if $self->batch();
    }
  }

  1;
}

# Check the status of the Ansys solver
#  0 - not running (expected)
#  1 - running
# -1 - not running (unexpected)
sub check_status {
  my $self=shift;
  if ($self->ansys_running()) {
    my $rv = CFX5::Commands::poll_bg_cmd($self->ansys_pid());
    unless ($rv) {
      $self->ansys_running(0);
      _error("ANSYS Solver terminated unexpectedly with return code ". CFX5::Commands::wait_bg_cmd($self->ansys_pid()));
      return 0;
    }
  }
  return 1;
}

sub stop {
  my $self=shift;
  my $murder=shift;
  $murder=0 unless defined $murder;
  return 0 unless $self->ansys_running();
  # Kill it if it's still running
  if (CFX5::Commands::poll_bg_cmd($self->ansys_pid()) && $murder) {
    kill 1, $self->ansys_pid();
    $self->ansys_running(0);
    return 0;
  }
  my $rv=CFX5::Commands::wait_bg_cmd($self->ansys_pid());
  $self->ansys_running(0);
  if ($rv) {
    _error("ANSYS Solver terminated with return code $rv");
  }
  return 0;
}

1;
