#!/usr/bin/perl

# Created on: 2008-01-16 08:05:58
# Create by:  ivanw
# $Id$
# $Revision$, $HeadURL$, $Date$
# $Revision$, $Source$, $Date$

use strict;
use warnings;
use version;
use Scalar::Util;
use List::Util qw/max/;
use Getopt::Long;
use Pod::Usage;
use Data::Dumper qw/Dumper/;
use English qw/ -no_match_vars /;
use FindBin qw/$Bin/;
use VCS::Which;
use IO::Prompt qw/prompt/;
use Path::Class;

our $VERSION = version->new('0.3.0');
my ($name)   = $PROGRAM_NAME =~ m{^.*/(.*?)$}mxs;

my %option = (
    revision => '',
    verbose  => 0,
    man      => 0,
    help     => 0,
    VERSION  => 0,
);

if ( !@ARGV ) {
    pod2usage( -verbose => 1 );
}

main();
exit 0;

sub main {

    Getopt::Long::Configure('bundling');
    GetOptions(
        \%option,
        'file|f=s',
        'revision|r=s',
        'change|c=i',
        'replay|R',
        'max|m=i',
        'test|t!',
        'verbose|v+',
        'man',
        'help',
        'VERSION!',
    ) or pod2usage(2);
    $option{'file'} ||= shift @ARGV;

    if ( $option{'VERSION'} ) {
        print "$name Version = $VERSION\n";
        exit 1;
    }
    elsif ( $option{'man'} ) {
        pod2usage( -verbose => 2 );
    }
    elsif ( $option{'help'} || !-e $option{'file'} ) {
        pod2usage( -verbose => 1 );
    }

    # sort out the revision names
    my ( $rev_old, $rev_new ) = ('', '');
    if ( $option{'revision'} ) {
        ($rev_old, $rev_new) =
            $option{'revision'} =~ /:/xms ? ( split /:/xms, $option{'revision'} )
            :                               ( $option{'revision'} );
    }

    if ( $option{'change'} ) {
        ( $rev_old, $rev_new ) =
            $option{'change'} > 0 ? ( $option{'change'} - 1, $option{'change'} )
            :                       ( $option{'change'}, $option{'change'} - 1 );
        $option{'revision'} = "$rev_old\:$rev_new";
    }

    # create the temporary file object name
    my $tmp = "/tmp/$$.$name." . file($option{'file'})->basename;

    # create a new VCS::Which object for the file of interest
    my $vcs = VCS::Which->new(dir => $option{file});

    if ($option{replay}) {
        my $first = 1;
        my @versions = $vcs->versions($option{file}, $rev_old ? $rev_old : 0, $option{max});
        if ( $option{verbose} ) {
            my $i = 0;
            my $j = -2;
            print map {$i++ . "\t" . $j-- . "\t$_\n"} @versions;
        }

        while (
            @versions
            && (
                $first
                || prompt("Next revision $versions[-1]: Continue? ", -nd => 'y')
            )
        ) {
            $first = 0;
            unlink "$tmp.$rev_old" if -e "$tmp.$rev_old";
            $rev_old = pop @versions;
            write_file( "$tmp.$rev_old", scalar $vcs->cat($option{file}, $rev_old) );
            if ($option{test} || $option{verbose}) {
                print "vimdiff $option{'file'} $tmp.$rev_old\n";
            }
            if (!$option{test}) {
                system "vimdiff $option{'file'} $tmp.$rev_old";
            }
        }
        unlink "$tmp.$rev_old" if -e "$tmp.$rev_old";
    }
    elsif ($rev_new) {
        write_file( "$tmp.$rev_new", scalar $vcs->cat($option{file}, $rev_new) );
        write_file( "$tmp.$rev_old", scalar $vcs->cat($option{file}, $rev_old) );
        if ($option{test} || $option{verbose}) {
            print "vimdiff $tmp.$rev_new $tmp.$rev_old\n";
        }
        if (!$option{test}) {
            exec "vimdiff $tmp.$rev_new $tmp.$rev_old";
        }
    }
    elsif ($rev_old) {
        write_file( "$tmp.$rev_old", scalar $vcs->cat($option{file}, $rev_old) );
        if ($option{test} || $option{verbose}) {
            print "vimdiff $option{'file'} $tmp.$rev_old\n";
        }
        if (!$option{test}) {
            exec "vimdiff $option{'file'} $tmp.$rev_old";
        }
    }
    else {
        my $log = $vcs->log($option{file});
        my ($ver) = max keys %$log;
        my $rev = $log->{$ver}{rev} ? ".$log->{$ver}{rev}" : '';
        write_file( "$tmp$rev", scalar $vcs->cat($option{file}) );
        if ($option{test} || $option{verbose}) {
            print "vimdiff $option{'file'} $tmp$rev\n";
        }
        if (!$option{test}) {
            exec "vimdiff $option{'file'} $tmp$rev";
        }
    }

    return;
}

sub write_file {
    my ($file, @contents) = @_;
    my $fh = file($file)->openw;
    print {$fh} @contents;
    close $fh;
}

__DATA__

=head1 NAME

vcsvimdiff - Uses vimdiff to compare a file with it unmodified version or
historic versions from subversion or bazaar.

=head1 VERSION

This documentation refers to vcsvimdiff version 0.3.0.

=head1 SYNOPSIS

   vcsvimdiff [option] file

 OPTIONS:
  -r --revision=rev1[:rev2]
                Specify revisions to use for full details see vcs help diff
  -c --change=int
                Specify changes from a specific revision (see vcs help diff)
  -f --file=str Explisitly specify the file name
  -R --replay   Replay each change vs the current file
  -m --max=int  Maximum number of revisions to replay
  -t --test     Turn on testing (vimdiff wont actually be run)
     --no-test  Trurn off testing

  -v --verbose  Show more detailed option
     --version  Prints the version information
     --help     Prints this help information
     --man      Prints the full documentation for vcsvimdiff

=head1 DESCRIPTION

=head1 SUBROUTINES/METHODS

=head1 DIAGNOSTICS

=head1 CONFIGURATION AND ENVIRONMENT

=head1 DEPENDENCIES

=head1 INCOMPATIBILITIES

=head1 BUGS AND LIMITATIONS

There are no known bugs in this module.

Please report problems to Ivan Wills (ivan.wills@gmail.com).

Patches are welcome.

=head1 AUTHOR

Ivan Wills - (ivan.wills@gmail.com)

=head1 LICENSE AND COPYRIGHT

Copyright (c) 2009 Ivan Wills (14 Mullion Close, Hornsby Heights, NSW, 2077)
All rights reserved.

This module is free software; you can redistribute it and/or modify it under
the same terms as Perl itself. See L<perlartistic>.  This program is
distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE.

=cut
