=head1 NAME

  CFX5::TrnInfo - Object responsible for maintaining records about
                  transient results files

=head1 SYNOPSIS

=head1 DESCRIPTION

$Id$

=cut

package CFX5::TrnInfo;

use strict;

use CFX5::Output qw(:all error_text);
use CFX5::PathManip qw(dirname basename fullpath join_file split_file normalize_filename split_mult_files);
use CFX5::Simulation::Util qw (GetDataSet);
use CFX5::FileStat;
use CFX5::Output::Utils 'wraptext';
use CFX5::DefFile 'DataSet';

#
################################################################################
# new: Constructor
################################################################################
#
sub new {
  my $this = shift;

  my $class = ref($this) || $this;
  my $self = {
    nTrnInfo  => 0 ,
    TimeStep  => undef,
    SimuTime  => undef,
    FilePath  => undef,
	};
  bless $self, $class;
  return $self;
}

#
################################################################################
# Modifications
################################################################################
#

# Add new entry

sub AddEntry {
  my $self     = shift;
  my $timeStep = shift;
  my $simuTime = shift;
  my $filePath = shift;

  # Validation
  unless (defined $timeStep) {
    _error("AddEntry failed - missing Time Step");
    return 0;
  }
  unless (defined $simuTime) {
    _error("AddEntry failed - missing Simulation Time");
    return 0;
  }
  unless (defined $filePath) {
    _error("AddEntry failed - missing file path");
    return 0;
  }

  # Cleanup directory separators; we'll use UNIX style '/' consistently
  my $filePathClean = normalize_filename($filePath);
  my @filePathArray = split_file($filePathClean);
  $filePath = join('/',@filePathArray);

  # Add the entry
  my $ii = ++$self->{nTrnInfo};
  push (@{$self->{TimeStep}}, $timeStep);
  push (@{$self->{SimuTime}}, $simuTime);
  push (@{$self->{FilePath}}, $filePath);

  1;
}

# Delete entry

sub DeleteEntry {
  my $self = shift;
  my $i    = shift;

  return 0 unless ($i < $self->{nTrnInfo});

  $self->{nTrnInfo} -= 1;
  splice(@{$self->{TimeStep}}, $i, 1);
  splice(@{$self->{SimuTime}}, $i, 1);
  splice(@{$self->{FilePath}}, $i, 1);
  
  return 1;
}

# DeleteDuplTimestep - Delete entries with duplicate time step

sub DeleteDuplTimestep {
  my $self=shift;

  my @todelete;
  for (my $i=1; $i<$self->{nTrnInfo}; $i++) {
    for (my $j=0; $j<$i; $j++) {
      unshift(@todelete,$i) if ($self->{TimeStep}[$i] == $self->{TimeStep}[$j]);
    }
  }

  for my $i (@todelete) {
    return 0 unless($self->DeleteEntry($i));
  }
  
  return 1;
}

#
################################################################################
# Input
################################################################################
#
#
#===============================================================================
# File Input
#===============================================================================
#
sub ReadFromFile {
  my $self=shift;
  my $fName=shift;

  #
  # Clear existing array before reading
  $self->{nTrnInfo} = 0;
  $self->{TimeStep} = ();
  $self->{SimuTime} = ();
  $self->{FilePath} = ();

  #
  # Get the dataset from the file
  # --> let client decide what to do if the dataset is missing
  my @res_info = GetDataSet($fName,"G/TRN_INFO");
  unless (ref $res_info[0]) {
    return 0;
  }

  #
  # Translate dataset structure (array of arrays) to local structure
  foreach my $entry (@res_info) {
    # Strip trailing whitespace
    @{$entry} = map {$_=~s!\s+$!!; $_;} @{$entry};
    $self->AddEntry(${$entry}[0],${$entry}[1],${$entry}[2]);
  }

  return 1;
}

sub ReadFromPrintFile {
  my $self=shift;
  my $srcFile=shift;

  #
  # Clear existing array before reading
  $self->{nTrnInfo} = 0;
  $self->{TimeStep} = ();
  $self->{SimuTime} = ();
  $self->{FilePath} = ();

  unless(open(INP,"<".$srcFile) ) {
    print("Can't open Input file: $srcFile!\n");
    return 0;
  }

  my $line = <INP>;

  while($line=<INP>){
    chomp $line;
    my @fields=split_mult_files($line);
    $self->AddEntry(@fields);
  }
  close(INP);
}

