#!/usr/bin/perl
#
# RESET script - DSP configuration
#
# Usage: cmd_reset OBJID
#  
# 1. Set flag var/conf/<OBJID>/conf.reset (PID=1234)
# 2. Set timeout (based on catrige.cfg:RESET_TIMEOUT)
# 3. Execute probing in "RESET" mode
# 4. Post result to conf.reset (RESULT=SUCCESS|FAIL)
# 5. Submit human-readable messages from the probing results 
#    into the LOG readable from Admin / Camera Editor / LOG button
# 6. Correctly post results and log messages if RESET_TIMEOUT was reached
               
use strict;
use warnings;
use SKM::Common "ProcName";
use NextCAM::Conf "GetCfgs";
use Device::Conf;
use Log::Log4perl "get_logger";
use Log::Log4perl::Level;

require "$ENV{APL}/common/bin/logger.patrol";
my $log = get_logger('NEXTCAM::CONF::CMD_RESET');

#------------------------- ARGV ----------------------------
#
my $objid = $ARGV[0];

#------------------------- CONS ----------------------------
#
my $PROG = ProcName;
my $APL = $ENV{APL};
my $APL_CONF = $ENV{APL_CONF};
my $DEF_TIMEOUT = 180;

#------------------------- SIGNALS -------------------------
#
$SIG{INT} = $SIG{TERM} = $SIG{QUIT} = sub { 
    $log->error("Caught signal ($_[0]) while reseting camera DEVID=$objid"); 
    Finalize();
};

#------------------------- MAIN ----------------------------
#

# Check basic conditions
die "Usage: $PROG OBJID\n" unless $objid;
my %conf = GetCfgs OBJID => $objid;
my $cfg = $conf{$objid};
die "No such device: $objid\n" unless $cfg;
die "Not a camera device: $objid\n" unless $cfg->{CAMERAMODEL};

my $result = "FAIL";

# Get cartridge params
my $cart;
foreach (@{ Cartridges 'camera' }) {
    $cart = $_, last if $_->{NAME} eq $cfg->{CAMERAMODEL};
}
die "Cannot find appropriate cartridge for $cfg->{CAMERAMODEL}" unless $cart;
die "No probe script for $cfg->{CAMERAMODEL}" if not $cart->{PROBE} or $cart->{PROBE} eq 'NONE';

# Read default value for RESET_TIMEOUT
my $default = DefaultCartridgeCfg('camera');

# Set flag
my $flag = "$APL_CONF/$objid/conf.reset";
my $timeout = $cart->{RESET_TIMEOUT} || $default->{RESET_TIMEOUT} || $DEF_TIMEOUT;
die "Another instance running\n" if -f $flag;

open FH, '>', $flag or die "Cannot write to $flag: $!";
print FH "PID=$$\n";
close FH;

# Run probe and wait for complete
$log->info("Reset camera DEVID=$objid: START");

my $kidpid;
my %out;
my @comments;
eval {
    local $SIG{ALRM} = sub { die "ALARM" };
    alarm $timeout;
    
    $kidpid = open PROBE, "-|"; # fork + pipe
    die "Cannot fork: $!" unless defined $kidpid;
    
    if($kidpid) {
	while(<PROBE>) {
	    $out{$1} = $2 if /^(\w+)=(.+)$/;
	    push @comments, $1 if /^#(.+)$/;
	}
	close PROBE; # wait for kid to exit
    } 
    else {
	exec $cart->{PROBE}, "DEVID=$objid", "PROBE=RESET";
    }
};
alarm 0;
if ($@ and $@ =~ /ALARM/) {
    # Stop child process if timeout expired
    # Log error message to system.log
    kill 9 => $kidpid if $kidpid > 1;
    $result = "FAIL";
    $log->error("Reset camera DEVID=$objid: Timeout expired");
}
else {
    my ($status, undef, $text) = $out{STATUS} =~ /^(\w+)(: (.+))?$/;
    if ($status eq 'ERROR') {
	$result = "FAIL";
	$log->error("Errors when reseting camera DEVID=$objid: $text");
	#$log->error("(DEVID=$objid) Error details: $_") foreach @comments;
    }
    elsif ($status eq 'WARNING') {
	$result = "SUCCESS";
	$log->warn("(DEVID=$objid) $text");
    }
    elsif ($status eq 'OK') {
	$result = "SUCCESS";
    }
    else {
	$result = "FAIL";
	$log->error("(DEVID=$objid) Unknown status returned from PROBE script");
    }
}

Finalize();

#--------------------------SUB -----------------------------
#
sub Finalize {
    
    $log->log(
	$result eq 'SUCCESS' ? $INFO : $ERROR, 
	"Reset camera DEVID=$objid: DONE. Result: $result"
    );
    
    # Write result
    open FH, '>', $flag;
    print FH "RESULT=$result\n";
    close FH;
    
    # Kill child process if running
    kill 9 => $kidpid if $kidpid > 1 and kill(0 => $kidpid);
    
    exit($result eq 'SUCCESS' ? 0 : 1);
}
