#!/usr/bin/perl

BEGIN {
	use strict;
	use File::Basename;
	use Cwd;
	use vars qw($YAA_DEFAULT_CONFIG_FILE);

	# determine platform
	use constant YAA_SLASH => ((($^O !~ /win/i) ? "/" : "\\"));
	use constant DEBUG => ((defined $ENV{YAA_DEBUG}) ? 1 : 0);

	# we need to determinate this script's directory
	my $ok = 0;
	my $module_dir = undef;

	# @INC
	foreach (@INC) {
		my $f = $_ . YAA_SLASH . "Yaa.pm";
		if (-f $f && -r $f) {
			$ok = 1;
			$module_dir = $_;
			last;
		}
	}

	unless ($ok) {	
		# ./
		if (substr($0, 0, 2) eq "." . YAA_SLASH) {
			$module_dir = getcwd() . YAA_SLASH . ".." . YAA_SLASH . "lib";
		}
		# /path/to
		elsif (substr($0, 0, 1) eq YAA_SLASH || substr($0, 0, 3) =~ m/^(\w{1}):/) {
			$module_dir = dirname($0) . YAA_SLASH . ".." . YAA_SLASH . "lib";
		}
		# $PATH
		else {
			my $path_delimiter = (YAA_SLASH eq '/') ? ':' : ';';
			foreach my $d (split(/$path_delimiter/, $ENV{PATH})) {
				if (-e $d . YAA_SLASH . $0 && -f $d . YAA_SLASH . $0 && -x $d . YAA_SLASH . $0) {
					$module_dir = $d . YAA_SLASH . ".." . YAA_SLASH . "lib";
					last;
				}
			}
		}

		# No module path defined yet? Weird. Let's try one more thing
		# No module path defined yet? Weird. Let's try one more thing
		if (! defined $module_dir) {
			my $str = getcwd() . YAA_SLASH . ".." . YAA_SLASH . "lib" . YAA_SLASH . "Yaa.pm";
			$module_dir = getcwd() . YAA_SLASH . ".." . YAA_SLASH . "lib" if (-f $str && -r $str && ! -z $str);
		}
	}

	# any success?
	unless (defined $module_dir) {
		print STDERR "Unable to determinate Yaa module directory.\n";
		exit 1;	
	}

	$YAA_DEFAULT_CONFIG_FILE = $module_dir . YAA_SLASH . ".." . YAA_SLASH . "conf" . YAA_SLASH . "yaa.conf";

	# push dir into @INC
	unshift(@INC, $module_dir);
}

use strict;
use Yaa::LookupMap;
use Getopt::Long;
use File::Basename;
use Time::HiRes qw(time);
use Data::Dumper;

use constant VERSION => "0.1";
use vars qw(
	$chroot $user $group
	$daemon $daemon_background $daemon_lockfile $daemon_pidfile $daemon_min_servers $daemon_max_servers $daemon_min_spare_servers $daemon_max_spare_servers $daemon_protocol @daemon_listen_ports $daemon_listen_host @daemon_listen_sockets $daemon_tcpserver_loglevel $daemon_listen_port
	$db_dir $duration_interval
	$mail_sending_method $sendmail_path $smtp_server $smtp_auth $smtp_username $smtp_password
	$logging $log_syslog $log_syslog_facility $log_syslog_priority $log_file $log_file_filename $log_stderr $log_time_format
	$lookup_maps $lookup_map_query_order
	@extra_modules
);

my $config_file = $YAA_DEFAULT_CONFIG_FILE;
my $nlookups = 30000;
$lookup_maps = {};
my $error = undef;
my $map_name;
my $map = undef;
my @query_keys = undef;
my $dump_result = 0;


sub help {
	print "\nThis is a Yaa lookup map performance test, version ", VERSION, "\n\n";
	print STDERR "Usage: ", basename($0), " OPTIONS\n";
	print STDERR "  -c    --config-file    ...   Yaa config file (default: $config_file)\n";
	print STDERR "  -m    --map-name       ...   Lookup map name defined in config file\n";
	print STDERR "  -k    --query-key      ...   Lookup key(s)\n";
	print STDERR "  -n    --numlookups     ...   Number of lookups (defalt: $nlookups)\n";
	print STDERR "  -d    --dump-result    ...   Dump each result (default: ", (($dump_result) ? "YES" : "NO"), ")\n";
	print STDERR "  -h    --help           ...   This help\n";
}

sub version {
	print basename($0), " ", VERSION, "\n";
}

sub parse_config_file ($) {
	my ($file) = @_;
	unless (my $result = do $file) {
		if ($@) {
			$error = "Syntax error in config file " . $file . ": " . $@;
		}
		elsif (! defined $result) {
			$error = "Couldn't open config file " . $file . ": " . $!;
		}
		elsif (! $result) {
			$error = "Couldn't run config file " . $file;
		}
		# return error		
		return 0;
	}
	return 1;
}

# parse command line
my $r = GetOptions(
	'c|config-file=s' => \ $config_file,
	'm|map-name=s' => \ $map_name,
	'k|query-key=s' => \ @query_keys,
	'n|numlookups=i' => \ $nlookups,
	'd|dump-result' => \ $dump_result,
	'V|version' => sub { version(); exit 0; },
	'h|?|help' => sub { help(); exit 0; },
	'<>' => sub {my $opt = shift; print STDERR "Invalid option: $opt\n"; help(); exit 1; }
);

unless ($r) {
	help();
	exit 1;	
}

unless (parse_config_file($config_file)) {
	print STDERR $error, "\n";
	exit 1;
}

unless (@query_keys) {
	print STDERR "Query key(s) not defined.\n";
	help();
	exit 1;
}
unless ($map_name) {
	print STDERR "Map name not defined.\n";
	help();
	exit 1;
}

# build lookup map
if (! defined ($map = Yaa::LookupMap->factory(%{$lookup_maps->{$map_name}}))) {
	print STDERR "Lookup map initialization failed: ", $Yaa::LookupMap::Error, "\n";
	exit 1;
}

# configure Data::Dumper if necessary
$Data::Dumper::Indent = 0 if ($dump_result);
my $num_keys = $#query_keys;

print "Performing performance test for map '$map_name', please wait...\n";
my $start_time = time();
for (my $i = 0; $i < $nlookups;) {
	foreach my $key (@query_keys) {
		unless (defined (my $result = $map->lookup($key))) {
			print STDERR "Lookup failed: ", $map->error, "\n";
		}
		elsif ($dump_result) {
			print "Result: ", Dumper($result->getMatch()), "\n";
		}
	}
	$i += $num_keys;
	#sleep(1);
}

my $stop_time = time();
my $total_time = $stop_time - $start_time;
my $tmp = ($total_time > 0) ? $nlookups / $total_time : "undefined";

printf "Querying for %d results took %.5f seconds (%.5f queries/second).\n", $nlookups, $total_time, $tmp;
exit 0;
