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

use File::Path;
use Net::FTP;
use POSIX qw(uname);

my $cache_dir = "$ENV{HOME}/.cache/ncbi-converters";
if (defined $ENV{NCBI_CONVERTER_DIR}) {
    $cache_dir = $ENV{NCBI_CONVERTER_DIR};
}

my $server   = 'ftp.ncbi.nlm.nih.gov';
my $platform = DetectPlatform();
my $dir      = "/toolbox/ncbi_tools/converters/by_platform/$platform";
my $ext      = ($platform eq 'win') ? 'zip' : 'gz';
my $binext   = ($platform eq 'win') ? '.exe' : '';
my $archive  = "$ARGV[0].$platform.$ext";
my $executable = "$cache_dir/" . $ARGV[0] . $binext;

if ( ! -d $cache_dir ) {
    File::Path::make_path($cache_dir)
        or die "Unable to ensure the existence of $cache_dir: $!";
}

my $ftp = new Net::FTP($server, Passive => 1)
    or die "Unable to connect to FTP server: $!";
$ftp->login or die "Unable to log in to FTP server";
$ftp->cwd($dir) or die "Unable to change to $dir";
$ftp->binary or warn "Unable to set binary mode";

my $time = $ftp->mdtm($archive);
my @stats = stat "$cache_dir/$ARGV[0]$binext";
if ( !@stats  ||  $stats[9] < $time) {
    $ftp->get("$archive", "$cache_dir/$archive")
        or die "Unable to download $archive";
    utime $time, $time, "$cache_dir/$archive";
    my $pid = fork();
    if ($pid < 0) {
        die "Unable to fork for unpacking: $!";
    } elsif ($pid > 0) {
        waitpid($pid, 0);
        chmod(0777 &~ umask, $executable);
        utime $time, $time, $executable;
    } else {
        chdir($cache_dir);
        if ($platform eq 'win') {
            exec('unzip', $archive);
        } else {
            system('gunzip', '-n', $archive);
            rename("$ARGV[0].$platform", $ARGV[0]);
            exit 0;
        }
    }
}

shift;
exec($executable, @ARGV);

sub DetectPlatform
{
    my @uname = uname();
    my $OS    = $uname[0];
    my $CPU   = $uname[4];
    my $pf;
    my $last_built;
    if ($OS =~ /^CYGWIN/) {
        $pf = 'win';
    } elsif ($OS eq 'Darwin') {
        $pf = 'mac';
    } elsif ($OS eq 'Linux') {
        if ($CPU =~ /i\d86/) {
            $pf = 'linux32';
            $last_built = 'November 2014';
        } elsif ($CPU eq 'x86_64') {
            $pf = 'linux64';
        }
    } elsif ($OS eq 'SunOS') {
        if ($CPU =~ /^s/) {
            $pf = 'solaris';
            $last_built = 'March 2014';
        } else {
            $pf = 'solaris-x86';
            $last_built = 'September 2014';
        }
    } else {
        die "No prebuilt binaries available for $OS/$CPU";
    }

    if (defined $last_built) {
        warn "NCBI no longer builds for $OS/$CPU; using a binary from"
            . " $last_built";
    }
    return $pf;
}
