#!/usr/bin/perl

use strict;
use warnings;

use Getopt::Std;
use Time::Local;
use POSIX qw(strftime);

my $time_format="%Y-%m-%d %H:%M:%S";

sub toUtime {
  my ($date, $time) = @_;

  $date =~ /(\d{4})-(\d{2})-(\d{2})/;
  my ($year, $month, $day) = ($1, $2, $3);

  $time =~ /(\d{2}):(\d{2}):(\d{2})/;
  my ($hour, $min, $sec) = ($1, $2, $3);

  return timelocal($sec,$min,$hour,$day,$month - 1,$year);
}

my %opts = ();

if ( !getopts("c:d:",\%opts) || !$opts{c} || !$opts{d}) {
  printf STDERR "usage $0 -c columns -d duration\n";
  exit(1);
}

my ($columns, $max_duration) = ($opts{c}, $opts{d} * 60 * 60);

my %STATUS = (
  UNKNOWN => 0,
  SHARE => 1,
  LINK => 2,
  IDLE => 4,
);

my $n_hosts = 0;
my %host_status = ();
my %host_name = ();

my %n_jobs = ();
my %job_start = (());
my %job_end = (());
my %job_type = (());
my %job_name = (());

my $start_stamp = 0;
my $time_stamp;

while (<STDIN>) {
  my $line = $_;

  if ($line =~ /(\d{4}-\d{2}-\d{2}) (\d{2}:\d{2}:\d{2}) Started (full|incr) backup on ([^\s]*) \(pid=\d+, share=([^\s]*)\)/) {
    my $host = $4;
    $time_stamp = toUtime($1, $2);

    if (!grep $_ eq $host, %host_name) {
      $start_stamp = $time_stamp if($n_hosts == 0);
      $host_name{$n_hosts} = $host;
      $n_jobs{$host} = 0;

      $n_hosts++;
    } elsif ($host_status{$host} == $STATUS{SHARE}) {
      $job_end{$host}{$n_jobs{$host} - 1} = $time_stamp;
    } elsif ($host_status{$host} != $STATUS{IDLE}) {
      print "error: share starts but status is $host_status{$host}\n";
    }

    $job_start{$host}{$n_jobs{$host}} = $time_stamp;
    $job_end{$host}{$n_jobs{$host}} = 0;
    $job_type{$host}{$n_jobs{$host}} = $3;
    $job_name{$host}{$n_jobs{$host}} = $5;
    $n_jobs{$host}++;

    $host_status{$host} = $STATUS{SHARE};
  } elsif ($line =~ /(\d{4}-\d{2}-\d{2}) (\d{2}:\d{2}:\d{2}) Finished (full|incr) backup on ([^\s]*)/) {
    my $host = $4;
    $time_stamp = toUtime($1, $2);

    if (!grep $_ eq $host, %host_name) {
      $start_stamp = $time_stamp if($n_hosts == 0);
      $host_name{$n_hosts} = $host;
      $n_jobs{$host} = 0;

      $job_start{$host}{$n_jobs{$host}} = 0;
      $job_end{$host}{$n_jobs{$host}} = $time_stamp;
      $job_type{$host}{$n_jobs{$host}} = $3;
      $job_name{$host}{$n_jobs{$host}} = "?";
      $n_jobs{$host}++;

      $n_hosts++;
    } elsif ($host_status{$host} == $STATUS{SHARE}) {
      $job_end{$host}{$n_jobs{$host} - 1} = $time_stamp;
    } else {
      print "error: shares end but status is $host\n" 
    }

    $host_status{$host} = $STATUS{IDLE};
  } elsif ($line =~ /(\d{4}-\d{2}-\d{2}) (\d{2}:\d{2}:\d{2}) Running BackupPC_link ([^\s]*)/) {
    my $host = $3;
    $time_stamp = toUtime($1, $2);

    if (!grep $_ eq $host, %host_name) {
      $start_stamp = $time_stamp if($n_hosts == 0);
      $host_name{$n_hosts} = $host;
      $n_jobs{$host} = 0;

      $n_hosts++;
    } elsif ($host_status{$host} != $STATUS{IDLE}) {
      print "error: link starts but status is $host_status{$host}\n";
    }

    $job_start{$host}{$n_jobs{$host}} = $time_stamp;
    $job_end{$host}{$n_jobs{$host}} = 0;
    $job_type{$host}{$n_jobs{$host}} = "link";
    $job_name{$host}{$n_jobs{$host}} = "link";
    $n_jobs{$host}++;

    $host_status{$host} = $STATUS{LINK};
  } elsif ($line =~ /(\d{4}-\d{2}-\d{2}) (\d{2}:\d{2}:\d{2}) Finished ([^\s]*) \(BackupPC_link/) {
    my $host = $3;
    $time_stamp = toUtime($1, $2);

    if (!grep $_ eq $host, %host_name) {
      $start_stamp = $time_stamp if($n_hosts == 0);
      $host_name{$n_hosts} = $host;
      $n_jobs{$host} = 0;

      $job_start{$host}{$n_jobs{$host}} = 0;
      $job_end{$host}{$n_jobs{$host}} = $time_stamp;
      $job_type{$host}{$n_jobs{$host}} = "link";
      $job_name{$host}{$n_jobs{$host}} = "link";
      $n_jobs{$host}++;

      $n_hosts++;
    } elsif ($host_status{$host} == $STATUS{LINK}) {
      $job_end{$host}{$n_jobs{$host} - 1} = $time_stamp;
    } elsif ($host_status{$host} != $STATUS{LINK}) {
      print "error: link ends but status is $host_status{$host}\n" 
    }

    $host_status{$host} = $STATUS{IDLE}; 
 }
}

my $end_stamp = $start_stamp + $max_duration;
my $scale = $columns / $max_duration;

printf "%10s    %10s -> %10s (%10s)\n","",strftime($time_format, localtime($start_stamp))
                                         ,strftime($time_format, localtime($end_stamp))
                                         ,strftime($time_format, localtime($time_stamp));

sub terminate_row {
  my ($finished, $j, $fill_char, $end_char) = @_;
  if ($finished == 0) {
    for ( ; $j < $columns ; $j++) {
      printf STDOUT "%s", $fill_char;
    }
    printf STDOUT "%s", $end_char;
  }
  return 1;
}

if ( 1 ) {
  for (my $h = 0 ; $h < $n_hosts ; $h++ ) {
    my $host = $host_name{$h};
    printf STDOUT "%10s %d: %s",$host,$n_jobs{$host},($job_start{$host}{0} == 0) ? "<" : "|";
    my $finished = 0;
    my $j = 0;
    for (my $job = 0 ; $job < $n_jobs{$host} ; $job++) {
      if ($job_start{$host}{$job} < $end_stamp) {
        for ( ; $j < $columns && $j < ( $job_start{$host}{$job} - $start_stamp ) * $scale ; $j++) {
          printf STDOUT " ";
        }
        if ($job_end{$host}{$job} == 0 || $job_end{$host}{$job} > $end_stamp) {
          $finished = terminate_row($finished, $j, uc(substr($job_type{$host}{$job},0,1)), ">");
        } else {
          my $end = $job_end{$host}{$job};
          if ($j >= ( $end - $start_stamp ) * $scale) {
            printf STDOUT "%s", lc(substr($job_type{$host}{$job},0,1));
            $j++;
          } else {
            for ( ; $j < $columns && $j < ( $end - $start_stamp ) * $scale ; $j++) {
              printf STDOUT "%s", uc(substr($job_type{$host}{$job},0,1));
            }
          }
        }
      } else {
        $finished = terminate_row($finished, $j, " ", "|");
        printf STDOUT ">";
      }
    }
    $finished = terminate_row($finished, $j, " ", "|");
    printf STDOUT "\n";
  }
} else {
  for (my $h = 0 ; $h < $n_hosts ; $h++ ) {
    my $host = $host_name{$h};
    for (my $job = 0 ; $job < $n_jobs{$host} ; $job++) {
      printf STDOUT "%10s %d: %d -> %d (%s)\n",$host,$job,$job_start{$host}{$job},$job_end{$host}{$job},$job_name{$host}{$job};
    }
  }
}















