package Ernad::Learn::Isink; use strict; use warnings; use Carp qw(cluck longmess shortmess croak confess); use Data::Dumper; use File::Slurper; use File::Path; use List::Util qw(shuffle); use Ernad::Erimp; use Ernad::Files; use Ernad::Learn::Common; my $exfit_ext='.txt'; binmode(STDOUT,':utf8'); ## constructor sub new { my $this=shift; my $class=ref($this) || $this; my $i={}; bless $i, $class; my $params=shift; ## copy parameters into the object foreach my $key (keys %{$params}) { $i->{$key}=$params->{$key}; } if(not defined($i->{'impna'})) { confess "I need an impna here."; } if(not defined($i->{'e'})) { $i->{'e'}=Ernad::Erimp->new({'impna' => $i->{'impna'}, 'verbose' => $i->{'verbose'}}); } &Ernad::Learn::Common::set_basic($i); $i->{'dir'}->{'isink'}=$i->{'learn_dir'}.'/isink'; ## I only used this for separated doklis $i->{'dir'}->{'alink'}=$i->{'learn_dir'}.'/alink'; ## an isisker is a style that makes an isisk. This seems obsolete: $i->set_isinkers(); return $i; } ## main function. It makes sure it updates. ## this sholud be deprecate sub list_isink_files { my $i=shift; my $repcode=shift // confess "I need a repcode here."; ## if it's 'alink' we have to say so explicitly my $type=shift // 'isink'; my $isink_dir_name=$i->{'dir'}->{$type}.'/'.$repcode; my $isink_dir; if(not -d $isink_dir_name) { mkpath($isink_dir_name); } opendir( $isink_dir, $isink_dir_name) or confess "I can't open $isink_dir_name."; my $e=$i->{'e'} // confess "I need an erimp here."; $e->echo(__LINE__,"Updating isink files",1); $i->update_isinks($repcode,$type); my $learnable_dates=$e->{'report'}->{$repcode}->{'learnable_issuedates'} // ''; while (my $file = readdir $isink_dir ) { if(not $file=~m|(\d{4}-\d{2}-\d{2})\.txt$|) { $i->{'e'}->echo(__LINE__,"I'm skipping file $file when looking for isink files.",4); next; } my $issuedate=$1; if($learnable_dates and not defined($learnable_dates->{$issuedate})) { $e->echo(__LINE__,"I skip the non-learnable issuedate $issuedate."); } $i->{'file'}->{$type}->{$repcode}->{$issuedate}=$isink_dir_name.'/'.$file; } return $i->{'file'}->{$type}->{$repcode}; } ## works for both allport and not allport sub update_isinks { my $i=shift; my $repcode=shift or confess "I need a repcode here"; my $type = shift // 'isink'; my $e=$i->{'e'}; $e->echo(__LINE__,"I am updating isinks for $repcode.",2); my $to_update=$i->find_issuedates_to_update($repcode); foreach my $issuedate (sort keys %{$to_update}) { $i->{'e'}->echo(__LINE__,"I update $type for $repcode for $issuedate",1); if($e->{'conf'}->{'separate_doklis'}) { if($type eq 'alink') { $i->update_alink_for_issuedate($repcode,$issuedate); } elsif($type eq 'isink') { $i->update_isink_for_issuedate($repcode,$issuedate); } else { confess "I don't know the type '$type'"; } } ## default case, non-separating else { if($repcode eq $i->{'allport'}) { $i->update_alink_for_issuedate($repcode,$issuedate); } else { $i->update_isink_for_issuedate($repcode,$issuedate); } } } } # seems useless #sub update_alinks { # my $i=shift; # my $repcode=$i->{'allport'} or confess "I need the allport set here"; # my $to_update=$i->find_issuedates_to_update($repcode); # foreach my $issuedate (keys %{$to_update}) { # $i->{'e'}->echo(__LINE__,"I update alink for $issuedate",4); # $i->make_alink_for_issuedate($issuedate); # } #} ## works for both alinks and isinks sub find_issuedates_to_update { my $i=shift; my $repcode=shift or confess "I need a repcode here"; my $rerc=$i->{'e'}->{'report'}->{$repcode} or confess "I don't know the report $repcode."; my $sent_dir=$rerc->{'dir'}->{'sent'}; $i->{'e'}->echo(__LINE__,"repcode is $repcode",4); my $rifs=&Ernad::Common::get_latest_rif_from_each_issue_in_dir($sent_dir); my $to_update={}; foreach my $rif (@$rifs) { my $issuedate=&Ernad::Common::find_issuedate_from_file($rif); ## if this is not an issuedate we work with ###if(not $i->{'issuedates'}->{$issuedate}) { ### $i->{'e'}->echo(__LINE__,"I skip $issuedate, it is not in range.",4); ### next; ###} my $out_file=$i->{'dir'}->{'isink'}.'/'.$repcode.'/'.$issuedate.'.txt'; $i->{'e'}->echo(__LINE__,"out_file is $out_file",10); if(-f $out_file and -M $out_file < -M $rif) { $i->{'e'}->echo(__LINE__,"out_file is is more recent that $rif, next",10); next; } $to_update->{$issuedate}=1; } return $to_update; } sub update_isink_for_issuedate { my $i=shift; my $repcode=shift or confess "I need a repcode here"; my $issuedate=shift; my $rerc=$i->{'e'}->{'report'}->{$repcode} or confess "I have no clue about report $repcode."; $i->find_issuedates_to_update($repcode); my $isinker=$i->{'isinker'}->{$repcode} or confess "I need a isinker for report $repcode here"; ## there is only my $isink_file=$i->{'dir'}->{'isink'}.'/'.$repcode.'/'.$issuedate.'.txt'; my $sent_dir=$rerc->{'dir'}->{'sent'}; my $sent_rif=&Ernad::Common::get_latest_rif($sent_dir,$issuedate); my $inkst=$i->{'e'}->transform_file_to_text($sent_rif,$isinker); my $alink=$i->get_alink($issuedate) or confess "I need some alink here"; if($inkst=~m|^\s*$|) { #print "inkst is blank\n"; my $isink=$alink; $isink=~s|0 # |-1 # |g; &File::Slurper::write_text($isink_file,$isink); } else { my $selected_dir=$rerc->{'dir'}->{'selected'}; my $rif=&Ernad::Common::get_latest_rif($selected_dir,$issuedate) // ''; if(not $rif) { $i->{'e'}->echo(__LINE__,"WARN: There is no selected_rif for $issuedate of $repcode."); $rif=$sent_rif; } my $inkst=$i->{'e'}->transform_file_to_text($rif,$isinker); my $alink=$i->get_alink($issuedate); my $isink=$i->inkst_from_alink($alink,$inkst); &File::Slurper::write_text($isink_file,$isink); $i->{'e'}->echo(__LINE__,"I write file $isink_file"); } } ## does it for a give issueda sub make_alink_for_issuedate { my $i=shift; my $issuedate=shift // confess "I need an issuedate here."; my $e=$i->{'e'} // confess "I don't see the erimp erimp"; my $repcode=$i->{'repcode'} // confess "I need a repcode here."; $i->{'e'}->echo(__LINE__,"I make the alink $repcode $issuedate"); my $rerc=$e->{'report'}->{$repcode}; ## the repcode we need to make the alinks for my $allcode; if($e->{'conf'}->{'separate_doklis'}) { $allcode=$e->{'repcode'} // confess "I need a repcode here"; } ## default, non separating else { $allcode=$i->{'allport'} or confess "I need the allport set here"; } $i->find_issuedates_to_update($allcode); my $isinker=$i->{'isinker'}->{$allcode} or confess "I need a isinker for report $allcode here"; my $alink_file=$i->{'dir'}->{'alink'}.'/'.$allcode.'/'.$issuedate.'.txt'; &Ernad::Common::prepare_for_file($alink_file); my $source_dir=$rerc->{'dir'}->{'source'}; my $source_rif=&Ernad::Common::get_latest_rif_with_subdir($source_dir,$issuedate); my $inkst=$i->{'e'}->transform_file_to_text($source_rif,$isinker); &File::Slurper::write_text($alink_file,$inkst); return $alink_file; } sub inkst_from_alink { my $i=shift; my $alink=shift; my $inkst=shift; my $included; my $out=''; foreach my $line (split("\n",$inkst)) { my $handle=substr($line,5); $included->{$handle}=1; $i->{'e'}->echo(__LINE__,"I find $handle in isink."); } ## the position of the handle in the alink my $apos; if($i->{'e'}->{'conf'}->{'separate_doklis'}) { $apos=5; } else { $apos=4; } foreach my $line (split("\n",$alink)) { my $handle=substr($line,$apos); $i->{'e'}->echo(__LINE__,"I find '$handle' in alink."); if(defined($included->{$handle})) { $out.="+1 # $handle\n"; delete $included->{$handle}; } else { $out.="-1 # $handle\n"; } } my $count_remaining=scalar keys (%$included); if($count_remaining) { my $print_remaining=Dumper $included; $i->{'e'}->echo(__LINE__,"WARN: Some papers in the report are not in the allport:\n$print_remaining"); confess; } return $out; } sub get_alink { my $i=shift; my $e=$i->{'e'}; my $issuedate=shift or confess "I need an issuedate here."; if(defined($i->{'alink'}->{$issuedate})) { return $i->{'alink'}->{$issuedate}; } my $repcode=$e->{'repcode'} // $e->get_allport_repcode(); my $alink_dir=$i->{'dir'}->{'alink'} // confess "I need an alink dir defined here."; my $alink_file=$i->{'dir'}->{'alink'}.'/'.$repcode.'/'.$issuedate.'.txt'; if(not -f $alink_file) { $alink_file=$i->make_alink_for_issuedate($issuedate); } if(not -f $alink_file) { confess "I have failed to make the alink_file $alink_file"; } $i->{'e'}->echo(__LINE__,"I read alinks from $alink_file"); my $alink=&File::Slurper::read_text($alink_file); $i->{'alink'}->{$issuedate}=$alink; return $alink; } sub set_isinkers { my $i=shift; my $style_dir=$i->{'e'}->{'dir'}->{'style'}.'/isink' // confess "I need an isinker style directory here."; if(not -d $style_dir) { confess "I can't open the directory '$style_dir'"; } my @reports=keys %{$i->{'e'}->{'report'}}; my $ext=$i->{'e'}->{'const'}->{'xsl_ext'}; $i->{'style_dir'}=$style_dir; foreach my $repcode (@reports) { my $style_file=$i->{'style_dir'}.'/'.$repcode.$ext; if(-f $style_file) { $i->{'isinker'}->{$repcode}='isink/'.$repcode; $i->{'isinker_file'}->{$repcode}=$style_dir.'/'.$repcode.$ext; } else { $i->{'isinker'}->{$repcode}='isink/isink'; $i->{'isinker_file'}->{$repcode}=$style_dir.'/isink'.$ext; } } } 1;