=head1 NAME

  CFX5::ResInfo - Object responsible for maintaining records about
                  results files generated during this simulation

=head1 SYNOPSIS

=head1 DESCRIPTION

$Id$

=cut

package CFX5::ResInfo;

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 = { 
    nResInfo  => 0 , 
    SimStep   => undef, 
    ConfStep  => undef, 
    ConfName  => undef, 
    FilePath  => undef, 
	};
  bless $self, $class;
  return $self;
}

#
################################################################################
# Modifications
################################################################################
#
sub ClearEntry {
  my $self     = shift ;
  my $simStep  = shift ; 
  my $confStep = shift ; 
  my $confName = shift ; 
  my $filePath = shift ; 

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

  my $found = 0;
  my $ii = 0;
  for ($ii=0; $ii < $self->{nResInfo}; $ii++) {
    if ($self->{SimStep}[$ii]  eq $simStep  and
        $self->{ConfStep}[$ii] eq $confStep and
        $self->{ConfName}[$ii] eq $confName and
        $self->{FilePath}[$ii] eq $filePath ) {
      $found = 1;
      last; 
    }
  }
  
  if ($found) {
    $self->{nResInfo} -= 1 ; 
    splice(@{$self->{SimStep}},  $ii, 1) ; 
    splice(@{$self->{ConfStep}}, $ii, 1) ; 
    splice(@{$self->{ConfName}}, $ii, 1) ; 
    splice(@{$self->{FilePath}}, $ii, 1) ; 
  }
}

sub ClearEntries {
  my $self     = shift ;
  my $simStep  = shift ; 
  my $confStep = shift ; 
  my $confName = shift ; 

  my $offset = 0;
  my $length = 0; 
  for (my $ii=0; $ii < $self->{nResInfo}; $ii++) {
    if ($self->{SimStep}[$ii]  eq $simStep and
        $self->{ConfStep}[$ii] eq $confStep and
        $self->{ConfName}[$ii] eq $confName ) {
      $length++; 
      $offset = $ii if ($length == 1) ;
    }
  }
  $self->{nResInfo} -= $length ; 
  splice(@{$self->{SimStep}}, $offset, $length) ; 
  splice(@{$self->{ConfStep}}, $offset, $length) ; 
  splice(@{$self->{ConfName}}, $offset, $length) ; 
  splice(@{$self->{FilePath}}, $offset, $length) ; 
}

#
################################################################################
# Input
################################################################################
#
#
#===============================================================================
# Add new entry during run
#===============================================================================
#
sub AddEntry {
  my $self     = shift;
  my $simStep  = shift; 
  my $confStep = shift; 
  my $confName = shift; 
  my $filePath = shift; 
  
  # Validation
  unless (defined $simStep) {
    _error("AddEntry failed - missing Simulation Step");
    return 0; 
  }
  unless (defined $confStep) {
    _error("AddEntry failed - missing Configuration Step");
    return 0; 
  }
  unless (defined $confName) {
    _error("AddEntry failed - missing Configuration Name");
    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->{nResInfo} ; 
  push (@{$self->{SimStep}},  $simStep) ;
  push (@{$self->{ConfStep}}, $confStep) ;
  push (@{$self->{ConfName}}, $confName) ;
  push (@{$self->{FilePath}}, $filePath) ;
    
  1 ; 
}

#
#===============================================================================
# File Input
#===============================================================================
#
sub ReadFromFile {
  my $self=shift;
  my $fName=shift;  
  
  #
  # Clear existing array before reading
  $self->{nResInfo} = 0 ; 
  $self->{SimStep}  = () ; 
  $self->{ConfStep} = () ; 
  $self->{ConfName} = () ; 
  $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/RES_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],${$entry}[3]); 
  }
  
  return 1; 
}

