#!/usr/bin/perl -w

use strict;
use utf8;
use warnings;

our $pophome;
BEGIN {
    $pophome = $ENV{POPHOME} || '@POPHOME@';
    unshift @INC, "$pophome/lib"
      unless $ENV{KUNDE_NO_PERLPATH};
}

use Encode qw(encode);
use Getopt::Long qw(GetOptions);
use Umlaut;

my $AngrenzendeMonate = 1;
GetOptions(
    'angrenzende-monate=i' => sub {
        ( my $option, $AngrenzendeMonate ) = @_;
        die "-$option akzeptiert nur natürliche Zahlen oder 0.\n"
          if $AngrenzendeMonate < 0;
    },
    'chart=s'        => \my $Chart,
    'chart-height=i' => \( my $ChartHeight = 900 ),
    'chart-type=s'   => \( my $ChartType = 'LinesPoints' ),
    'chart-width=i'  => \( my $ChartWidth = 1272 ),
    'max-kunden=i'   => \( my $MaxKunden = 10 ),
    'max-monate=i'   => \( my $MaxMonate = 24 ),
    'min-stunden=f'  => \( my $MinStunden = 8 ),
    'verbose!'       => \( my $Verbose = -t STDERR ),
    'help|?'         => sub {
        exec perldoc => -F => $0
          or die qq(Kann "perldoc -F $0" nicht ausführen: $!\n);
    },
) or exit 1;

sub jjjj_mm($$) { sprintf '%d-%02d', @_ }

sub vormonat($) {
    my ( $jahr, $monat ) = split /-/, shift, 2;
    unless ( --$monat ) {
        $monat = 12;
        $jahr--;
    }
    jjjj_mm( $jahr, $monat );
}

my $zeit_seit = vormonat(
    my $zeit_vor = do {
        my ( $jahr, $monat ) = (localtime)[ 5, 4 ];
        jjjj_mm( $jahr + 1900, $monat + 1 );
      }
);

my ( %zeit4kunde, @monate );
Monat: while () {

    print STDERR "$zeit_seit... " if $Verbose;
    open my $a4t,
"$pophome/bin/arbeitszeit4tickets -zeit-seit $zeit_seit-01 -zeit-vor $zeit_vor-01 -zeit-fuer-alle-kunden -ohne-kunde POP -ohne-kunde ito"
      . join( '', map " -kunde $_", keys %zeit4kunde )
      . " | csv-filter -column Kunde -column 'Arbeitszeit mit Faktoren (s)' -output-separator '\t' |"
      or die "Fehler beim Aufruf von arbeitszeit4tickets für $zeit_seit: $!\n";

    <$a4t> eq "Kunde\tArbeitszeit mit Faktoren (s)\n" or die;

    splice @$_, 1, 0, 0 for values %zeit4kunde;

    while ( defined( my $ticket = <$a4t> ) ) {
        chomp $ticket;
        my ( $kunde, $sekunden ) = split "\t", $ticket;
        if ( $kunde eq '' ) {
            printf STDERR "%.f\n", $sekunden / 3600 if $Verbose;
            last Monat unless $sekunden;
        }
        else {
            $zeit4kunde{$kunde} ||= [ 0, 0 ];
            $zeit4kunde{$kunde}[$_] += $sekunden for 0, 1;
        }
    }
}
continue {
    unshift @monate, $zeit_seit;
    if ( @monate == 1 and $MinStunden || $MaxKunden ) {
        if ($MinStunden) {
            my $min_sekunden = $MinStunden * 3600;
            while ( my ( $kunde, $zeit ) = each %zeit4kunde ) {
                delete $zeit4kunde{$kunde} if $zeit->[0] < $min_sekunden;
            }
        }
        delete @zeit4kunde{
            (
                sort { $zeit4kunde{$b}[0] <=> $zeit4kunde{$a}[0] }
                  keys %zeit4kunde
              )[ $MaxKunden .. keys(%zeit4kunde) - 1 ]
          }
          if $MaxKunden && keys %zeit4kunde > $MaxKunden;
        print STDERR 'Kunden: ' . join( ', ', sort keys %zeit4kunde ) . "\n"
          if $Verbose;
    }
    last if $MaxMonate && @monate >= $MaxMonate;
    $zeit_seit = vormonat( $zeit_vor = $zeit_seit );
}

unless ( defined $Chart && $Chart eq '-' ) {
    print join( ',', 'Kunde', @monate ) . "\n";
    print join( ',',
        $_,
        map sprintf( '%.f', $_ / 3600 ),
        @{ $zeit4kunde{$_} }[ 1 .. @monate ] )
      . "\n"
      for sort { $zeit4kunde{$b}[0] <=> $zeit4kunde{$a}[0] } keys %zeit4kunde;
}

