#!/usr/bin/env perl
use strict;
use warnings;

use Getopt::Long;
use YAML::Syck;
use List::MoreUtils qw/uniq firstidx/;
use Carp;

my %args;

confess "unknown option"
  unless GetOptions( \%args, 'update-order', 'keep-requires=s',
    'keep-recommends=s', 'keep-build-requires=s', 'for-dists=s', 'help',
	'generate-tar-file=s',
	);

my $USAGE = <<'END'
run: ./bin/shipwright-utility --update-order

options: 

help: print this usage

update-order: regenerate install order.
    sub options:
        keep-requires: keep dists with requires dep type. default is true.
        keep-recommends: keep dists with recommends dep type. default is true.
        keep-build-requires: keep dists with build-requires dep type. default is true.
        for-dists: make order only for these dists, seperated by comma.
        default is for all the dists in the source.

    e.g. --update-order --keep-recommends 0 --for-dists Jifty-DBI,Jifty

generate-tar-file: generate a self executable tar file
    e.g. --generate-tar-file /tmp/foo

END
  ;

if ( $args{'help'} ) {
    print $USAGE;
    exit 0;
}
if ( $args{'update-order'} ) {
    for ( 'keep-requires', 'keep-recommends', 'keep-build-requires' ) {
        $args{$_} = 1 unless defined $args{$_};
    }

    my @dists = split /,\s*/, $args{'for-dists'} || '';
    unless (@dists) {
        my $out = `ls scripts`;
        my $sep = $/;
        @dists = split /$sep/, $out;
        chomp @dists;
        s{/$}{} for @dists;
    }

    my $require = {};

    for (@dists) {

        # bloody hack, cpan-Module-Build have recommends that will
        # cause circular deps
        if ( $_ eq 'cpan-Module-Build' ) {
            $require->{'cpan-Module-Build'} = [];
        }
        else {
            fill_deps( %args, require => $require, name => $_ );
        }
    }

    require Algorithm::Dependency::Ordered;
    require Algorithm::Dependency::Source::HoA;

    my $source = Algorithm::Dependency::Source::HoA->new($require);
    $source->load();
    my $dep = Algorithm::Dependency::Ordered->new( source => $source, )
      or confess $@;
    my $order = $dep->schedule_all();

    DumpFile( 'shipwright/order.yml', $order );
	print "updated order with success\n";
}
elsif ( $args{'generate-tar-file'} ) {
	require File::Spec;
	require Cwd;
	my $cwd = Cwd::getcwd();
	my @dirs = File::Spec->splitdir( $cwd );
	my $name = pop @dirs;
	my $parent_dir = File::Spec->catdir( @dirs );
	my $tar_file = Cwd::abs_path( $args{'generate-tar-file'} );

	chdir $parent_dir;
	open my $tar_out, '>', $tar_file or die $!;
	chmod 0755, $tar_file; ## no critic
	print $tar_out <<'EOF';
#!/usr/bin/env perl
open my $tar, '|-', 'tar xz 2>/dev/null';
while (<DATA>) {
    print $tar $_; 
}
close $tar;
EOF
	print $tar_out <<EOF;
exec("cd $name; bin/shipwright-builder \@ARGV");
__DATA__
EOF
	open my $tar_in, '-|', "tar cz $name" or die $!;
	while ( <$tar_in> ) {
		print $tar_out $_;
	}
	chdir $cwd;
	print "generated with success\n";
}

sub fill_deps {
    my %args    = @_;
    my $require = $args{require};
    my $name    = $args{name};

    my $string;
    my $req = LoadFile("scripts/$name/require.yml");

    if ( $req->{requires} ) {
        for (qw/requires recommends build_requires/) {
            my $arg = "keep-$_";
            $arg =~ s/_/-/g;
            push @{ $require->{$name} }, keys %{ $req->{$_} }
              if $args{$arg};
        }
    }
    else {

        #for back compatbility
        push @{ $require->{$name} }, keys %$req;
    }

    @{ $require->{$name} } = uniq @{ $require->{$name} };

    for my $dep ( @{ $require->{$name} } ) {
        next if $require->{$dep};
        fill_deps( %args, name => $dep );
    }
}

