package Data::Tubes::Plugin::Writer;

# vim: ts=3 sts=3 sw=3 et ai :

use strict;
use warnings;
use English qw< -no_match_vars >;
use POSIX qw< strftime >;
our $VERSION = '0.738';

use Log::Log4perl::Tiny qw< :easy :dead_if_first LOGLEVEL >;
use Template::Perlish;

use Data::Tubes::Util
  qw< normalize_args read_file_maybe shorter_sub_names sprintffy >;
use Data::Tubes::Plugin::Util qw< identify log_helper >;
use Data::Tubes::Plugin::Plumbing;
my %global_defaults = (input => 'rendered',);

sub _filenames_generator {
   my $template = shift;

   my $n             = 0; # counter, used in closures inside $substitutions
   my $substitutions = [
      [qr{(\d*)n} => sub { return sprintf "%${1}d",    $n; }],
      [qr{Y}      => sub { return strftime('%Y',       localtime()); }],
      [qr{m}      => sub { return strftime('%m',       localtime()); }],
      [qr{d}      => sub { return strftime('%d',       localtime()); }],
      [qr{H}      => sub { return strftime('%H',       localtime()); }],
      [qr{M}      => sub { return strftime('%M',       localtime()); }],
      [qr{S}      => sub { return strftime('%S',       localtime()); }],
      [qr{z}      => sub { return strftime('%z',       localtime()); }],
      [qr{D}      => sub { return strftime('%Y%m%d',   localtime()); }],
      [qr{T}      => sub { return strftime('%H%M%S%z', localtime()); }],
      [qr{t} => sub { return strftime('%Y%m%dT%H%M%S%z', localtime()); }],
   ];

   # see if the template depends on the counter
   my $expanded = sprintffy($template, $substitutions);
   return sub {
      my $retval = sprintffy($template, $substitutions);
      ++$n;
      return $retval;
     }
     if ($expanded ne $template);    # it does!

   # then, by default, revert to poor's man expansion of name...
   return sub {
      my $retval = $n ? "${template}_$n" : $template;
      ++$n;
      return $retval;
   };
} ## end sub _filenames_generator

sub dispatch_to_files {
   my %args = normalize_args(
      @_,
      [
         {
            %global_defaults,
            name    => 'write dispatcher',
            binmode => ':encoding(UTF-8)'
         },
         'filename'
      ],
   );
   identify(\%args);
   my $name = delete $args{name};    # so that it can be overridden

   if (defined(my $filename = delete $args{filename})) {
      my $ref = ref $filename;
      if (!$ref) {
         $args{filename_template} //= $filename;
      }
      elsif ($ref eq 'CODE') {
         $args{filename_factory} //= $filename;
      }
      else {
         LOGDIE "argument filename has invalid type $ref";
      }
   } ## end if (defined(my $filename...))

   my $factory = delete $args{filename_factory};
   if (!defined($factory) && defined($args{filename_template})) {
      my $tp = Template::Perlish->new(%{$args{tp_opts} || {}});
      my $template = $tp->compile($args{filename_template});
      $factory = sub {
         my ($key, $record) = @_;
         return $tp->evaluate($template, {key => $key, record => $record});
      };
   } ## end if (!defined($factory)...)

   $args{factory} //= sub {
      my $filename = $factory->(@_);
      return write_to_files(%args, filename => $filename);
   };

   return Data::Tubes::Plugin::Plumbing::dispatch(%args);
} ## end sub dispatch_to_files

sub write_to_files {
   my %args = normalize_args(
      @_,
      [
         {
            %global_defaults,
            name     => 'write to file',
            binmode  => ':encoding(UTF-8)',
            filename => \*STDOUT,
         },
         'filename'
      ],
   );
   identify(\%args);
   my $name = $args{name};
   LOGDIE "$name: need a filename" unless defined $args{filename};
   LOGDIE "$name: need an input"   unless defined $args{input};

   my $output = $args{filename};
   $output = _filenames_generator($output) unless ref($output);

   my %oha =
     map { ($_ => $args{$_}) }
     grep { defined $args{$_} } qw< binmode policy >;
   for my $marker (qw< footer header interlude >) {
      $oha{$marker} = read_file_maybe($args{$marker})
        if defined $args{$marker};
   }
   require Data::Tubes::Util::Output;
   my $output_handler =
     Data::Tubes::Util::Output->new(%oha, output => $output,);

   my $input = $args{input};
   return sub {
      my $record = shift;
      $output_handler->print($record->{$input});
      return $record;    # relaunch for further processing
   };
} ## end sub write_to_files

shorter_sub_names(__PACKAGE__, 'write_');

1;