if ( defined $Chart ) {
    if ($AngrenzendeMonate) {
        print STDERR 'Berechne gleitende Durchschnitte...' if $Verbose;
        require List::Util and List::Util->import('sum');
        while ( my ( $kunde, $zeit4kunde ) = each %zeit4kunde ) {
            my @zeiten = $zeit4kunde->[0];
            for ( 1 .. @monate ) {
                my $min_monat = $_ - $AngrenzendeMonate;
                $min_monat = 1 if $min_monat < 1;
                my $max_monat = $_ + $AngrenzendeMonate;
                $max_monat = @monate if $max_monat > @monate;
                push @zeiten,
                  sum( @{$zeit4kunde}[ $min_monat .. $max_monat ] ) /
                  ( 1 + $max_monat - $min_monat );
            }
            @$zeit4kunde = @zeiten;
        }
        print STDERR " erledigt.\n" if $Verbose;
    }

    eval 'require ' . ( my $chart_module = "Chart::$ChartType" );
    my @kunden =
      sort { $zeit4kunde{$b}[0] <=> $zeit4kunde{$a}[0] } keys %zeit4kunde;
    my $chart = $chart_module->new( $ChartWidth, $ChartHeight );
    $chart->set(
        colors          => { dataset0 => [ 0,          0, 0 ] },
        f_y_tick        => sub        { sprintf '%.f', shift },
        gif_border      => 0,
        grey_background => 0,
        legend          => 'bottom',
        legend_labels   => \@kunden,
        title           => encode(
            latin1 => "Arbeitszeit nach Kunden für $monate[0] bis $monate[-1]"
              . (
                $AngrenzendeMonate > 0
                  && ' (gleitende '
                  . ( 1 + ( $AngrenzendeMonate << 1 ) )
                  . 'er-Durchschnitte)'
              )
        ),
        y_label => 'Stunden'
    );
    $chart->png(
        $Chart,
        [
            \@monate,
            map [ map $_ / 3600, @{ $zeit4kunde{$_} }[ 1 .. @monate ] ], @kunden
        ]
    );
    exit if $Chart eq '-';
}

__END__

=encoding utf8

=head1 NAME

stunden-statistik - Statistik zu auf Tickets gebuchte Arbeitszeit nach Kunden

=head1 SYNOPSE

    stunden-statistik -max-monate 12

=head1 BESCHREIBUNG

Das Script gibt auf der Standardausgabe eine CSV-Tabelle aus, die für diejenigen
Kunden, auf die im vergangenen Monat die meiste Arbeitszeit auf Tickets gebucht
wurde, den Verlauf der gebuchten Arbeitszeit pro Monat in den letzten Monaten
enthält.

=head1 OPTIONEN

=over 4

=item -max-monate Anzahl

maximal die C<Anzahl> vergangenen Monate auswerten.

Ansonsten bricht das Script erst ab, wenn es für einen Monat gar keine
Arbeitszeit mehr findet.

Default: 24

=item -max-kunden Anzahl

Auswertung für maximal C<Anzahl> Kunden (mit der meisten auf Tickets gebuchten
Arbeitszeit im vergangenen Monat)

Default: 10

=item -min-stunden Anzahl

Auswertung nur für Kunden, auf deren Tickets im vergangenen Monat mindestens so
viele Stunden gebucht wurden

Default: 8

=item -verbose

um Fortschrittsinformationen auf der Standardfehlerausgabe zu bekommen.
Ist per Default an, wenn diese auf ein Terminal zeigt.

=item -noverbose

um die Anzeige von Fortschrittsinformationen auf der Standardfehlerausgabe zu
unterdrücken

=item -angrenzende-monate Anzahl

als Wert jedes Monats im Diagramm den Durchschnitt der Werte aus dem Monat
selbst sowie jeweils der Anzahl Monate davor und danach einzeichnen.
(Für die ersten und letzten Monate wird abweichend davon ein Durchschnitt aus
weniger Werten gebildet.)

Default: 1, also gleitende 3er-Durchschnitte

=item -chart Datei

Diagramm als PNG in angegebene Datei ausgeben

=item -chart-type Typ

zur Erzeugung des L</-chart Datei|Diagramms> zu verwendendes Chart::*-Modul.
Default: C<LinesPoints>

=item -chart-width Pixel

Breite des L</-chart Datei|Diagramms>; Default: 1272

=item -chart-height Pixel

Höhe des L</-chart Datei|Diagramms>; Default: 900

=item -help

=item -?

um (nur) diese Dokumentation anzeigen zu lassen

=back

=head1 BEKANNTE FEHLER

=over 4

=item *

Es wird generell nur Arbeitszeit ausgewertet, die auf Tickets gebucht wurde.

=item *

Die Zuordnung der Arbeitszeit erfolgt anhand des Kunden des jeweiligen Tickets,
nicht nach dem in der Zeiterfassung eingetragenen Kunden.

=back

=head1 AUTOR

 Martin H. Sluka <fany@noris.net>
 für die noris network AG
