package Ernad::ReportState;
use strict;
use warnings;
use Carp qw(confess);
use Data::Dumper;
use Encode;
use File::Basename;
use File::Copy;
use Ernad::Common;
use Ernad::Erimp;
use Krichel::Shoti;
use Krichel::File;
our $UNKNOWN = 'unknown'; # Unknown state
our $STATEFILE = 'state'; # Filename
our $RiffExtension= '.amf.xml'; # A Riff's extension
our $e;
$e=$main::e;
#if(not defined($e)) {
# $e=$Erimp::e;
#}
## constructor
sub new {
my $this = shift;
my $class = ref($this) || $this;
my $rs = {};
bless $rs, $class;
my $repcode=shift();
if(not $repcode) {
my ( $package, $filename, $line ) = caller;
my $error="Your package $package file $filename line $line called ";
$error.="new Reportstate without repcode.";
confess $error;
}
my $e=shift or confess 'I need an erimp.';
if(not $e->{'report'}->{$repcode}->{'path'}) {
if(not $e->{'r'}) {
confess "My erimp does not see its recon.";
}
$e->{'r'}->load($repcode);
}
my $Path=$e->{'report'}->{$repcode}->{'path'};
my $path=$e->{'report'}->{$repcode}->{'path'};
$rs->{'repcode'}=$repcode;
$rs->{'path'}=$path;
$rs->{'stage'}='unknown';
$rs->{'e'}=$e;
$rs->{'rix'}='';
$rs->{'file'}='';
return $rs;
}
# The name, current
sub repcode() {
my $rs = shift();
return $rs->{'repcode'};
}
# The path, current
sub path() {
my $rs = shift();
return $rs->{'path'};
}
## The stage, current
sub stage() {
my $rs = shift();
my $stage_to_set = shift // '';
my $e=$rs->{'e'};
my $source_dir=$e->{'const'}->{'source_dir'};
## set the stage
if($stage_to_set) {
## Stage is going to be set
## Find the most recent file in new stage
$rs->{'stage'} = $stage_to_set;
if($rs->{'stage'} ne $source_dir) {
my $search_path=$rs->{'path'}.'/'.$rs->{'stage'};
$rs->{'file'} = $e->{'d'}->most_recent_rif($search_path);
## set back to the source of no oldest file can be found
if(not $rs->{'file'} ) {
$rs->{'stage'} = $source_dir;
}
}
else {
$rs->{'file'} = '';
}
$rs->{'rix'} = '';
$rs->save_to_state_file();
}
return $rs->{'stage'};
}
# The full path to report file
sub file() {
my $rs = shift();
if(not defined($rs->{'path'})) {
## 2020-01-13: better reporting here
my $d_rs=Dumper $rs;
confess 'I need a path.' . $d_rs;
}
if(not defined($rs->{'stage'})) {
confess 'I need a stage.';
}
if(not defined($rs->{'file'})) {
die 'I need a file.';
}
## immergency maintenance on 2019-06-19
if(-f $rs->{'file'}) {
return $rs->{'file'};
}
return $rs->{'path'}.'/'.$rs->{'stage'}.'/'.$rs->{'file'};
}
# report XML?
sub rix() {
my $rs = shift();
return $rs->{'rix'};
}
# Returns report timestamp, rather the issuedate
sub timestamp() {
my $rs = shift();
if(not $rs->{'file'}) {
return '';
}
my @s;
@s = split( "_", $rs->{'file'} );
return $s[0];
}
## Loads
sub load {
my $rs = shift();
my $issuedate=shift // '';
my $e=$rs->{'e'};
# Build up filename of state file
my $rif_ext=$e->{'const'}->{'rif_ext'};
## check all folders and find which one contains latest report
my $current_stage = '';
my $current_file = '';
my @stages=@{$e->{'const'}->{'stages'}};
if($e->{'testing'}) {
open(L,'> '.$e->{'dir'}->{'test'}.'/report_state_load.log');
print L "start\n";
}
foreach my $stage (@stages) {
## files in the stage
my $file_found_in_stage = $e->{'d'}->most_recent_rif( $rs->{'path'}.'/'.$stage,
'do_lax') // '';
if($e->{'testing'}) {
print L "stage $stage, found file_found_in_stage $file_found_in_stage\n";
}
## skip if there no files in the analyzed folder
if( $file_found_in_stage eq '') {
if($e->{'testing'}) {
print L "no file found, next ...\n";
}
next;
}
## initialize stage
if( $current_stage eq '' ) {
if($e->{'testing'}) {
print L "setting current_file to $file_found_in_stage\n";
}
$current_file = $file_found_in_stage;
if($e->{'testing'}) {
print L "setting stage to $stage\n";
}
$current_stage = $stage;
}
#elsif(&Ernad::Common::is_first_rif_more_recent($file_found_in_stage,$current_file)) {
elsif($e->{'f'}->is_first_more_recent($file_found_in_stage,$current_file)) {
if($e->{'testing'}) {
print L "updating current_file to $file_found_in_stage\n";
}
$current_file=$file_found_in_stage;
$current_stage=$stage;
if($e->{'testing'}) {
print L "updating stage to $stage\n";
}
}
}
if($e->{'testing'}) {
close L;
}
## source is the default stage
if($current_file eq '') {
$current_stage = $e->{'const'}->{'source_dir'};
}
## set values
$rs->{'stage'} = $current_stage;
$rs->{'file'} = $current_file // '';
#if(not (not $current_file or $current_file eq './' or $current_file eq '..')) {
if($current_file) {
#$rs->{'update_tist'}=&Ernad::Common::get_rif_tist($current_file)
$rs->{'update_tist'}=$e->{'f'}->tist($current_file)
}
## case of an empty report
if(not defined($rs->{'update_tist'})) {
$rs->{'update_tist'}=time;
}
$rs->{'rix'} = '';
}
sub load_from_stage {
my $rs=shift;
my $stage=shift // confess "I need a stage here.";
## files in the stage
my $e=$rs->{'e'};
my $file_found_in_stage = $e->{'d'}->most_recent_rif( $rs->{'path'}.'/'.$stage );
if($e->{'testing'}) {
print L "stage $stage, found file_found_in_stage $file_found_in_stage\n";
}
## skip if there no files in the analyzed folder
if($file_found_in_stage eq '') {
if($e->{'testing'}) {
print L "no file found, next ...\n";
}
return 0;
}
$rs->{'file'}=$file_found_in_stage;
## rs->file() gives the full path
$rs->{'rix'}= &Krichel::File::load($rs->file());
$rs->save_to_state_file();
return 1;
}
sub set_stage {
my $rs=shift;
my $stage=shift // confess "I need a stage here.";
my $e=$rs->{'e'};
if($stage eq 'source') {
$rs->{'stage'} = $e->{'const'}->{'source_dir'};
$rs->{'file'} = '';
return 0;
}
## files in the stage
my $to_find = $rs->{'path'}.'/'.$stage;
my $file_found_in_stage = $e->{'d'}->most_recent_rif( $to_find );
if($e->{'testing'}) {
print L "stage $stage, found file_found_in_stage $file_found_in_stage\n";
}
## skip if there no files in the analyzed folder
if($file_found_in_stage eq '') {
confess "no file found in $stage at $to_find";
return 0;
}
$rs->{'stage'}=$stage;
$rs->{'file'}=$file_found_in_stage;
## rs->file() gives the full path
$rs->{'rix'}= &Krichel::File::load($rs->file());
$rs->save_to_state_file();
return 1;
}
## Parses and loads in memory xml report
sub load_rix {
my $rs = shift();
## wellington
#if( $Ernad::Common::Config{'DebugInfo'} ) {
#print "trying to load ". $rs->{'file'}."
\n";
#}
###
my $file=$rs->file() // '';
if(not $file) {
confess 'I have no file to load rix from';
}
if(not -f $file) {
## just remove the state file, as the bad reference is likely be there
my $state_file=$rs->{'state_file'};
if($state_file) {
unlink $state_file;
}
##confess "I don't have the file '$file'.";
if(not $rs->{'no_reload'}) {
$rs->{'no_reload'}=1;
$rs->load();
my $file=$rs->file() // '';
if(not $file) {
confess 'I have no file to load rix from, even after reload.';
}
}
}
else {
## in case it does not exits, we can reload
$rs->{'can_reload'}=1;
}
$rs->{'rix'} = &Krichel::File::load( $rs->file());
return $rs->{'rix'};
}
## Generates filename
sub generate_file_name {
my $rs = shift();
my $file = shift // $rs->{'file'};
if(not $file ) {
confess "I need a file here.";
}
my $e=$rs->{'e'};
## Xmas 2017
my $bana=basename($file);
my $dina=dirname($file);
if(not $bana=~m|^(\d{4}-\d{2}-\d{2})|) {
confess "I have a bad filename $file.";
}
my $date=$1;
my $now=&Krichel::Shoti::now();
my $new_file=$date.'_'.$now.$e->{'const'}->{'rif_ext'};
return $new_file;
}
## saves the state file
sub save_to_state_file() {
my $rs = shift();
my $e=$rs->{'e'};
my @toStore;
$toStore[0] = $rs->{'stage'};
$toStore[1] = $rs->{'file'};
$rs->{'state_file'}=$rs->{'path'}.'/'.$e->{'const'}->{'state_file'};
if(not $rs->{'stage_file'}) {
my $state_file = $rs->{'path'}.'/'.$e->{'const'}->{'state_file'};
$rs->{'state_file'}=$state_file;
}
###Ernad::Common::save_to_file( \@toStore, $rs->{'state_file'});
}
## Saves the state
sub save {
my $rs = shift();
my $new_stage=shift // $rs->{'stage'};
my @toStore;
my $e=$rs->{'e'};
## Filename must be set to process
if(not $rs->{'file'} ) {
$rs->save_to_state_file();
return;
}
my $old_stage = $rs->{'stage'};
my $old_file = $rs->{'file'};
## Generate new filename, main change of Xmas 2017
my $new_file = $rs->generate_file_name();
if( $rs->{'rix'} ) {
# If report is in memory
# then save it as xml in utf-8 encoding
my $out_file=$rs->{'path'}.'/'.$new_stage.'/'.$new_file;
&Krichel::File::prepare($out_file);
open(OUT, "> $out_file");
binmode(OUT,":utf8:");
my $out_string=decode_utf8($rs->{'rix'}->toString() );
$out_string.="\n";
print OUT $out_string;
close OUT;
}
else {
# Report is not in memory
# it means it wasnt changed
# so simply copy it
### Wellington
my $old_file=$rs->{'path'}.'/'."$old_stage".'/'.$old_file;
my $new_file=$rs->{'path'}.'/'."$new_stage".'/'.$new_file;
#if( $Ernad::Common::Config{'DebugInfo'} ) {
# print "I copy $old_file to $new_file
\n";
#}
copy($old_file, $new_file);
}
# Update state and file
$rs->{'stage'} = $new_stage;
$rs->{'file'} = $new_file;
#
$rs->save_to_state_file();
}
## creates a new source file
sub create_from_source {
my $rs = shift();
my $type = shift(); # presorted or unsorted
my $dt = shift(); # Date of the file
my $e=$rs->{'e'};
## get filename
my $source_dir = $e->{'const'}->{'source_dir'};
my $created_dir = $e->{'const'}->{'created_dir'};
## up will become the general case. Then the type will not
## be require. I still have to check the xslt
my $glob = $rs->{'path'}.'/'.$source_dir.'/'.$dt."*" ;
my $old_file = $e->{'d'}->get_last_file($glob);
## in case we still store by us/ps/sd
if($old_file == 0) {
my $glob = $rs->{'path'}.'/'.$source_dir.'/'.$type.'/'.$dt."*" ;
# my $old_file = Ernad::Common::get_last_file($glob);
$old_file = $e->{'d'}->get_last_file($glob);
}
## generate new filename, main change of Xmas 2017
my $new_file_name = $rs->generate_file_name( $old_file );
my $new_file = $rs->{'path'}.'/'.$created_dir.'/'.$new_file_name;
## copy
if($old_file =~m|\.gz$|) {
if($e->{'testing'}) {
open(L,'> '.$e->{'dir'}->{'test'}.'/report_state_load.log');
print L "I zcat $old_file to $new_file
\n";
}
system("/bin/zcat $old_file > $new_file");
}
else {
#if($e->{'testing'}) {
# print L "I copy $old_file to $new_file
\n";
#}
copy($old_file, $new_file);
}
## update members
$rs->{'stage'} = $e->{'const'}->{'created_dir'};
$rs->{'file'} = $new_file_name;
$rs->{'rix'} = '';
$rs->save_to_state_file();
}
sub vadoc_file {
my $rs = shift;
my $vadoc_type= shift // confess "I need a vadoc_type here";
my $issuedate=$rs->issuedate() // confess "I can't get the issuedate.";
my $e=$rs->{'e'};
my $vadoc_file=$rs->{'path'}.'/'.$e->{'const'}->{'vadoc_dir'}.'/'.$issuedate.'_'.$vadoc_type.'.xml';
&Krichel::File::prepare($vadoc_file);
$rs->{'vadoc_file'}->{$vadoc_type}=$vadoc_file;
return $vadoc_file;
}
sub delete_vadoc_file {
my $rs = shift;
my $vadoc_type= shift // confess "I need a vadoc_type here";
my $vadoc_file = $rs->{'vadoc_file'}->{$vadoc_type} // return 0;
if(not -f $vadoc_file) {
return 0;
}
unlink $vadoc_file;
}
sub save_vadoc {
my $rs = shift;
my $vadoc_type= shift // confess "I need a vadoc_type here";
my $vadoc=shift;
my $ref_doc=ref $vadoc;
if($ref_doc ne 'XML::LibXML::Document') {
confess "I need a doc here, but you gave me a $ref_doc";
}
my $vadoc_file=$rs->vadoc_file($vadoc_type);
$vadoc->toFile($vadoc_file,1);
return $vadoc;
}
sub load_vadoc {
my $rs = shift;
my $vadoc_type= shift // confess "I need a vadoc_type here";
my $vadoc_file=$rs->vadoc_file($vadoc_type);
if(not -f $vadoc_file) {
return '';
}
my $vadoc=&Krichel::File::load($vadoc_file);
$rs->{'vadoc'}->{$vadoc_type}=$vadoc;
return $vadoc;
}
##
sub issuedate {
my $rs=shift;
my $date=shift // '';
my $e=$rs->{'e'} or confess 'I need an erimp.';
if($date) {
$rs->{'issuedate'}=$date;
return $date;
}
my $file=$rs->{'file'} // '';
if(not $file) {
$rs->{'file'} = $e->{'d'}->most_recent_rif($file);
}
$file=$rs->{'file'} // return 0;
$date=$e->{'f'}->issuedate($file) // '';
if($date) {
$rs->{'issuedate'}=$date;
return $date;
}
confess "I could not find issuedate on '$file'.";
}
## update the editor data
sub update_editor {
my $rs=shift;
my $e=$rs->{'e'} or die 'no erimp';
my $dm=Dumper $rs;
my $rix=$rs->{'rix'} // '' ;
if(not $rix) {
$rs->load_rix();
}
$rix=$rs->{'rix'};
if(not $rix) {
die "no rix";
}
$rs->{'rix'}=$e->{'x'}->update_editor($rix);
# $rix->toFile("/tmp/rix.xml");
}
1;