use alienfile;
use Config;

configure { requires 'Alien::Build' => '2.37' };

my $test_program = <<'EOF';
#include <stdio.h>
#include <libxml/xmlversion.h>
#include <libxml/parser.h>
#include <libxml/tree.h>

int
main(int argc, char *argv[])
{
  xmlDoc *doc = NULL;
  /*
   * xmlRead should fail, but having this call ensures
   * that the we have access to the symbols in -lxml2
   * (LIBXML_DOTTED_VERSION below is in the header file)
   */
  doc = xmlReadFile("foo.xml", NULL, 0);
  printf("xml version = '%s'\n", LIBXML_DOTTED_VERSION);
}
EOF

my @try_flags = (
  { cflags => '',                             libs => '-lxml2' },
  { cflags => '-I/usr/include/libxml2',       libs => '-lxml2' },
  { cflags => '-I/usr/local/include/libxml2', libs => '-lxml2' },
);

plugin 'Probe::Vcpkg' => 'libxml2';

probe [
  ['xml2-config', '--version' => \'%{.install.my_version}'],
  ['xml2-config', '--cflags'  => \'%{.install.my_cflags}'],
  ['xml2-config', '--libs'    => \'%{.install.my_libs}'],
];

plugin 'PkgConfig' => 'libxml-2.0';

plugin 'Probe::CBuilder' => (
  cflags  => $_->{cflags},
  libs    => $_->{libs},
  program => $test_program,
  version => qr{xml version = '(.*?)'},
) for @try_flags;
plugin 'PkgConfig::MakeStatic' => ();

my %bad_versions = map { $_ => 1 } (
  # known bad versions
  # may have some extras, and may be incomplete.
  # but probably sufficient.
  # computed using maint/tags-to-versions.pl and the git repository
  # for libxml2.
  '2.0.0',
  '2.1.0','2.1.1',
  '2.2.0','2.2.1','2.2.2','2.2.3','2.2.4','2.2.5','2.2.6','2.2.7','2.2.8',
  '2.3.0','2.3.1','2.3.2','2.3.3','2.3.4','2.3.5','2.3.6','2.3.7','2.3.8','2.3.9','2.3.10','2.3.11','2.3.12','2.3.13','2.3.14',
  '2.4.0','2.4.1','2.4.2','2.4.3','2.4.4','2.4.5','2.4.6','2.4.7','2.4.8','2.4.9','2.4.10','2.4.11','2.4.12','2.4.13','2.4.14','2.4.15','2.4.16','2.4.17','2.4.18','2.4.19','2.4.20','2.4.21','2.4.22','2.4.23','2.4.24','2.4.25','2.4.26','2.4.27','2.4.28','2.4.29','2.4.30',
  '2.5.0','2.5.1','2.5.2','2.5.3','2.5.4','2.5.5','2.5.6','2.5.7','2.5.8','2.5.9','2.5.10','2.5.11',
  '2.6.0','2.6.1','2.6.2','2.6.3','2.6.4','2.6.5','2.6.6','2.6.7','2.6.8','2.6.9','2.6.10','2.6.11','2.6.12','2.6.13','2.6.14','2.6.15','2.6.19','2.6.20','2.6.25',
  '2.7.0','2.7.1',
  '2.9.4',
  #  The next set have reported CVEs
  (map {'2.11.' . $_} (0 .. 9)),
  (map {'2.12.' . $_} (0 .. 9)),
  (map {'2.13.' . $_} (0 .. 6)),
);

