package HelperAppUnixServerSocket;

use strict;
use warnings;

use IO::Socket::UNIX;
use Class::Std::Utils;
{
	my %socket_of;
	
	sub new
	{
		my ( $class, $path ) = @_;

        my $new_object = bless \do{ my $anon_scalar }, $class;
        
		$socket_of{ ident $new_object } = IO::Socket::UNIX->new( Peer     => $path,
										  						 Type     => SOCK_STREAM,
										  						 Timeout  => 5,
										  						 Blocking => 1 ) or die "Unable to connect to $path";
        $socket_of{ ident $new_object }->autoflush( 1 );

        return $new_object;
	}
	
	sub DESTROY
	{
		my $self = shift @_;

		delete $socket_of{ ident $self };
	}
		
	sub close
	{
		my $self = shift @_;
		
		$socket_of{ ident $self }->close();
	}
	
	sub read
	{
		my $self 		= shift @_;
		my $msg_len_str = $self->readBytes( 4 );
		
		return undef if !$msg_len_str;

		my $msg_len = unpack( "N", $msg_len_str );
		
		return ( $msg_len, $self->readBytes( $msg_len ) );
	}
	
	sub write
	{
		my ( $self, $data ) = @_;
		
		$self->writeBytes( pack( 'N', length( $data ) ) );
		$self->writeBytes( $data );
	}
	
	sub readBytes
	{
		my ( $self, $num_bytes ) = @_;

		my $in     = '';
		my $amt_in = 0;

		while ( $amt_in < $num_bytes ) {
			my $one_in;
			my $one_amt_in = $socket_of{ ident $self }->sysread( $one_in, ( $num_bytes - $amt_in ) );

			return undef if ( !$one_amt_in );

			$in     .= $one_in;
			$amt_in += $one_amt_in;
		}

		return $in;
	}
	
	sub writeBytes
	{
		my ( $self, $bytes ) = @_;

		my $len     = length $bytes;
		my $amt_out = 0;

		while ( $amt_out < $len ) {
			my $one_out = $socket_of{ ident $self }->syswrite( substr( $bytes, $amt_out ) );

			return 0 if ( !defined $one_out );

			$amt_out += $one_out;
		}

		return 1;
	}
}

1;