package inc::MakeMaker;

use Moose;
use Config;

extends 'Dist::Zilla::Plugin::MakeMaker::Awesome';

override _build_MakeFile_PL_template => sub {
	my ($self) = @_;

	my $template = <<'TEMPLATE';
use strict;
use warnings;
use Config;
use Getopt::Long;
use File::Basename qw(basename dirname);

use Devel::CheckLib;

# compiler detection
my $is_gcc = length($Config{gccversion});
my $is_msvc = $Config{cc} eq 'cl' ? 1 : 0;
my $is_sunpro = (length($Config{ccversion}) && !$is_msvc) ? 1 : 0;

# os detection
my $is_solaris = ($^O =~ /(sun|solaris)/i) ? 1 : 0;
my $is_windows = ($^O =~ /MSWin32/i) ? 1 : 0;
my $is_linux = ($^O =~ /linux/i) ? 1 : 0;
my $is_osx = ($^O =~ /darwin/i) ? 1 : 0;
my $is_gkfreebsd = ($^O =~ /gnukfreebsd/i) ? 1 : 0;
my $is_netbsd = ($^O =~ /netbsd/i) ? 1 : 0;

# allow the user to override/specify the locations of libarchive
our $opt = {};

Getopt::Long::GetOptions(
	"help" => \&usage,
	'with-libarchive2-include=s' => \$opt->{'archive'}->{'incdir'},
	'with-libarchive-lib=s@'    => \$opt->{'archive'}->{'libs'},
) || die &usage();

my $def = '';
my $lib = '';
my $otherldflags = '';
my $inc = '';
my $ccflags = '';

my %os_specific = (
	'darwin' => {
		'archive' => {
			'inc' => ['/usr/local/opt/libarchive/include', '/opt/local/include'],
			'lib' => ['/usr/local/opt/libarchive/lib', '/opt/local/lib']
		}
	},
	'linux' => {
		'archive' => {
			'inc' => ['/home/linuxbrew/.linuxbrew/opt/libarchive/include', '/opt/local/include', '/usr/local/include', '/usr/include'],
			'lib' => ['/home/linuxbrew/.linuxbrew/opt/libarchive/lib', '/opt/local/lib', '/usr/local/lib', '/usr/lib']
		}
	},
	'freebsd' => {
		'archive' => {
			'inc' => ['/usr/local/include'],
			'lib' => ['/usr/local/lib']
		}
	},
	'netbsd' => {
		'archive' => {
			'inc' => ['/usr/pkg/include'],
			'lib' => ['/usr/pkg/lib']
		},
	}
);

my ($archive_libpath, $archive_incpath);
if (my $os_params = $os_specific{$^O})
{
	if (my $archive = $os_params -> {'archive'})
	{
		$archive_libpath = $archive->{'lib'};
		$archive_incpath = $archive->{'inc'};
	}
}

my @library_tests = (
	{
		'lib'     => 'archive',
		'libpath' => $archive_libpath,
		'incpath' => $archive_incpath,
		'header'  => 'archive.h',
	},
);

my %library_opts = (
	'archive' =>
	{
		'defines' => ' ',
		'libs'    => ' -larchive',
	},
);

# check for optional libraries
foreach my $test (@library_tests) {
	my $library = $test->{lib};
	my $user_library_opt = $opt->{$library};
	my $user_incpath = $user_library_opt->{'incdir'};
	my $user_libs = $user_library_opt->{'libs'};

	if ($user_incpath && $user_libs) {
		$inc .= " -I$user_incpath";

		# perform some magic
		foreach my $user_lib (@$user_libs) {
			my ($link_dir, $link_lib) = (dirname($user_lib), basename($user_lib));

			if (!$is_msvc) {
				my @tokens = grep { $_ } split(/(lib|\.)/, $link_lib);
				shift @tokens if ($tokens[0] eq 'lib');
				$link_lib = shift @tokens;
			}
			$lib .= " -L$link_dir -l$link_lib";
		}

		my $opts = $library_opts{$library};
		$opts->{'use'} = 1;

		$def .= $opts->{'defines'};

		print uc($library), " support enabled (user provided)", "\n";
	} elsif (check_lib(%$test)) {
		if (exists($test->{'incpath'})) {
			if (my $incpath = $test->{'incpath'}) {
				$inc .= ' -I'.join (' -I', @$incpath);
			}
		}

		if (exists($test->{'libpath'})) {
			if (my $libpath = $test->{'libpath'}) {
				$lib .= ' -L'.join (' -L', @$libpath);
			}
		}

		my $opts = $library_opts{$library};
		$opts->{'use'} = 1;

		$def .= $opts->{'defines'};
		$lib .= $opts->{'libs'};

		print uc($library), " support enabled", "\n";
	} else {
		print uc($library), " support disabled", "\n";
	}
}

my @deps;
my @srcs;

my @objs = map { substr ($_, 0, -1) . 'o' } (@deps, @srcs);

sub MY::c_o {
	my $out_switch = '-o ';

	if ($is_msvc) {
		$out_switch = '/Fo';
	}

	my $line = qq{
.c\$(OBJ_EXT):
	\$(CCCMD) \$(CCCDLFLAGS) "-I\$(PERL_INC)" \$(PASTHRU_DEFINE) \$(DEFINE) \$*.c $out_switch\$@
};

	if ($is_gcc) {
		# disable parallel builds
		$line .= qq{

.NOTPARALLEL:
};
	}
	return $line;
}

# This Makefile.PL for {{ $distname }} was generated by Dist::Zilla.
# Don't edit it but the dist.ini used to construct it.
{{ $perl_prereq ? qq[BEGIN { require $perl_prereq; }] : ''; }}
use strict;
use warnings;
use ExtUtils::MakeMaker {{ $eumm_version }};
use ExtUtils::Constant qw (WriteConstants);

{{ $share_dir_block[0] }}
my {{ $WriteMakefileArgs }}

$WriteMakefileArgs{MIN_PERL_VERSION}  = '5.8.8';
$WriteMakefileArgs{DEFINE}  .= $def;
$WriteMakefileArgs{LIBS}    .= $lib;
$WriteMakefileArgs{INC}     .= $inc;
$WriteMakefileArgs{CCFLAGS} .= $Config{ccflags} . ' '. $ccflags;
$WriteMakefileArgs{OBJECT}  .= ' ' . join ' ', @objs;
$WriteMakefileArgs{dynamic_lib} = {
	OTHERLDFLAGS => $otherldflags
};
$WriteMakefileArgs{clean} = {
	FILES => "*.inc"
};

unless (eval { ExtUtils::MakeMaker->VERSION(6.56) }) {
	my $br = delete $WriteMakefileArgs{BUILD_REQUIRES};
	my $pp = $WriteMakefileArgs{PREREQ_PM};

	for my $mod (keys %$br) {
		if (exists $pp -> {$mod}) {
			$pp -> {$mod} = $br -> {$mod}
				if $br -> {$mod} > $pp -> {$mod};
		} else {
			$pp -> {$mod} = $br -> {$mod};
		}
	}
}

delete $WriteMakefileArgs{CONFIGURE_REQUIRES}
	unless eval { ExtUtils::MakeMaker -> VERSION(6.52) };

my @constants = (qw(
	EXTRACT_OWNER
	EXTRACT_PERM
	EXTRACT_TIME
	EXTRACT_NO_OVERWRITE
	EXTRACT_UNLINK
	EXTRACT_ACL
	EXTRACT_FFLAGS
	EXTRACT_XATTR
	EXTRACT_SECURE_SYMLINKS
	EXTRACT_SECURE_NODOTDOT
	EXTRACT_NO_AUTODIR
	EXTRACT_NO_OVERWRITE_NEWER
	EXTRACT_SPARSE
	EXTRACT_MAC_METADATA
	EXTRACT_NO_HFS_COMPRESSION
	EXTRACT_HFS_COMPRESSION_FORCED
	EXTRACT_SECURE_NOABSOLUTEPATHS
	EXTRACT_CLEAR_NOCHANGE_FFLAGS

	FORMAT_CPIO
	FORMAT_CPIO_POSIX
	FORMAT_CPIO_BIN_LE
	FORMAT_CPIO_BIN_BE
	FORMAT_CPIO_SVR4_NOCRC
	FORMAT_CPIO_SVR4_CRC
	FORMAT_CPIO_AFIO_LARGE
	FORMAT_SHAR
	FORMAT_SHAR_BASE
	FORMAT_SHAR_DUMP
	FORMAT_TAR
	FORMAT_TAR_USTAR
	FORMAT_TAR_PAX_INTERCHANGE
	FORMAT_TAR_PAX_RESTRICTED
	FORMAT_TAR_GNUTAR
	FORMAT_ISO9660
	FORMAT_ISO9660_ROCKRIDGE
	FORMAT_ZIP
	FORMAT_EMPTY
	FORMAT_AR
	FORMAT_AR_GNU
	FORMAT_AR_BSD
	FORMAT_MTREE
	FORMAT_RAW
	FORMAT_XAR
	FORMAT_LHA
	FORMAT_CAB
	FORMAT_RAR
	FORMAT_7ZIP
	FORMAT_WARC
	FORMAT_RAR_V5

	READ_FORMAT_ENCRYPTION_UNSUPPORTED
	READ_FORMAT_ENCRYPTION_DONT_KNOW

	READ_FORMAT_CAPS_NONE
	READ_FORMAT_CAPS_ENCRYPT_DATA
	READ_FORMAT_CAPS_ENCRYPT_METADATA

	AE_IFMT
	AE_IFREG
	AE_IFLNK
	AE_IFSOCK
	AE_IFCHR
	AE_IFBLK
	AE_IFDIR
	AE_IFIFO
	AE_SYMLINK_TYPE_UNDEFINED
	AE_SYMLINK_TYPE_FILE
	AE_SYMLINK_TYPE_DIRECTORY

	ENTRY_ACL_EXECUTE
	ENTRY_ACL_WRITE
	ENTRY_ACL_READ
	ENTRY_ACL_READ_DATA
	ENTRY_ACL_LIST_DIRECTORY
	ENTRY_ACL_WRITE_DATA
	ENTRY_ACL_ADD_FILE
	ENTRY_ACL_APPEND_DATA
	ENTRY_ACL_ADD_SUBDIRECTORY
	ENTRY_ACL_READ_NAMED_ATTRS
	ENTRY_ACL_WRITE_NAMED_ATTRS
	ENTRY_ACL_DELETE_CHILD
	ENTRY_ACL_READ_ATTRIBUTES
	ENTRY_ACL_WRITE_ATTRIBUTES
	ENTRY_ACL_DELETE
	ENTRY_ACL_READ_ACL
	ENTRY_ACL_WRITE_ACL
	ENTRY_ACL_WRITE_OWNER
	ENTRY_ACL_SYNCHRONIZE
	ENTRY_ACL_PERMS_POSIX1E
	ENTRY_ACL_PERMS_NFS4
	ENTRY_ACL_ENTRY_INHERITED
	ENTRY_ACL_ENTRY_FILE_INHERIT
	ENTRY_ACL_ENTRY_DIRECTORY_INHERIT
	ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT
	ENTRY_ACL_ENTRY_INHERIT_ONLY
	ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS
	ENTRY_ACL_ENTRY_FAILED_ACCESS
	ENTRY_ACL_INHERITANCE_NFS4
	ENTRY_ACL_TYPE_ACCESS
	ENTRY_ACL_TYPE_DEFAULT
	ENTRY_ACL_TYPE_ALLOW
	ENTRY_ACL_TYPE_DENY
	ENTRY_ACL_TYPE_AUDIT
	ENTRY_ACL_TYPE_ALARM
	ENTRY_ACL_TYPE_POSIX1E
	ENTRY_ACL_TYPE_NFS4
	ENTRY_ACL_USER
	ENTRY_ACL_USER_OBJ
	ENTRY_ACL_GROUP
	ENTRY_ACL_GROUP_OBJ
	ENTRY_ACL_MASK
	ENTRY_ACL_OTHER
	ENTRY_ACL_EVERYONE
	ENTRY_ACL_STYLE_EXTRA_ID
	ENTRY_ACL_STYLE_MARK_DEFAULT
	ENTRY_ACL_STYLE_SOLARIS
	ENTRY_ACL_STYLE_SEPARATOR_COMMA
	ENTRY_ACL_STYLE_COMPACT
));

ExtUtils::Constant::WriteConstants(
	NAME         => 'Archive:Raw',
	NAMES        => [@constants],
	DEFAULT_TYPE => 'IV',
	C_FILE       => 'const-c-constants.inc',
	XS_FILE      => 'const-xs-constants.inc',
	XS_SUBNAME   => '_constant',
	C_SUBNAME    => '_c_constant',
);

WriteMakefile(%WriteMakefileArgs);
exit (0);

sub usage {
	print STDERR << "USAGE";
Usage: perl $0 [options]

Possible options are:
  --with-libarchive-include=<path>    Specify <path> for the root of the libarchive installation.
  --with-libarchive-lib=<lib>         Specify <lib> for the libarchive library.
USAGE

	exit(1);
}

{{ $share_dir_block[1] }}
TEMPLATE

	return $template;
};

override _build_WriteMakefile_args => sub {
	return +{
		%{ super() },
		INC	    => '-I. ',
		OBJECT	=> '$(O_FILES)',
	}
};

__PACKAGE__ -> meta -> make_immutable;
