package Dist::Zilla::Plugin::PPPort;
$Dist::Zilla::Plugin::PPPort::VERSION = '0.011';
# vi:noet:sts=4:sw=4:ts=4
use Moose;
with qw/Dist::Zilla::Role::FileGatherer Dist::Zilla::Role::PrereqSource Dist::Zilla::Role::AfterBuild Dist::Zilla::Role::FilePruner/;
use namespace::autoclean;

use experimental 'signatures';

use Moose::Util::TypeConstraints 'enum';
use MooseX::Types::Moose 'Int';
use MooseX::Types::Perl qw(StrictVersionStr);
use MooseX::Types::Stringlike 'Stringlike';
use Devel::PPPort 3.23;
use File::Spec::Functions 'catdir';
use File::pushd 'pushd';
use List::Util 'any';

has style => (
	is  => 'ro',
	isa => enum(['MakeMaker', 'ModuleBuild']),
	default => 'MakeMaker',
);

has filename => (
	is      => 'ro',
	isa     => Stringlike,
	lazy    => 1,
	coerce  => 1,
	default => sub($self) {
		if ($self->style eq 'MakeMaker') {
			return 'ppport.h';
		}
		elsif ($self->style eq 'ModuleBuild') {
			my @module_parts = split /-/, $self->zilla->name;
			return catdir('lib', @module_parts[0 .. $#module_parts - 1], 'ppport.h');
		}
		else {
			confess 'Invalid style for XS file generation';
		}
	}
);

has version => (
	is      => 'ro',
	isa     => StrictVersionStr,
	default => '3.23',
);

has override => (
	is      => 'ro',
	isa     => Int,
	default => 0,
);

sub gather_files($self) {
	Devel::PPPort->VERSION($self->version);
	require Dist::Zilla::File::InMemory;
	$self->add_file(Dist::Zilla::File::InMemory->new(
		name => $self->filename,
		content => Devel::PPPort::GetFileContents($self->filename),
		encoding => 'ascii',
	));
	return;
}

sub after_build($self, $args) {
	my @all_files = map {$_->name } @{ $self->zilla->files };
	my @files;
	my $main_module_xs = $self->zilla->main_module =~ s/.*:://r . ".xs";
	push @files, $main_module_xs if any { $_ eq $main_module_xs } @all_files;
	push @files, grep { $_ =~ m{ ^ lib/ .* \.xs $ }x } @all_files;

	return unless @files;

	my $build_root = $args->{build_root};

	my $wd = pushd $build_root;

	my $filename = $self->filename;

	my $perl_prereq = $self->zilla->prereqs->cpan_meta_prereqs
		->merged_requirements([ qw(configure build runtime test) ], ['requires'])
		->requirements_for_module('perl') || '5.006';

	if ($self->logger->get_debug) {
		chomp(my $out = `$^X $filename --compat-version=$perl_prereq @files`);
		$self->log_debug($out) if $out;
	}
	else {
		chomp(my $out = `$^X $filename --compat-version=$perl_prereq --quiet @files`);
		$self->log($out) if $out;
	}
}

sub register_prereqs($self) {
	$self->zilla->register_prereqs({ phase => 'develop' }, 'Devel::PPPort' => $self->version);
	return;
}

sub prune_files($self) {
	return unless $self->override;

	my @files = @{ $self->zilla->files };
	my $filename = $self->filename;
	for my $file (@files) {
		$self->zilla->prune_file($file) if $file->name eq $filename and $file->added_by !~ __PACKAGE__;
	}
}

__PACKAGE__->meta->make_immutable;

1;

#ABSTRACT: PPPort for Dist::Zilla

__END__

=pod

=encoding UTF-8

=head1 NAME

Dist::Zilla::Plugin::PPPort - PPPort for Dist::Zilla

=head1 VERSION

version 0.011

=head1 SYNOPSIS

In your dist.ini

 [PPPort]
 filename = ppport.h ;default

=head1 DESCRIPTION

This module adds a PPPort file to your distribution. By default it's called C<ppport.h>, but you can name differently.

=head1 ATTRIBUTES

=head2 style

This affects the default value for the C<filename> attribute. It must be either C<MakeMaker> or C<ModuleBuild>, the former being the default.

=head2 filename

The filename of the ppport file. It defaults to F<ppport.h> if C<style> is C<MakeMaker>, and something module specific if C<style> is C<Module::Build>.

=head2 version

This describes the minimal version of Devel::PPPort required for this module. It currently defaults to C<3.23>.

=head2 override

If this is set to a positive value, the module will prune any preexisting $filename.

=for Pod::Coverage gather_files
register_prereqs
after_build
prune_files
=end

=head1 AUTHOR

Leon Timmermans <leont@cpan.org>

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2011 by Leon Timmermans.

This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.

=cut
