# BEGIN {unshift@INC,('../..');}

use ExtUtils::MakeMaker;
use Config;
use English;
use strict;

my $REVISION = '$Id: Makefile.PL,v 1.54 2007/02/22 01:07:12 eric Exp $ ';

my @extras = ();

push(@extras,
     CAPI => 'TRUE')
    if ($PERL_VERSION >= 5.005 and $OSNAME eq 'MSWin32'
	and $Config{archname} =~ /-object\b/i);

push(@extras,
     ABSTRACT => "set of RDF modules for query federation",
     AUTHOR   => 'Eric Prud\'hommeaux (eric@w3.org)')
    if ($ExtUtils::MakeMaker::Version >= 5.4301);

WriteMakefile(CONFIGURE => \ &configure);

sub configure {
    my $exes = [qw(bin/algae)];
    my $scrp = [qw(cgibin/algae)];

    my $input = {ENABLE => {'tripleStore' => 0, 
			    'orderTracking' => 0, 
			    'toxicAssoc' => 0, 
			    'http' => 0, 
			    'finger' => 0}, 

		 PREREQS => {'W3C::XML::XmlParser' => 1.0, 
			     'W3C::Util::Exception' => 1.0, 
			     'URI' => 0}};

    # Look for flag file indicating we are making a distribution.
    if (-e '../MAKEDIST') {
	# Don't configure anything for distributions.
	goto end;
    }

    $input->{EXPLAINATION} = 1;

    # Configure according to user input.
    if ((!exists $ENV{'CONFIG_DATABASE'} || $ENV{'CONFIG_DATABASE'} =~ m/^y/)
	&& 
	(&ExtUtils::MakeMaker::prompt("would you like to configure database access?", 'y') =~ /^y/)
	&& 
	&evalWithPrompt(\ &requireDB, $input, 
			'You don\'t have W3C::Database::Kit installed.')
	&&
	&evalWithPrompt(\ &connect, $input, 
			'You don\'t have access to the database with these credentials.')) {
    }
    my $testpm = "# Configuration for test.pl

\$test::tripleStore = $input->{ENABLE}{tripleStore};
\$test::orderTracking = $input->{ENABLE}{orderTracking};
\$test::toxicAssoc = $input->{ENABLE}{toxicAssoc};
\$test::http = $input->{ENABLE}{http};
\$test::finger = $input->{ENABLE}{finger};
1;
";
    if (open (TESTPM, '>', 'test.pm')) {
	print TESTPM $testpm;
	close TESTPM;
    } else {
	warn "Unable to update your test.pm file. It should look like this:\n$testpm"
    }

    # Final arguments to emulate the contructor args to WriteMakefile
  end:
    return {  NAME         => 'W3C::Rdf::Kit',
              VERSION => 1.0,
              PREREQ_PM    => $input->{PREREQS},
              dist         => {COMPRESS => 'gzip', SUFFIX => '.gz'},
	      EXE_FILES    => $exes,
	      @extras};
}

sub requireDB {
    my ($input) = @_;
    require W3C::Database::DBIInterface;
    print "configuring to use SQL database...\n";
}

