package Net::ZKMon;
#

use IO::Socket;
use Carp;
use vars qw($VERSION $DEBUG);
use strict;
use Data::Dumper;

require AutoLoader;

use vars qw($VERSION @ISA @EXPORT @EXPORT_OK
            $DEBUG $HOSTNAME);

use constant CLIENTPORT                => 2181;
use constant BUFFER_LENGTH             => 4096;
use constant DEFAULT_SOCKET_TIMEOUT    => 60;
use constant DEFAULT_ZOO_CMD           => 'conf'; 
# Note: conf command is available since ZooKeeper version 3.3.0

@ISA = qw(AutoLoader);

$VERSION = '0.02a';

sub new {

    my $class = shift;
    my %args  = @_;

    my $self = bless {
               hostname => $args{hostname},
               port     => $args{ClientPort} || CLIENTPORT,
               }, $class;
    $self->debug($args{debug});
    
    return $self;

}

sub debug {

   my $class = shift;
   $DEBUG = shift if @_;
   $DEBUG;

}

#
# run 4 letter commands for zookeeper
#
sub _poll_zhost {

   my $self = shift;
   my $cmd = shift || DEFAULT_ZOO_CMD;

   $self->_connect;
   if ($self->{socket}) {
       my $return_content;
       $self->{socket}->send($cmd);            
       $self->{socket}->recv($return_content, BUFFER_LENGTH ); 
       $self->{socket}->close;
       return $return_content;
   } else {
       croak "There is no connection to host $self->{hostname} : $@ ";
   }
  
   
}

sub _connect {

    my $self = shift;
    my $socket = ();
    if ($self->{hostname}) {
        $socket = IO::Socket::INET->new(
                   PeerAddr => $self->{hostname},
                   PeerPort => $self->{port},
                   Proto    => 'tcp', 
                   Timeout  => DEFAULT_SOCKET_TIMEOUT,
                   Type     => SOCK_STREAM,
                  ) or 
          croak "Could not connect to $self->{hostname}:$self->{port}/tcp : $@";
    } else {
       croak "Please specify a hostname for connecting : $@ ";
    }

    $self->{socket} = $socket;

}

sub _structurify {

    my $arr_ref    = shift;
    my $split_char = shift;
    my $hash_result;
    my @lines = split /\n/, $arr_ref;

    foreach (@lines) {
       chomp;
       if (my ($attr, $value) = (split/$split_char/, $_)) {
            $hash_result->{trim($attr)} = trim($value);
	    if ($attr =~ /Zookeeper version/) {
	        $hash_result->{'version_string'} = trim($value);
		($hash_result->{'version'} = trim($value)) 
		    =~ s/(\d+\.\d+\.\d+)-.*/$1/;
	    }  
	    if ($attr =~ /Latency\smin\/avg\/max/) {
		($hash_result->{min_latency},
		     $hash_result->{avg_latency},
		     $hash_result->{max_latency}) = (split/\//, trim($value));
	    }

       }
    }
    return $hash_result;
}


sub trim {
  
    my $to_return = shift;
    $to_return =~ s/^\s+//;
    $to_return =~ s/\s+$//;
    return($to_return);

}

sub mntr {

   my $self = shift;
   my $cmd = 'mntr';
   my $hash_result = 
          _structurify($self->_poll_zhost($cmd), ':');
   $hash_result->{'cmd'} = $cmd;
   return $hash_result;

}

sub stat {

   my $self = shift;
   $self->{'hostname'} = shift || $self->{'hostname'};
   $self->{'port'} = shift || $self->{'port'}; 
   my $cmd = 'stat';
   my $hash_result = 
          _structurify($self->_poll_zhost($cmd), ':');
   $hash_result->{'hostname'} = $self->{'hostname'};
   $hash_result->{'cmd'} = $cmd;
   return $hash_result;

}

sub conf {
   
    my $self = shift;
    $self->{'hostname'} = shift || $self->{'hostname'};
    $self->{'port'} = shift || $self->{'port'}; 
    my $cmd = 'conf';
    my $hash_result =
          _structurify($self->_poll_zhost($cmd), '=');
    $hash_result->{'hostname'} = $self->{'hostname'};
    $hash_result->{'cmd'} = $cmd;
    return $hash_result;

}

sub envi {
   
    my $self = shift;
    $self->{'hostname'} = shift || $self->{'hostname'};
    $self->{'port'} = shift || $self->{'port'}; 
    my $cmd = 'envi';
    my $hash_result =
          _structurify($self->_poll_zhost($cmd), '=');
    $hash_result->{'hostname'} = $self->{'hostname'};
    $hash_result->{'cmd'} = $cmd;
    return $hash_result;

}

sub srvr {
   
    my $self = shift;
    $self->{'hostname'} = shift || $self->{'hostname'};
    $self->{'port'} = shift || $self->{'port'}; 
    my $cmd = 'srvr';
    my $hash_result =
          _structurify($self->_poll_zhost($cmd), ':');
    $hash_result->{'hostname'} = $self->{'hostname'};
    $hash_result->{'cmd'} = $cmd;
    return $hash_result;

}

1;
__END__
=head1 NAME

Net::ZKMon

=head1 DESCRIPTION

Description : 
  A wrapper module around Zookeeper's 4 letter command words.
  The intention is to use the abstract methods and have the resultant
  data available in perl's scalar reference/hash ;
  thus reducing the parsing overhead involved in the scripts.

=head1 REQUIRES

L<IO::Socket> 

=head1 METHODS

=head2 new

 $this->new();

=head2 conf

 $this->conf();

=head2 mntr

 $this->mntr();

=head2 stat

 $this->stat();

=head2 envi

 $this->envi();

=head2 srvr

 $this->srvr();

=cut
