package Net::Gnutella::Server;
use Net::Gnutella::Connection;
use IO::Socket;
use Carp;
use strict;
use vars qw/$VERSION $AUTOLOAD/;

$VERSION = $VERSION = "0.1";

# Use AUTOHANDLER to supply generic attribute methods
#
sub AUTOLOAD {
	my $self = shift;
	my $attr = $AUTOLOAD;
	$attr =~ s/.*:://;
	return unless $attr =~ /[^A-Z]/; # skip DESTROY and all-cap methods
	croak sprintf "invalid attribute method: %s->%s()", ref($self), $attr unless exists $self->{_attr}->{lc $attr};
	$self->{_attr}->{lc $attr} = shift if @_;
	return $self->{_attr}->{lc $attr};
}

sub accept {
	my $self = shift;

	my $server = IO::Socket::INET->new(
		Listen    => SOMAXCONN,
		LocalAddr => $self->server,
		LocalPort => $self->port,
		Reuse     => 1,
	);

	unless (defined $server) {
		$self->error("Couldn't bind to port: $!");
		return;
	}

	$self->socket($server);
	$self->server($server->sockhost);
	$self->port($server->sockport);

	$self->parent->_add_fh($self->socket, $self->can("_accept"), "r", $self);
}

sub connections {
	my $self = shift;
	my @ret;

	foreach my $key (keys %{ $self->{_connhash} }) {
		my $conn = $self->{_connhash}->{$key};

		next unless $conn->connected;

		push @ret, $conn;
	}

	return @ret;
}

sub new {
	my $proto = shift;
	my $parent = shift;
	my %args = @_;

	my $self = {
		_attr    => {
			parent    => $parent,
			debug     => $parent->debug,
			timeout   => $parent->timeout,
			error     => '',
			socket    => '',
			server    => undef,
			port      => 6346,
			allow     => 0,
		},
	};

	bless $self, $proto;

	foreach my $key (keys %args) {
		my $lkey = lc $key;

		$self->$lkey($args{$key});
	}

	$self->accept;

	return $self;
}

sub _accept {
	my $self = shift;
	my $sock = $self->socket->accept || return;

	printf STDERR "+ Accepted connection from '%s'\n", $sock->peerhost if $self->debug;

	my $conn = Net::Gnutella::Connection->new($self->parent,
		Debug     => $self->debug,
		Timeout   => $self->timeout,
		Allow     => $self->allow,
		Socket    => $sock,
		Ip        => $sock->peerhost,
		Connected => 2,
	);

	$self->{_connhash}->{$sock} = $conn;
}

1;
