package Server;

use IO::Select;
use IO::Socket;
use strict;
use Carp;
use Sys::Syslog;
use Crypt::HCE_SHA;

my @response;
my $data;

sub new {
    my $class = shift;
    my $self = {};

    bless $self, $class;
    if ((scalar(@_) % 2) != 0) {
	croak "incorrect number of parameters";
    }
    while (@_) {
	my $key = shift(@_);
	my $value = shift(@_);
	$self->{$key} = $value;
    }
    $self->_initialize;
    return $self;
}

sub _initialize {
    my $self = shift;

    if (!defined($self->{'Server'})) {
	croak "Server not initialized properly : Server parameter missing";
    }
    if (!defined($self->{'Port'})) {
	croak "Server not initialized properly : Port parameter missing";
    }
    if (!defined($self->{'Queue'})) {
	croak "Server not initialized properly : Queue parameter missing";
    }
    if (!eval {$self->{'Socket'} = IO::Socket::INET->new(LocalAddr => $self->{'Server'},
							 LocalPort => $self->{'Port'},
							 Proto => 'tcp',
							 Reuse => 1,
							 Listen => $self->{'Queue'}
							 ); })
    {
	croak "Server couldn't establish a port on $self->{'Server'}";
    }
    $self->{'Socket'}->autoflush(1);
    delete $self->{'HCE'};
    $self->{'Select'} = IO::Select->new($self->{'Socket'});
}

sub accept {
    my $self = shift;
    my ($time) = @_; # how long to wait
    my (@ready_to_read, $size);

    @ready_to_read = $self->{'Select'}->can_read($time);
    $size = scalar(@ready_to_read);
    if ($size == 1) {
	$self->{'Connect'} = $self->{'Socket'}->accept;
	$self->{'Connect'}->autoflush(1); # don't buffer return messages
    } else {
	delete $self->{'Connect'};
    }
    return $size;
}

sub close {
    my $self = shift;

    $self->{'Connect'}->close;
    delete $self->{'Connect'};
    delete $self->{'HCE'};
    return 0;
}

sub send {
    my $self = shift;
    my @items = @_;
    my ($item, $enc_item);

    if (!defined($self->{'Connect'})) {
	croak "No Connection established: did you accept?";
    }
    if (defined($self->{'HCE'})) {
	foreach $item (@items) {
#	    syslog('debug','Server encode: %s',$item);
	    $enc_item = $self->{'HCE'}->hce_block_encode_mime($item);
#	    syslog('debug','Server sending: %s', $enc_item);
	    print { $self->{'Connect'} } "$enc_item\n";
	}
	$enc_item = $self->{'HCE'}->hce_block_encode_mime("+END_OF_LIST");
	print { $self->{'Connect'} } "$enc_item\n";
    } else {
	foreach $item (@items) {
#	    syslog('debug','Server sending: %s',$item);
	    print { $self->{'Connect'} } "$item\n";
	}
    }
    return 0;
}

sub recv {
    my $self = shift;
    my ($data, $dec_data, $fh);

    if (!defined($self->{'Connect'})) {
	croak "No Connection established: did you accept?";
    }
    $fh = $self->{'Connect'};
    undef(@response);
    if (!defined($self->{'SKey'})) {
	while (<$fh>) {
	    chomp;
#           syslog('debug','Server recv: %s', $_);
	    tr/\n\r\t//d;
	    last if ($_ eq '+END_OF_LIST');
	    push @response, $_;
	};
	if (!defined(@response)) {
	    return;
	} else {
	    return @response;
	}
    }
    if (defined($self->{'HCE'})) {
	while (<$fh>) {
	    chomp;
#	    syslog('debug','Server recv: %s',$_);
	    $dec_data = $self->{'HCE'}->hce_block_decode_mime($_);
	    $dec_data =~ tr/\n\r\t//d;
#	    syslog('debug','Server decode: %s', $dec_data);
	    last if ($dec_data eq "+END_OF_LIST");
	    push @response, $dec_data;
	};
	if (!defined(@response)) {
	    return;
	} else {
	    return @response;
	};
    } else {
	$_ = <$fh>; # get RKey
	chomp;
	$self->{'RKey'} = $_;
	$self->{'HCE'} = Crypt::HCE_SHA->new($self->{'SKey'}, $self->{'RKey'});
	return $self->recv();
    }
}

1;
__END__

#------- POD ------