#!/usr/bin/env perl
# @(#)Ident: gitpre-commit 2013-04-12 11:26 pjf ;

use strict;
use warnings;
use lib qw(lib);
use version; our $VERSION = qv( '0.1' );

use Date::Format          qw(time2str);
use English               qw(-no_match_vars);
use File::Spec::Functions qw(catfile updir);
use Module::Metadata;
use Perl::Version;

sub __read_all_from ($) {
   my $path = shift;

   open my $fh, '<', $path or die 'Path ${path} cannot open: ${OS_ERROR}';

   local $RS = undef; my $content = <$fh>; close $fh; return $content;
}

sub __write_data_to ($$) {
   my ($path, $data) = @_;

   open my $fh, '>', $path or die "Path ${path} cannot open: ${OS_ERROR}";

   print {$fh} $data; close $fh; return;
}

sub __get_ignore_rev_regex () {
   my $ignore_rev_file = '.gitignore-rev'; -f $ignore_rev_file or return;

   my $paths = __read_all_from $ignore_rev_file; chomp $paths;

   return join '|', split m{ [\n] }mx, $paths;
}

my ($module, $rev, $rev_file);

my $project_file = -f 'Build.PL'    ? 'Build.PL'    :
                   -f 'Makefile.PL' ? 'Makefile.PL' : undef;

if (defined $project_file) {
   my $content  = __read_all_from $project_file;

   $module = (map    { eval $_ }
              map    { m{ \A \s* (?:module|name) \s* => \s* (.+) [,] }imx }
              grep   { m{ \A \s*   (module|name) }imx }
              split m{ [\n] }mx, $content)[ 0 ];

   my $distname = lc $module; $distname =~ s{ :: }{-}gmx;

   $rev_file = catfile( updir, ".${distname}.rev" );

   if (-f $rev_file) { $rev = __read_all_from $rev_file; chomp $rev; $rev++ }
}

if (defined $rev and qx{ git branch 2>/dev/null } =~ m{ \A [*] \s+ master }mx) {
   my @stat   = split m{ \n }mx, qx{ git status --porcelain };
   my $ignore = __get_ignore_rev_regex;
   my $found  = 0;

   for my $path (map { s{ \A .+ \s+ }{}mx; $_ } grep { m{ \A [AM] }mx } @stat) {
      $ignore and $path =~ m{ (?: $ignore ) }mx and next;

      my $content = __read_all_from $path;

      $content =~ m{ \$ (Rev (?:ision)?) (?:[:] \s+ (\d+) \s+)? \$ }mx or next;
      $content =~ s{ \$ (Rev (?:ision)?) (?:[:] \s+ (\d+) \s+)? \$ }{\$$1\$}gmx;
      $rev < ($2 || 0) + 1 and $rev = ($2 || 0) + 1;
      $content =~ s{ \$ (Rev (?:ision)?) \$ }{\$$1: $rev \$}gmx;
      __write_data_to $path, $content;

      my $cmd = "git add ${path}"; qx{ $cmd }; $found = 1;
   }

   $found and __write_data_to $rev_file, "${rev}\n";
}

my $changes_file = 'Changes';

if (-f $changes_file) {
   my $changes     = __read_all_from $changes_file;
   my $changes_ver = qv( (split q( ),
                          (grep { m{ \A v?[0-9._]+ }mx } split m{ [\n] }mx,
                           $changes)[ 0 ] || q())[ 0 ] || '0.1.1' );
   my $meta        = defined $module
                   ? Module::Metadata->new_from_module( $module ) : undef;
   my $module_ver  = $meta ? $meta->version : qv( '0.1.1' );

   $meta or warn "No meta object for module ${module}";

   if ($module_ver > $changes_ver) {
      my $stamp  = time2str( '%Y-%m-%d %H:%M:%S', time );
      my $header = sprintf "%-9.9s %s", $module_ver, $stamp;
      my $pmv    = Perl::Version->new( $module_ver  ); $pmv->components( 2 );
      my $pcv    = Perl::Version->new( $changes_ver ); $pcv->components( 2 );

      if ($pmv > $pcv) { $changes =~ s{ ^ $ }{\n$header}mx }
      else { $changes =~ s{ ^ v?[0-9._]+ \s* [^\n]* $ }{$header}mx }

      __write_data_to $changes_file, $changes;

      my $cmd = "git add ${changes_file}"; qx{ $cmd };
   }
}

exit 0;
