#!/usr/bin/env perl

use strict;
use POSIX;
use Tie::File;
use Pod::Usage;
use Getopt::Long;
use File::Basename;
use FindBin qw( $Bin $Script );

our $PACK = dirname( $Bin );
our @MODULE = ( split '-', basename( $PACK ) )[0];
pop @MODULE if $MODULE[-1] =~ /^\d+.+?\d+$/;
our $MODULE = join( '/', @MODULE ) . '.pm';

$| ++;

our ( %PREREQ_PM, @INSTALL );
our ( $HIST, $MAKE, $LIST, $INST ) = qw( Changes Makefile.PL MANIFEST .install );

my %o;
Pod::Usage::pod2usage( -input => $0, -output => \*STDERR, -verbose => 2 )
    if ! Getopt::Long::GetOptions( \%o, qw( install=s dist prereq bump=s ) );

=head3 install prerequisite modules

 $0 --prereq

=cut
prereq() if $o{prereq};
load();

if ( $o{dist} || $o{install} )
{
    makefile();
    make();

=head1 SYNOPSIS

=head3 distro

 $0 --dist

=cut
    if ( $o{dist} ) { make( dist => 0 ) } 
=head3 install

 $0 --install /install/path

=cut
    else { install( $o{install} ) }
}
=head3 update

 $0 [--bump minor]

 $0 [--bump major]

=cut
elsif( ! $o{prereq} )
{
    version( $o{bump} );
    manifest();
    changes();
}

exit 0;

sub load
{
    chdir $PACK;
    system "cd $PACK";

    @INSTALL = `cat $INST`; 
    chomp @INSTALL;
}

sub makefile
{
    exit 1 if system "$^X $MAKE";
}

sub prereq
{
    do "$PACK/$MAKE";
    exit 1 if grep { system "$Bin/cpanm --sudo $_" } keys %PREREQ_PM;
}

sub install
{
    return unless my $dir = shift;
    return unless @INSTALL;

    my $mkdir = "mkdir -p $dir";
    my $untar = "tar xvf - )";
    my $tar = "tar cf - @INSTALL | ( cd $dir; ";

    make( install => 1 );
    map { $_ = "sudo $_" } $mkdir, $untar unless canwrite( $dir );
    exit 1 if system( $mkdir ) || system( $tar . $untar )
        || system( "cd $dir && sudo chown -R root:root @INSTALL" );
}

sub make
{
    my ( $rule, $sudo ) = splice @_;
    my $make = 'make';

    $make = "$make $rule" if $rule;
    $make = "sudo $make" if $sudo;
    exit 1 if system $make;
}

sub version
{
    my $path = "$PACK/lib/$MODULE";
    require $path;

    my $bump = shift;
    my $version = eval '$' . join '::', @MODULE, 'VERSION';

    if ( $bump && ( my @version = $version =~ /(\d+)\.(\d+)/ ) )
    {
        if ( lc $bump eq 'minor' ) { $version[-1] ++ }
        else { $version[-1] =~ s/./0/g; $version[0] ++ }

        system sprintf "$^X -pi -e 's/$version/%s/' $path",
            ( $version = join '.', @version );
    }

    my $time = POSIX::strftime( '%Y.%m.%d', localtime( ( stat $path )[9] ) );

    tie my @hist, 'Tie::File', $HIST;
    for ( my $i = 0; $i < @hist; $i ++ )
    {
        next unless $hist[$i] =~ /^(\d+\S+)/;
        last if $1 eq $version;
        splice @hist, $i, 0, "$version    $time\n\n"; last;
    }
    untie @hist;
}

sub manifest
{
    die $! unless open my $handle, '>', $LIST;
    map { print $handle "$_\n" } 'README', $HIST, $MAKE, $LIST, $INST;
    print $handle `find lib t @INSTALL -type f -not -name .*.swp`;
    close $handle;
}

sub changes
{
    system "vi $HIST && cat $LIST"; ## update changes
    warn << "MEMO";

Be sure that the following are up to date.

    VERSION and MODULES in $MODULE and PREREQ_PM in $MAKE

MEMO
}

sub canwrite
{
    my $dir = shift;
    $dir = dirname( $dir ) while ! -e $dir;
    return -w $dir;
}
