use 5.006001;
use strict;
use Config qw(%Config);
use ExtUtils::MakeMaker;

# Where to find 'libscineplex.a' and the *.h files
my $SUPPORT = "../scineplex";
$SUPPORT = "../../../libs/scineplex/main" unless -d $SUPPORT;

my @clean;

# Generate lib/ActiveState/Scineplex/Constants.pm
my @lang;
opendir(my $dh, $SUPPORT) || die "Can't opendir $SUPPORT: $!";
while (my $file = readdir($dh)) {
    if ($file =~ /^Lex(\w+).cxx$/) {
	push(@lang, $1 eq "VB" ? "vbscript" : lc($1));
    }
}
@lang = sort @lang;
print "Supported languages: @lang\n";

my %LexerConstant;
open(my $fh, "<", "$SUPPORT/SciLexer_gen.h") || die "Can't open '$SUPPORT/SciLexer_gen.h': $!";while (<$fh>) {
    if (/^\#define\s+(\w+)\s+(\d+)/) {
	$LexerConstant{$1} = $2;
    }
    else {
	warn "Can't parse: $_";
    }
}
close($fh);

my %sce_lang = (
   perl => "PL",
   html => "H",
   ruby => "RB",
   vbscript => "B",
   xslt => "XML",
);

my $constants_pm = "lib/ActiveState/Scineplex/Constants.pm";

require File::Path;
File::Path::mkpath("lib/ActiveState/Scineplex", 1, 0755);
open($fh, ">", $constants_pm) || die "Can't create $constants_pm: $!";

print $fh "package ActiveState::Scineplex;\n\n";
print $fh "use strict;\n\n";

print $fh "our %SCLEX_LANG_CODE = (\n";
my @sce;
push(@sce, "our %SCE_TOKEN = (\n");

for my $lang (@lang) {
    my $sclex = "SCLEX_\U$lang";
    die "$sclex not defined" unless exists $LexerConstant{$sclex};
    printf $fh "    %-6s => %2d,\n", $lang, $LexerConstant{$sclex};
    my $sce_lang = $sce_lang{$lang} || uc($lang);
    push(@sce, "    $lang => {\n");
    my $found;
    for my $c (sort {$LexerConstant{$a} <=> $LexerConstant{$b}}
               grep /^SCE_\Q$sce_lang\E_/, keys %LexerConstant)
    {
	push(@sce, sprintf qq(%-8s%2d => "%s",\n), "", $LexerConstant{$c}, $c)
	    unless $c =~ /_UPPER_BOUND$/;

	$found++;
    }
    die "No lexer constants for $lang" unless $found;
    push(@sce, "    },\n");
}
print $fh ");\n\n";

push(@sce, ");\n");
print $fh join("", @sce);
print $fh "\n1;\n";

close($fh) || die "Can't write $constants_pm: $!";
push(@clean, $constants_pm);

# Figure out how to link in C++ code
my @LD;
my @LIBS;
my $LDDLFLAGS = $Config{lddlflags};
my $OBJECT = '$(BASEEXT)$(OBJ_EXT)';
my $CCFLAGS;

if ($Config{cc} eq 'gcc') {
    my $LD = "g++";
    if ($^O eq 'darwin') {
        $LD = $Config{ld};
        $LD =~ s/g?cc$/g++/;
        $LD =~ s/^g?cc\b/g++/;
    }
    if ($^O eq 'hpux') {
        push @LIBS, '-lunwind';
    }

    my $libcpp = `$Config{cc} $Config{ldflags} -print-file-name=libstdc++.a`;
    chomp $libcpp;
    if ( -r $libcpp  ) {
        print STDERR "Found a static c++ lib ($libcpp), linking against it\n";
        my $copy = $^O eq "MSWin32" ? "cp -f" : "ln -sf";
        system("$copy $libcpp libstdc++.a");
        push @clean, 'libstdc++.a';
        $LD .= " -static-libgcc -L.";
    }

    @LD = (LD => $LD);
}
elsif($Config{cc} eq 'cc') {
    if ($^O eq 'hpux') {
        push @LIBS, '-lCsup -lunwind';
        foreach my $acc (qw(/opt/aCC/bin/aCC)) {
            if (-x $acc) {
                my $LD = $acc;
                if ($Config{use64bitall}) {
                   $LD .= " +DA2.0W";
                }
                @LD = ( LD => $LD );
                $LDDLFLAGS =~ s/\+vnocompatwarnings//;
                my $csup_ver = MY::libCsup_ver();
                if ($csup_ver <= 3.13) {
                    $OBJECT .= ' cpprt0_stub$(OBJ_EXT)';
                    if (!$Config{use64bitall}) {
                        $CCFLAGS .= ' -DBOOT_CALL_MAIN_';
                    }
                }
            }
        }
    }
    elsif($^O eq 'solaris') {
	push @LIBS, '-lCrun';
    }
}


WriteMakefile(
    NAME              => 'ActiveState::Scineplex',
    VERSION_FROM      => 'lib/ActiveState/Scineplex.pm',
    ABSTRACT_FROM     => 'lib/ActiveState/Scineplex.pm',
    AUTHOR            => 'ActiveState <support@activestate.com>',
    MYEXTLIB          => ("$SUPPORT/libscineplex" . '$(LIB_EXT)'),
    INC               => "-I. -I$SUPPORT",
    @LD,
    LIBS              => \@LIBS,
    LDDLFLAGS         => $LDDLFLAGS,
    (defined $CCFLAGS ?
        (CCFLAGS      => $CCFLAGS) : () ),
    OBJECT            => $OBJECT,
    clean             => { FILES => join ' ', @clean },
);

package MY;
# Necessary on HP if we want to statically link against libCsup, the c++ runtime
sub const_loadlibs {
    my $inherited = shift->SUPER::const_loadlibs(@_);
    if ($inherited =~ /^\s*LDLOADLIBS\s*=\s*(.*)/m) {
        my $ldl = $1;
        if ($ldl =~ /-lCsup/) {
            my $csup_ver = libCsup_ver();
            if (defined $csup_ver && $csup_ver > 03.37) {
                $inherited =~ s/-lCsup/-Wl,-a,archive -lCsup -Wl,-a,default/mg;
            }
        }
    }
    $inherited;
}

sub libCsup_ver {
    require File::Spec;
    my $libs = join ' ', map { File::Spec->catfile($_, 'libCsup.a') }
	                 qw(/lib /usr/lib /usr/lib/hpux32 /usr/lib/hpux64);
    open (my $what, "what $libs 2>/dev/null |") || return;
    while(<$what>) {
        return $1 if (/A\.(\d+.\d+).*Language Support Library/ );
    }
    return;
}