sub ReadFromPrintFile {
  my $self=shift;
  my $srcFile=shift; 
  
  #
  # Clear existing array before reading
  $self->{nResInfo} = 0 ; 
  $self->{SimStep}  = () ; 
  $self->{ConfStep} = () ; 
  $self->{ConfName} = () ; 
  $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->{nResInfo}) {
    print "Res Info dataset is empty\n" ; 
    return 1; 
  } 
  
  my $ii = 0;
  print "$self->{nResInfo}\n";
  while ($ii < $self->{nResInfo}) {
    print "$self->{SimStep}[$ii],";
    print "$self->{ConfStep}[$ii],";
    print "$self->{ConfName}[$ii],";
    print "$self->{FilePath}[$ii]\n";
    $ii++;
  }
  1; 
}
#
sub PrettyPrint {
  my $self=shift; 

  print "\n\n";
  
  if (!$self->{nResInfo}) {
    print "Results information dataset is empty\n" ; 
    return 1; 
  } 
  
  my $ii = 0;
	print  "================================================================================\n";
  printf (" Results Information Dataset                               (Total Entries: %3i)\n",$self->{nResInfo});
	print  "================================================================================\n";
	print  "| Entry  | Sim. Step | Config. Step | Config. Name                             |\n";
	print  "|        | File Path                                                           |\n";
	print  "+--------+-----------+--------------+------------------------------------------+\n";
  while ($ii < $self->{nResInfo}) {
	  printf("|   %3i  |      %3i  |         %3i  | %-41s|\n",
		      $ii,
		      $self->{SimStep}[$ii],
					$self->{ConfStep}[$ii],
					$self->{ConfName}[$ii]);
    my @text = wraptext(67,$self->{FilePath}[$ii]) ;
    foreach my $line (@text) {
  	  printf("|        | %-67s |\n",$line);
    }
		print  "+--------+-----------+--------------+------------------------------------------+\n";
    $ii++;
  }
  1; 
}
#
#===============================================================================
# ASCII file output
#===============================================================================
#
sub WriteToASCII
{
  my $Self = shift;
  my $FileName = shift;

  if (! $Self->{nResInfo})
  {
    print "Res 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->{nResInfo}\n";
  while($Index < $Self->{nResInfo})
  {
    foreach $Hash ('SimStep', 'ConfStep', 'ConfName')
    {
      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;  

  unless (defined $when) {
    $when = 0 ; 
  }
	
  return 1 if ($self->{nResInfo} eq 0); 
  
  my $ds = new CFX5::DefFile::DataSet(); 

  $ds->header(what=>'G/RES_INFO'); 
  $ds->header(where=>'EVERY'); 
  $ds->header(when=>$when); 
  $ds->header(number=>$self->{nResInfo}); 
  # SR: switch definition once io module is cleaned up...
  #$ds->header(datatype=>"STRC{INTR:2 STRI:1 CHAR:256}"); 
  $ds->header(datatype=>"STRC{INTR:2 STRI:80 CHAR:256}"); 

  my @data ;
  my $ii = 0 ; 
  while ($ii < $self->{nResInfo}) {
    my @lclData; 
    push (@lclData, $self->{SimStep}[$ii]) ; 
    push (@lclData, $self->{ConfStep}[$ii]) ; 
    push (@lclData, $self->{ConfName}[$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->{nResInfo};
}

# GetEntry - returns a specific entry

sub GetEntry {
  my $self = shift;
  my $i = shift;
  return undef unless ($self->{nResInfo} && $i < $self->{nResInfo});
  my %rv = () ;
  $rv{SimStep}  = ${$self->{SimStep}}[$i];
  $rv{ConfStep} = ${$self->{ConfStep}}[$i];
  $rv{ConfName} = ${$self->{ConfName}}[$i];
  $rv{FilePath} = ${$self->{FilePath}}[$i];
  return %rv;
}

# GetLast - returns the last resinfo for a given config, or the last entry if
# no config has been specified

sub GetLast {
  my $self=shift;
  my $configname=shift;
  
  my %rv = () ; 

  for(my $i=$self->{nResInfo} - 1; $i >= 0; $i--){
    if( not defined $configname or ${$self->{ConfName}}[$i] eq $configname ){
      $rv{SimStep}=${$self->{SimStep}}[$i];
      $rv{ConfStep}=${$self->{ConfStep}}[$i];
      $rv{ConfName}=${$self->{ConfName}}[$i];
      $rv{FilePath}=${$self->{FilePath}}[$i];
      return %rv;
    }
  }
  %rv; 
}

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

1 ;
