#!/usr/bin/perl -w

use strict;

use Test::More (tests => 6, skip_all => 'tmp');

exit;

sub ip_to_dword {
	my $ip = shift; # assume ipv4
	return unpack('B32', pack('C4C4C4C4', split(/\./, $ip)));
}

sub dword_to_ip {
	my $dword = shift;
	return join '.', unpack('C4C4C4C4', pack('B32', $dword));
}

BEGIN {
	use Socket;
	
	eval "
		use Coro;
		use Coro::AnyEvent;
		use Coro::Socket;
		use Coro::LWP;
		use Coro::Timer;
		use DBI:SQLite;
	";
	
	$::require_coro = $@ if $@;
	
	unlink "db.sqlite";
	
	$ENV{DBI_DSN}  ||= 'DBI:SQLite:dbname=db.sqlite';
	$ENV{DBI_USER} ||= '';
	$ENV{DBI_PASS} ||= '';
	
	use DBI;
	
	$::dbh = DBI->connect;
	$::dbh->do ('create table whois_quota (
		name varchar(200), 
		ip varchar(15),
		ip_expire integer,
		quota integer
	);');

	$::dbh->do ('create table whois_connection (
		local_ip integer,
		remote_ip integer,
		created integer,
		domain varchar(300)
	);');

	$::dbh->do ('create table whois_ip (
		local_ip varchar(15)
	);');

	# TODO: FILL IP LIST into whois_ip
	$::dbh->do ('insert into whois_ip values (?);', {}, ip_to_dword ('192.168.2.2'));
	$::dbh->do ('insert into whois_ip values (?);', {}, ip_to_dword ('10.0.2.6'));
	
    use_ok('Net::Whois::Raw',qw( whois ));

    $Net::Whois::Raw::CHECK_FAIL = 1;
    $Net::Whois::Raw::OMIT_MSG = 1;
    $Net::Whois::Raw::CHECK_EXCEED = 1;
};

my @domains = qw(
    yahoo.com
    freebsd.org
    reg.ru
    ns1.nameself.com.NS
    belizenic.bz
);

my $dns_cache = {};

SKIP: {
    print "The following tests requires internet connection. Checking...\n";
    skip "Looks like no internet connection", 5 unless get_connected();
    
    print "The following tests requires Coro. Checking...\n";
    skip "Looks like no Coro installed", 5 unless require_coro ();
    
    my @coros = ();
    
    # domains
    foreach my $domain ( @domains ) {
        push @coros, Coro->new (sub {
            my $txt = whois( $domain );
            $::dbh->do ('delete from whois_connection where domain = ?', {}, $domain);
            $domain =~ s/.NS$//i;
            ok($txt && $txt =~ /$domain/i, "domain '$domain' resolved");
        });
    }
    
    $_->ready foreach @coros;
    
    $_->join foreach @coros;
    
};

sub get_connected {
    require LWP::UserAgent;
    my $ua = LWP::UserAgent->new( timeout => 10 );
    my $res = $ua->get( 'http://www.google.com' );
    
    return $res->is_success;
}

sub require_coro {
	
	no warnings 'once';
	
	*Net::Whois::Raw::whois_socket_fixup = sub {
		my $class = shift;
		my $sock  = shift;
		
		return Coro::Socket->new_from_fh ($sock, partial => 1);
	};
	
	*Net::Whois::Raw::whois_query_sockparams = sub {
		my $class  = shift;
		my $domain = shift;
		my $name   = shift;
		
		# TODO: YOU MUST PLACE QUOTA CHECK HERE
		# my $sth = $::dbh->prepare ('select * from ');
		
		my $ip;
		
		if (! $dns_cache->{$name}) {
			$ip = inet_ntoa (inet_aton ($name)); # TODO: use coro::util for resolve
			$dns_cache->{$name} = $ip;
		} else {
			$ip = $dns_cache->{$name};
		}
		
		my $ip_num = ip_to_dword ($ip);
		
		my $sth = $::dbh->prepare (
			'select local_ip from whois_ip where local_ip not in (select local_ip from whois_connection where remote_ip = ? group by local_ip) limit 1;'
		);
		my $rows_affected = $sth->execute ($ip_num);
		my $result = $sth->fetchall_arrayref ({});
		
		$sth->finish;
		
		if (@$result == 0) {
			# no free ips, try to use minimally loaded
			$sth = $::dbh->prepare ('select local_ip, count(local_ip) as local_ip_c from whois_connection where remote_ip = ? and created > ? group by local_ip order by count(local_ip) asc limit 1;');
			
			$rows_affected = $sth->execute ($ip_num);
			$result = $sth->fetchall_arrayref ({});
			
		}
		
		$::dbh->do (
			'insert into whois_connection values (?, ?, ?, ?);',
			{},
			$result->[0]->{local_ip}, $ip_num, time, $domain
		);
		
		return (
			PeerAddr => $dns_cache->{$name},
			PeerPort => 43,
			LocalHost => dword_to_ip ($result->[0]->{local_ip}),
			# LocalPort => 
		);
	};
	
	return ! $::require_coro; 
}
