# CmdWorker starts a CWorker executing one command. In its do()
# method it reads the stdout of the command line by line and
# invokes process() for each line.
package CmdWorker;

use CWorker;
use FileHandle;

@CmdWorker::ISA = qw( CWorker );
my $pswarned = 0;

# create a new Worker executing command $comm
sub new {
    my( $this, $comm ) = @_;
    my $class = ref($this) || $this;
    my $self = {};
    bless( $self, $class );
    $self->{"cmd.comm"} = $comm;
    $self->initialize();
    # consumer level is typically low
    $self->consumes( 0 );
    return $self;
}


# initialize the background job: start the cmd command
sub initialize {
    my( $self ) = @_;

    $self->SUPER::initialize();
    my $fh = $self->{"cmd.fh"} = new FileHandle();
    unless( $self->{"pid"} = open( $fh, $self->{"cmd.comm"}."|" ) ) {
        $self->finish();
	&BigSister::common::log( "warning", "failed running cmd command ".($self->{"procs.comm"}) ) unless( $pswarned > time - 3600 );
	$pswarned = time;
    }
    $self->{"cmd.buff"} = "";
    $self->{"filenumber"} = $fh->fileno();
    $self->{"read"} = 1;
    $self->{"write"} = 0;
}


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

    my $mask = '';
    my $fh = $self->{"cmd.fh"};
    vec( $mask, $fh->fileno(), 1 ) = 1;
    while(1) {
	my $rmask = $mask;
        last unless( select( $rmask, undef, undef, 0 ) > 0 );
	my $buff;
	if( sysread( $fh, $buff, 4096 ) <= 0 ) {
	    close $fh;
	    $self->{"pid"} = undef;
	    $self->finish();
	    return;
	}
	$self->{"buff"} .= $buff;
	while( $self->{"buff"} =~ /^(.*?)[\r]*\n/ ) {
	    my $line = $1;
	    $self->{"buff"} = $';
	    $self->process( $line );
	}
    }
}


sub process {
    my( $self, $line ) = @_;

    # by default we just swallow the input
}


# in case the program is aborted ...
sub abort {
    my( $self ) = @_;
    if( $self->{"pid"} && $self->{"fh"} ) {
        kill( $self->{"pid"} );
	close( $self->{"fh"} );
    }
}

1;
