package Node::Channel::IMIP;

use strict;
use vars qw/@ISA/;
@ISA = qw/Node::Channel/;

sub new {
    my ($package, $handle, $channel_handler_package) = @_;

    my $self = $package->SUPER::new($handle);
    $self->{handlers}{'.'} = $channel_handler_package->new;

    return $self;
}

sub send {
    my ($self, $msg_type, $your_ref, $my_ref) = splice @_, 0, 3;
    my $body = @_ % 2 ? pop : undef;

    my $message = "$msg_type $your_ref $my_ref\n";
    $message .= (shift) .": ". (shift) . "\n" while @_;
    $message .= defined $body ?
	'body_length: '. length($body) . "\n\n$body" : "\n";

    $self->write($message);
}

sub receive {
    my ($self) = @_;

    if (my $header = $self->{header}) {
	# we have already extracted a message header, looking for its body now
	my ($msg_type, $my_ref, $your_ref, $fields, $body_length) = @$header;
	return 0 unless length $self->{read_buf} > $body_length;

	my $body = substr $self->{read_buf}, 0, $body_length, '';
	
	my $handler = $self->{handlers}{$my_ref};
	$handler->$msg_type($self, $my_ref, $your_ref, $fields, $body);

	$self->{header} = undef;
    } else {
	# looking for a new message header
	my $i = index $self->{read_buf}, "\n\n";
	return 0 if $i == -1;

	my $message = substr $self->{read_buf}, 0, $i;
	substr $self->{read_buf}, 0, $i+2, '';

	my @lines = split /\n/, $message;
	my ($msg_type, $my_ref, $your_ref) = split /\s+/, shift @lines;
	my %fields = map { split /:\s*/, $_, 2 } @lines;
	$msg_type = (uc substr $msg_type, 0, 1, '') . lc $msg_type;

	if (my $body_length = delete $fields{body_length}) {
	    $self->{header} = [$msg_type, $my_ref, $your_ref, {%fields}, $body_length];
	    return 0;
	}

	my $handler = $self->{handlers}{$my_ref};
	$handler->$msg_type($self, $my_ref, $your_ref, {%fields});
    }

    return 1;
}

sub add_handler {
    my ($self, $my_ref, $handler) = @_;
    die "attempted to add handler '$my_ref' when one exists" if $self->{handlers}{$my_ref};
    $self->{handlers}{$my_ref} = $handler;
}

sub remove_handler {
    my ($self, $my_ref) = @_;
    die "attempted to remove handler '$my_ref' when none exists" unless $self->{handlers}{$my_ref};
    delete $self->{handlers}{$my_ref};
}

sub closed {}

1