#
################################################################################
# Output
################################################################################
#
#===============================================================================
# Printed output (stdout) for debugging
#===============================================================================
#
sub Print {
  my $self=shift;

  if (!$self->{nTrnInfo}) {
    print "Res Info dataset is empty\n";
    return 1;
  }

  my $ii = 0;
  print "$self->{nTrnInfo}\n";
  while ($ii < $self->{nTrnInfo}) {
    print "$self->{TimeStep}[$ii],";
    print "$self->{SimuTime}[$ii],";
    print "$self->{FilePath}[$ii]\n";
    $ii++;
  }
  1;
}
#
sub PrettyPrint {
  my $self=shift;

  print "\n\n";

  if (!$self->{nTrnInfo}) {
    print "Transient results information dataset is empty\n";
    return 1;
  }

  my $ii = 0;
  print  "================================================================================\n";
  printf (" Transient Results Information Dataset                  (Total Entries: %6i)\n",$self->{nTrnInfo});
  print  "================================================================================\n";
  print  "| Entry  | Time Step | Simulation Time                                         |\n";
  print  "|        | File Path                                                           |\n";
  print  "+--------+-----------+---------------------------------------------------------+\n";
  while ($ii < $self->{nTrnInfo}) {
    printf("| %6i |  %6i   | %13.6e                                           |\n",
           $ii, $self->{TimeStep}[$ii], $self->{SimuTime}[$ii]);
    my @text = wraptext(67,$self->{FilePath}[$ii]);
    for my $line (@text) {
      printf("|        | %-67s |\n",$line);
    }
    print "+--------+-----------+---------------------------------------------------------+\n";
    $ii++;
  }
  1;
}
#
#===============================================================================
# ASCII file output
#===============================================================================
#
sub WriteToASCII
{
  my $Self = shift;
  my $FileName = shift;
  
  if(! $Self->{nTrnInfo})
  {
    print "Trn info dataset is empty.\n";
    return(1);
  }
  
  local *FILE;
  if(! open(FILE, ">$FileName"))
  {
    _error("Unable to open $FileName: $!");
    return(0);
  }
  
  my $Index = 0;
  my $Hash;
  print FILE "$Self->{nTrnInfo}\n";
  while($Index < $Self->{nTrnInfo})
  {
    foreach $Hash ('TimeStep', 'SimuTime')
    {
      print FILE "$Self->{$Hash}[$Index],";
    }
    print FILE "$Self->{FilePath}[$Index]\n";
    ++$Index;
  }
  close(FILE) or _error("Cannot close $FileName: $!");
  1;
}
#
#===============================================================================
# Res file output
#===============================================================================
#
sub WriteToFile {
  my $self = shift;
  my $fName= shift;
  my $when = shift;

  return 1 if ($self->{nTrnInfo} eq 0);

  unless (defined $when) {
    # WHEN defaults to the time step of the last entry + 1 (i.e. the res file)
    my %lasttrn = $self->GetLast();
    $when =  $lasttrn{TimeStep} + 1;
  }

  my $ds = new CFX5::DefFile::DataSet();

  $ds->header(what=>'G/TRN_INFO');
  $ds->header(where=>'EVERY');
  $ds->header(when=>$when);
  $ds->header(number=>$self->{nTrnInfo});
  $ds->header(datatype=>"STRC{INTR:1 REAL:1 STRI:80}");

  my @data;
  my $ii = 0;
  while ($ii < $self->{nTrnInfo}) {
    my @lclData;
    push (@lclData, $self->{TimeStep}[$ii]);
    push (@lclData, $self->{SimuTime}[$ii]);
    push (@lclData, $self->{FilePath}[$ii]);
    push (@data,[@lclData]);
    $ii++;
  }
  $ds->data(@data);

  # Create the file if it does not exist
  my $io;
  if( not CFX5::FileStat::test_e $fName ){
    $io = CFX5::DefFile->new_file($fName);
  }
  else {
    $io = CFX5::DefFile->new($fName);
  }

  unless (ref $io) {
    _error("WriteToFile failed - could not connect to file: $fName");
    return 0;
  }

  unless ($io->write_dataset($ds)) {
    _error("WriteToFile failed - dataset write filed");
    return 0;
  }
  1;
}

#
################################################################################
# Query
################################################################################
#

# GetCount - returns number of entries

sub GetCount {
  my $self=shift;
  return $self->{nTrnInfo};
}

# GetEntry - returns a specific entry

sub GetEntry {
  my $self = shift;
  my $i = shift;
  return undef unless ($self->{nTrnInfo} && $i < $self->{nTrnInfo});
  my %rv = ();
  $rv{TimeStep} = ${$self->{TimeStep}}[$i];
  $rv{SimuTime} = ${$self->{SimuTime}}[$i];
  $rv{FilePath} = ${$self->{FilePath}}[$i];
  return %rv;
}

# GetLast - returns the last entry

sub GetLast {
  my $self=shift;

  my %rv = ();

  my $i = $self->{nTrnInfo} - 1;
  $rv{TimeStep} = ${$self->{TimeStep}}[$i];
  $rv{SimuTime} = ${$self->{SimuTime}}[$i];
  $rv{FilePath} = ${$self->{FilePath}}[$i];

  return %rv;
}

# CheckDuplFilename - Check for entries with duplicate file name

sub CheckDuplFilename {
  my $self=shift;

  for (my $i=1; $i<$self->{nTrnInfo}; $i++) {
    for (my $j=0; $j<$i; $j++) {
      return 1 if ($self->{FilePath}[$i] eq $self->{FilePath}[$j]);
    }
  }

  return 0;
}

# CheckTimestepOrder - Check order of entries (time step)

sub CheckTimestepOrder {
  my $self=shift;

  for (my $i=1; $i<$self->{nTrnInfo}; $i++) {
    return 1 unless ($self->{TimeStep}[$i] > $self->{TimeStep}[$i-1]);
  }

  return 0;
}


#
################################################################################
# End of Package
################################################################################
#

1;
