package Net::IP::Resolver;

=pod

=head1 NAME

Net::IP::Resolver - Resolve IPs to a particular network

=head1 SYNOPSIS

  # Create the resolver and add some networks
  my $resolver = Net::IP::Resolve->new;
  $resolver->add( 'Comcast' => '123.0.0.0/8', '124.128.0.0/10' );
  $resolver->add( 'Foobar'  => [ '1.2.3.0/24', '1.2.4.0/24' ] );
  
  # Check an IP
  my $ip = '123.123.123.123';
  my $network = $resolver->find_first( $ip );
  print "IP $ip is in network $network";
  
  # prints... "IP 123.123.123.123 is in network Comcast";

=head1 DESCRIPTION

C<Net::IP::Resolver> provides a mechanism for registering a number of
different networks (specified by a set of ip ranges), and then finding
the network for a given IP based on this specification.

The identifier for a network can be any defined value that you wish.

Thus you can resolve to numeric identifiers, names, or even to objects
representing the networks.

=head1 METHODS

=cut

use strict;
use Net::IP::Match::XS ();

use vars qw{$VERSION};
BEGIN {
	$VERSION = '0.01';
}





#####################################################################
# Constructor and Accessors

=pod

=head2 new

The C<new> constructor takes no arguments, and create a new and empty
resolver.

Returns a new C<Net::IP::Resolver> object.

=cut

sub new {
	my $class = ref $_[0] ? ref shift : shift;

	my $self = bless {
		networks => [],
		results  => [],
		}, $class;

	$self;
}





#####################################################################
# Net::IP::Resolver Interface

=pod

=head2 add $network, $range, ...

The C<add> method adds a network to the resolver. It takes as argument
an identifier for the network, which can be C<any> defined value, including
an object of any type, followed by a set of 1 or more IP ranges, in the
format used by L<Net::IP::Match::XS> (which this class uses for the actual
ip matching).

Returns true if the network was added, or C<undef> if passed incorrect
arguments.

=cut

sub add {
	my $self    = shift;
	my $result  = defined $_[0] ? shift : return undef;
	my $network = @_ ? [ @_ ] : return undef;

	# Add the result and ranges
	push @{$self->{networks}}, $network;
	push @{$self->{results}},  $result;

	1;
}

=pod

=head2 find_first $ip

The C<find_first> method takes an IP address as argument, and checks
it against each network to find the first one that matches.

The assumption made by C<find_first> is that each network in the resolver
occupies a unique and non-overlapping set of ranges, and thus only any ip
can only ever resolve to one network

Returns the network identifier as originally provided, or C<undef> if the
ip is not provided, or the resolver cannot match it to any network.

=cut

sub find_first {
	my $self = shift;
	my $ip   = defined $_[0] ? shift : return undef;

	foreach my $i ( 0 .. $#{ $self->{networks} } ) {
		my $network = $self->{networks}->[$i];
		if ( Net::IP::Match::XS::match_ip( $ip, @$network ) ) {
			return $self->{results}->[$i];
		}
	}

	return undef;
}

1;

=pod

=head1 SUPPORT

All bugs should be filed via the bug tracker at

L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Net-IP-Resolver>

For other issues, or commercial enhancement and support, contact the author

=head1 AUTHORS

Adam Kennedy (Maintainer), L<http://ali.as/>, cpan@ali.as

=head1 SEE ALSO

L<Net::IP>, L<Net::IP::Match::XS>

=head1 COPYRIGHT

Copyright (c) 2005 Adam Kennedy. All rights reserved.
This program is free software; you can redistribute
it and/or modify it under the same terms as Perl itself.

The full text of the license can be found in the
LICENSE file included with this module.

=cut