sub connect {
    my ($input) = @_;

my $NeededProperties = [['queryHost', '"On what internet host is the SQL database installed?"', '"localhost"'], 
			['database', '"What is the name of the SQL triples database (new or existing name)?"', '"rdf"'], 
			['user', '"What is the username to modify $p->{database}?"', '"root"'], 
			['password', '"What is $p->{user}\'s password on $p->{database}?"', 'undef']];

  top:
    eval {
	require W3C::Util::Properties;
    }; if ($@) {
	print "
 You appear to not have W3C::Util::Kit installed. Without it, this
 configuration will fail. If you wish to continue anyways, with the
 possible intention of fixing this later, just keep hitting i (i)gnore.


";
	die 'You are missing W3C::Util::Kit';
    }

    # Input database access particulars from user.
    my $p = {};
    foreach my $needed (@$NeededProperties) {
	my ($name, $prompt, $default) = 
	    ($needed->[0], eval $needed->[1], eval $needed->[2]);
	$p->{$name} = &ExtUtils::MakeMaker::prompt($prompt, $default);
    }
    my $createOT = &ExtUtils::MakeMaker::prompt("would you like to create the OrderTracking demo database?", 'y') =~ /^y/;
    my $createTA = &ExtUtils::MakeMaker::prompt("would you like to create the Toxicity Association demo databases?", 'n') =~ /^y/;

    print "For your convenience, this install script can modify the demo property files
with this information. This will allow others to see the access information.\n";
    my $modify = &ExtUtils::MakeMaker::prompt("Would you like to modify the $ENV{PREFIX}/doc/W3C-Rdf-Kit/test/*.prop with this data?", 'n');

    if (&ExtUtils::MakeMaker::prompt("would you like to change these values?", 'y') !~ /^n/) {
	goto top;
    }

    &ensureTable($p->{'database'}, $p, 

		 # Check these tables for n entries.
		 {'__Holds__' => 0, 
		  '__Nodes__' => 0, 
		  '__Big__' => 0, 
		  '__Attributions__' => 0, 
		  '__AttrLists__' => 0}, 

		 # Create tables with these scripts.
		 ['cat test/makeGenericTripleStore.sql'], []);
    if ($modify =~ m/^\s*y/) {
	&updatePropsFile(['test/genericTripleStore.prop'], $p, 
			 {map {$_->[0] => undef} @$NeededProperties});
    }

    # Make sure we include the triple store tests in $(make test).
    $input->{ENABLE}{'tripleStore'} = 1;

    if ($createOT) {
	$p->{'database'} = 'OrderTracking';
	&ensureTable($p->{'database'}, $p, 

		     # Check these tables for n entries.
		     {'Products' => 10, 
		      'Addresses' => 3, 
		      'Customers' => 4, 
		      'Orders' => 4, 

		      '__Holds__' => 0, 
		      '__Nodes__' => 0, 
		      '__Big__' => 0, 
		      '__Attributions__' => 0, 
		      '__AttrLists__' => 0}, 

		     # Create tables with these scripts.
		     ['cat test/makeOrderTracking.sql', 
		      'cat test/makeGenericTripleStore.sql'], []);
	if ($modify =~ m/^\s*y/) {
	    &updatePropsFile(['test/OrderTracking.prop'], $p, 
			     {map {$_->[0] => undef} 
			      @$NeededProperties});
	}

	# Make sure we include the OrderTracking tests in $(make test).
	$input->{ENABLE}{'orderTracking'} = 1;
    }

    if ($createTA) {
	$p->{'database'} = 'ToxicAssoc';
	my @tables = ('ChemStructure', 'MicroArray', 'MouseToxicity', 'ScreeningAssay', 'Uniprot');
	&ensureTable($p->{'database'}, $p, 

		     # Check these tables for n entries.
		     {'ChemStructure' => 5, 
		      'Chemicals' => 1, 
		      'Kinase' => 1, 
		      'MicroArray' => 1, 
		      'MouseToxicity' => 5, 
		      'ScreeningAssay' => 3, 
		      'Uniprot' => 1}, 

		     # Create tables with these scripts.
		     ['cat test/makeToxicAssoc.sql', 
		      'cat test/makeToxicAssoc.sql | perl -pe "s/--%\\n/--/g;s/--\\\\\\$//g"'], 

		     # If creating a table, drop these first:
		     [@tables]);
	if ($modify =~ m/^\s*y/) {
	    foreach my $propFile (@tables) {
		&updatePropsFile(["test/$propFile.prop"], $p, 
				 {map {$_->[0] => undef} 
				  grep {$_->[0] ne 'database'} # don't change database name
				  @$NeededProperties});
	    }
	}

	$input->{ENABLE}{'toxicAssoc'} = 1;
    }

    # See if we can include LWP tests.
    $input->{ENABLE}{'http'} = 1;
    my $hasLWP = 0;
    eval {
	require LWP::UserAgent;
	$hasLWP = 1;
    };
    if (!$hasLWP && &ExtUtils::MakeMaker::prompt("You don't appear to have LWP installed.
Do you want to include the HTTP tests anyways?
(You may want to install it now and enter 'y'.)", 'n') !~ /^y/) {
	$input->{ENABLE}{'http'} = 0;
	$input->{PREREQS}{'LWP::UserAgent'} = 1.0;
    }
    return 1;
}

sub ensureTable {
    my ($createDB, $p, $neededTables, $createScripts, $additionalDrops) = @_;
    eval {
	# Already tested. If it fails, we are in ignore mode.
	require W3C::Database::DBIInterface;
    }; if (!$@) {
	require W3C::Util::Exception;
	my $props = new W3C::Util::Properties();
	foreach my $name (keys %$p) {
	    $props->put($name, $p->{$name});
	}

	my ($db, $ex);
	eval {
	    $db = new W3C::Database::DBIInterface($props);
	}; if ($@ && ($ex = &W3C::Util::Exception::catch('W3C::Database::DBIInterface::ConnectException'))) {

	    # Try to connect without the database name.
	    my $pCreate = new W3C::Util::Properties();
	    foreach my $p qw(queryHost user password) {
		$pCreate->put($p, $props->get($p));
	    }
	    eval {
		$db = new W3C::Database::DBIInterface($pCreate);
	    };

	    # See if we can created the database.
	    eval {
		$db->executeUpdate("CREATE DATABASE $createDB");
		$ex = undef;

		# Re-attach to the new database.
		$db = new W3C::Database::DBIInterface($props);
	    }; if ($@) {
		$ex = &W3C::Util::Exception::catch('W3C::Util::Exception');
	    }
	}
	if ($ex) {
	    &W3C::Util::Exception::throw($ex);
	}
	my $tables = {};
	$db->executeQuery($tables, "SHOW TABLES");
	my $collisions = 0;
	foreach my $table (keys %$neededTables) {
	    if ($tables->{$table}) {
		if ($db->executeSingleQuery("SELECT COUNT(*) FROM $table") <= $neededTables->{$table}) {
		    $db->executeUpdate("DROP TABLE $table");
		} else {
		    print "$table table not empty. can't continue to create $createDB tables.\n";
		    ++$collisions;
		}
	    }
	}
	if ($collisions) {
	    print "re-using existing $createDB database\n";
	} else {
	    print "creating $createDB database\n";
	    my $hostStr = $p->{'queryHost'} eq 'localhost' ? 
		'' : 
		"--host=$p->{queryHost}";
	    my $passwordStr = $p->{'password'} eq '' ? 
		'' : 
		"--password=$p->{password}";

	    # $additionalDrops is a list of other databases that need
	    # to get dropped if we're creating even a single database.
	    if (@$createScripts) {
		foreach my $database (@$additionalDrops) {
		    eval{$db->executeUpdate("DROP DATABASE $database");};
		}
	    }

	    foreach my $createScript (@$createScripts) {
		my $createCmd = "$createScript | mysql -u $p->{'user'} $passwordStr $hostStr $p->{database} |";
		open (CREATE, $createCmd) || die "failed to call mysql: $!";
		my $errors = 0;
		foreach my $line (<CREATE>) {
		    print $line;
		    ++$errors;
		}
		if (!$errors) {
		    print "looks good\n";
		}
	    }
	}
    }

}

sub evalWithPrompt {
    my ($code, $input, $prompt) = @_;
    my $ret = 0;
    for (my $try = 1; $try; ) {
	eval {
	    &$code($input);
	    $ret = 1;
	    $try = 0;
	    $input->{PREREQS}{'W3C::Util::Database'} = 1.0;
	}; if ($@) {
	    my $msg = $prompt;
	    my $at = $@;
	    eval {
		require W3C::Util::Exception;
		$@ = $at;
		if (my $ex = &W3C::Util::Exception::catch('W3C::Util::Exception')) {
		    $msg = $ex->getMessage();
		} else {
		    $msg = $@;
		}
	    };
	    my $r = &dbProblemPrompt($msg, $input->{EXPLAINATION});
	    $input->{EXPLAINATION} = 0;
	    if ($r eq 'c') {
		$try = 0;
		$ret = 0;
	    } elsif ($r eq 'i') {
		$try = 0;
		$ret = 1;
	    }
	}
    }
    return $ret;
}

sub dbProblemPrompt {
    my ($problem, $explaination) = @_;
    my $explText = <<EOI
 Without it you won\'t be able to access SQL databases for either generic
 triple store or the order tracking demo. You will need it for the Annotea
 installation.

 You may (c) continue without the database support.
 You may (t) ask this script to try again, with the presumption that you\'ve
 installed it in the mean time.
 You may (i) ignore the error and configure the database anyways.
EOI
    ;
    print "$problem\n";
    if ($explaination) {
	print $explText;
    }
    do {
	my ($redo, $prompt, $first) = ('t', '(c)ontinue (i)gnore (t)ry again?', 1);
	my $ret = &ExtUtils::MakeMaker::prompt($prompt, $redo);
	if ($ret eq 'c' || $ret eq 't' || $ret eq 'i') {
	    return $ret;
	}
    } while (1);
}
    
sub updatePropsFile {
    my ($fileList, $p, $lookFor) = @_;

    foreach my $file (@$fileList) {
	if (!open(PROP, $file)) {
	    die "could not read \"$file\": $!";
	}
	print "reading $file\n";
	my $lines = []; # lines from prop file

	# Get the existing lines.
	foreach my $line (<PROP>) {
	    foreach my $prop (keys %$lookFor) {
		if ($line =~ m/^\s*\Q$prop\E\s*\:\s*(.*)$/) {
		    my $value = $p->{$prop};
		    if ($1 ne $value) {
			push (@$lines, "# $line");
			$line = "$prop: $value\n";
		    }
		    delete $lookFor->{$prop};
		    last;
		}
	    }
	    push (@$lines, $line);
	}
	close (PROP);

	# Add needed lines at bottom.
	foreach my $prop (keys %$lookFor) {
	    my $value = $p->{$prop};
	    if ($value) {
		push (@$lines, "$prop: $value\n");
	    }
	}
	if (!open(PROP, '>', $file)) {
		die "could not write \"$file\": $!";
	    }
	foreach my $line (@$lines) {
	    print PROP $line;
	}
	close (PROP);
	print "$file updated\n";
    }
}

sub MY::postamble {
    return <<EOF;

install ::
	@\$(MOD_INSTALL) cgibin "\$(PREFIX)/cgi-bin"

install ::
	@\$(MOD_INSTALL) test "\$(PREFIX)/doc/W3C-Rdf-Kit/test"

PARSERS = AlgaeParser.pm \\
	  N3Parser.pm \\
	  RdalParser.pm \\
	  RdqlParser.pm \\
	  SeRQLParser.pm \\
	  SparqlParser.pm \\
	  TurtleSParser.pm

YAPPS := \$(patsubst \%.pm,\%.yp,\$(PARSERS))

parsers: \$(PARSERS)

\$(PARSERS): \%.pm: \%.yp
	yapp -m W3C::Rdf::_\$(basename \$\@) -v -o \$\@ -b '/usr/bin/perl' \$\<
	perl -pi -e "s/use Parse::Yapp::Driver;/# use Parse::Yapp::Driver; @@ replaced by W3C::Util::YappDriver/g" \$\@

try: RelaxNGParser.pm
	./RelaxNGParser.pm rdfxml-rdal.rnc

rdfxml-rdal.rng: rdfxml-rdal.rnc
	trang -I rnc -O rng rdfxml-rdal.rnc rdfxml-rdal.rng

diff: RelaxNGParser.pm
	./RelaxNGParser.pm rdfxml-rdal.rnc > asdf
	diff rdfxml-rdal.rnc.comp asdf

EOF
}