meta->around_hook(
  probe => sub {
    my $orig = shift;
    my $build = shift;
    my $install_type = $orig->($build, @_);
    # if the system type is install, make sure the version isn't on the
    # blacklist.
    # Honor $ENV{FORCE} used in the Makefile.PL for XML-LibXML to allow
    # versions on the blacklist.
    if($install_type eq 'system' && !$ENV{FORCE})
    {
      # the first is provided by Probe::CBuilder, or pkg-config plugins for AB >= 1.61
      # the second is generated by the Probe::CBuilder plugin since forever (or thereabouts)
      # the thirds is from this alienfile, (see above with the xml2-config probe).
      my $version = $build->hook_prop->{version}                                    ||
                    $build->install_prop->{plugin_probe_cbuilder_gather}->{version} ||
                    $build->install_prop->{my_version};

      $version =~ s/-.*$//g;

      unless(defined $version)
      {
        print STDERR "Unfortunately, Alien::Libxml2 requires the version from the system libxml2 in\n",
                     "order to determine if it is acceptible for use, but Alien::Build prior to 1.61\n",
                     "did not provide this information in the probe step.  Alien::Libxml2 can still\n",
                     "find the system libxml2 on systems with xml2-config in the PATH, or if libxml2\n",
                     "is available from one of the commonly known locations.  If you want to detect\n",
                     "the system libxml2 with a .pc file via pkg-config, then please upgrade\n",
                     "Alien::Build to 1.61 or better\n";
        return 'share';
      }

      if($bad_versions{$version})
      {
        print STDERR "Alien::Libxml2 is designed to work with XML::LibXML.\n\n".
                     "The installed system version of libxml2 $version is not compatible with XML::LibXML (and probably buggy)!\n\n".
                     "  - don't expect XML::LibXML to build or work correctly with this version of libxml2!\n" .
                     "  - don't report errors with this version of libxml2!\n" .
                     "  - don't send patches for this version of libxml2!\n\n";
        if($version eq '2.9.4')
        {
          print STDERR "XML::LibXML typically attempts to install with this version anyway, so will we.\n";
        }
        else
        {
          print STDERR "XML::LibXML typcially refuses to install with this version unless forced, so we will\n";
          print STDERR "attempt to download a newer version from the internet.  If you prefer you can force\n";
          print STDERR "Alien::Libxml2 to install with this possibly buggy version using:\n";
          print STDERR "env FORCE=1 perl Makefile.PL\n";
          print STDERR "or\n";
          print STDERR "env FORCE=1 cpanm Alien::Libxml2\n";
          return 'share';
        }
      }
    }
    $install_type;
  },
);

plugin 'Prefer::BadVersion' => [ keys %bad_versions ];

share {

  # out of source build is borked on Windows, so we turn it
  # off there.  Turn it on elsewhere as it saves a copy.
  meta->prop->{out_of_source} = $^O eq 'MSWin32' ? 0 : 1;

  plugin 'Download::GitLab' => (
    gitlab_host     => 'https://gitlab.gnome.org',
    gitlab_user     => 'GNOME',
    gitlab_project  => 'libxml2',
    type            => 'link',
    format          => 'tar.xz',
    version_from    => 'tag_name',
    convert_version => sub {
      my $version = shift;
      $version =~ s/^v//;
      $version;
    },
  );

  if($^O eq 'MSWin32' && $Config{ccname} eq 'cl')
  {
    build [
      sub { shift->install_prop->{prefix} =~ s/\//\\/g;},
      'cd win32',
      'cscript configure.js prefix=%{.install.prefix} iconv=no compiler=msvc static=yes',
      'nmake -f Makefile.msvc',
      'nmake -f Makefile.msvc install',
    ];

    plugin 'Gather::IsolateDynamic';

    gather sub {
      my($build) = @_;
      my $prefix = $build->runtime_prop->{prefix};
      $build->runtime_prop->{cflags} = "-I$prefix/include/libxml2";
      $build->runtime_prop->{libs}   = "-L$prefix/lib libxml2_a.lib";
    };
  }
  else
  {
    plugin 'Build::Autoconf' => ();

    build [
      '%{configure} --prefix=%{.install.autoconf_prefix} --without-python --disable-shared --enable-static',
      '%{make}',
      '%{make} install',
    ];

    plugin 'PkgConfig::MakeStatic' => ();
  }

};

sys {

  meta->after_hook(
    gather_system => sub {
      my($build) = @_;
      return if defined $build->runtime_prop->{libs};
      if($build->install_prop->{my_libs})
      {
        $build->runtime_prop->{$_} = $build->install_prop->{"my_$_"} for qw( version cflags libs );
      }
    },
  );

};
