#!/usr/bin/perl -w

use POSIX qw(strftime);
use Time::ParseDate;
use POSIX ":sys_wait_h";
use Term::ReadKey;

# $CAPTURE = './capture -d -l job.log';
$CAPTURE = './capture -l job.log';


init_args();


prepare_camera();

ReadMode 3;
while(1)
{
      $fname = sprintf "$dir/$prefix%.4d.jpg", $num;

      $tnow = time();
      CMD("capture $fname");
      
      if ( $shots >= $max_shots  )
      {
	    print "Camera running too long without restart ($shots captures) - restarting\n";
	    
	    $shots = 0;
	    CMD("quit");

	    print "Sleeping for 10sec\n";
	    sleep(10);

	    print "Running again\n";
	    prepare_camera();
      }

      sleep_until($tnow+$delay-1);
      if ( $turnoff ) { handle_turnoff(); }

      $num++;
      $shots++;
}
ReadMode 0;

exit; 



#-------------------



sub prepare_camera
{
      CMD("start");
      CMD("flash off");
      CMD("zoom 1");
      CMD("metering spot");
      CMD("focuspoint center");
}


sub help
{
      print "Usage: job [OPTIONS]\n\n",
	    "Options:\n",
	    "    -delay         delay before taking next shot\n",
	    "    -dir           where to put the images\n",
	    "    -max-shots     maximal count of captures without restarting the camera\n",
	    "    -prefix        how to name the images\n",
	    "    -overwrite     start image indexing from zero\n",
	    "    -turnoff       set time of automatic (periodical) turn-off\n",
	    "    -turnon        set time of automatic (periodical) turn-on\n",
	    "                   (time may be specified as 'tomorrow 5:45'\n",
            "                    - see Time::ParseDate documentation)\n",
	    "\n";
      print "Interactive commands:\n",
	    "    c  ...  send a command to the camera\n",
	    "    d  ...  detach (exit program, but don't break connecion with the camera)\n",
	    "    n  ...  take a shot now\n",
	    "    q  ...  quit\n",
	    "    s  ...  change job's setting (dir,prefix,delay,automatic turn off/on etc.)\n",
	    "    t  ...  display time left to the next capture and to the restart\n",
	    "    w  ...  wait - stops capturing until enter is pressed\n",
	    "\n";
}


sub exit_nicely
{
      ReadMode 0;
      exit;
}


sub CMD
{
      my $c = shift;
      
      my $cmd = "$CAPTURE '$c'";
      print "$cmd ...";
      if ( $debug ) { return; }

      $stat = system($cmd);
      print " done.\n";
      
      if ( $stat != 0 )
      {
	    $failures++;
	    printf "$cmd: bad status %04X (failure $failures)\n", $stat;
	    if ( $failures < 10 ) 
	    {
		  return; 
	    }
	    exit_nicely;
      }

      $failures = 0;
}


sub init_args
{
      $delay    = 0;
      $prefix   = '';
      $owr      = 0;
      $debug    = 0;
      $failures = 0;
      $turnoff  = 0;
      $turnon   = 0;
      $turnoff_str = '';
      $turnon_str  = '';
      $max_shots   = 100;

      while (my $arg = shift(@ARGV))
      {
	    if ( $arg eq '-debug' ) { $debug = 1; next; }
	    if ( $arg eq '-max-shots' ) { $max_shots = shift(@ARGV); next; }
	    if ( $arg eq '-delay' ) { $delay = shift(@ARGV); next; }
	    if ( $arg eq '-dir' )  { $dir = shift(@ARGV); next; }
	    if ( $arg eq '-prefix' ) { $prefix = shift(@ARGV); next; }
	    if ( $arg eq '-overwrite' ) { $owr = 1; next; }
	    if ( $arg eq '-turnoff' ) 
	    { 
		  $turnoff_str = shift(@ARGV);
		  $turnoff     = parsedate($turnoff_str); 
		  next; 
	    }
	    if ( $arg eq '-turnon' ) 
	    { 
		  $turnon_str = shift(@ARGV);
		  $turnon     = parsedate($turnon_str); 
		  next; 
	    }
	    else { help(); exit; }
      }

      if ( $turnon && ! $turnoff ) { $turnoff = time; }

      if ( ! $dir ) { help(); exit; }

      if ( ! -d $dir )
      {
	    `mkdir -p $dir`;
      }

      $num   = 0;
      $shots = 0;

      if ( ! $owr )
      {
	    opendir(DIR, $dir) || die "$dir: $!";
	    @files = grep { m{^$prefix} && ! /^\.+$/ } readdir(DIR);
	    closedir DIR;

	    $max = 0;
	    foreach my $f (@files)
	    {
		  $f =~ s{^$prefix}{};
		  $f =~ s{\.jpg$}{};
		  if ( int($f) > $max ) { $max = int($f); }
	    }
	    $num = $max+1;
      }

      $tnow = time();
}


sub handle_turnoff
{
      my $t = time;

      if ( $t < $turnoff ) { return; }

      print "it is now: ",strtime(),"  -  turning off until: ",strtime($turnon),"\n";

      my $wakeup = 0;
      while ( ! $wakeup )
      {
	    sleep(1);
	    if ( keypress_handler() == 1 ) { last; }
	    
	    if ( $turnon )
	    {
		  $t = time;
		  if ( $t > $turnon ) { $wakeup = 1; }
	    }
      }

      print "it is now: ",strtime(),"  -  turning on\n";

      if ( $turnoff_str ) { $turnoff = parsedate($turnoff_str); }
      if ( $turnon_str )  { $turnon  = parsedate($turnon_str); }
}


sub sleep_until
{
      my $t = shift;

      while ( $t > time() )
      {
	    sleep(1);
	    if ( keypress_handler() == 1 ) { last; }
      }
      keypress_handler();
}


sub strtime
{
      my $t = shift;
      if ( ! defined $t ) { $t = time; }
      if ( ! $t ) { return "unset"; }
      return strftime "%a %b %e %H:%M:%S %Y", localtime($t);
}

sub keypress_handler
{
      while ( ($key = ReadKey(1)) )
      {
	    if ( $key eq 'c' )
	    {
		  print "command for capture: ";
		  ReadMode 0;
		  my $cmd = $_ = <STDIN>;
		  ReadMode 3;
		  if ( /^\s*$/ ) { next; }
		  chomp($cmd);
		  CMD($cmd);
	    }
	    elsif ( $key eq 'd' ) { exit_nicely(); }
	    elsif ( $key eq 'n' ) { return 1; }
	    elsif ( $key eq 'q' ) { CMD("quit"); exit_nicely(); }
	    elsif ( $key eq 's' ) 
	    {
		  print "change settings: \n",
			"    dir       = \"$dir\"\n",
			"    prefix    = \"$prefix\"\n",
			"    delay     = \"$delay\"\n",
			"    max-shots = \"$max_shots\"\n",
			"    turn-off  = \"",strtime($turnoff),"\"\n",
			"    turn-on   = \"",strtime($turnon),"\"\n",
			"now it is: ",strtime(),"\n",
			"(time may be specified as 'tomorrow 5:45' - see Time::ParseDate documentation)\n",
			"\n> ";
			
		  ReadMode 0;
		  $_ = <STDIN>;
		  ReadMode 3;
		  if ( /^\s*$/ ) { next; }
		  elsif ( /^\s*dir\s*=\s*(\S+)\s*$/ ) { $dir = $1; }
		  elsif ( /^\s*prefix\s*=\s*(\S+)\s*$/ ) { $prefix = $1; }
		  elsif ( /^\s*max-shots\s*=\s*(\d+)\s*$/ ) { $max_shots = $1; }
		  elsif ( /^\s*delay\s*=\s*(\d+)\s*$/ ) { $delay = $1; }
		  elsif ( /^\s*turn-off\s*=\s*(.+)\s*$/ ) 
		  { 
			$turnoff_str = $1;
			$turnoff     = parsedate($turnoff_str);
			print "capturing will be turned off on: ",strtime($turnoff),"\n";
		  }
		  elsif ( /^\s*turn-on\s*=\s*(.+)\s*$/ ) 
		  {
			$turnon_str = $1;
			$turnon     = parsedate($turnon_str);
			print "capturing will be turned on on: ",strtime($turnon),"\n";
		  }
	    }
	    elsif ( $key eq 't' ) 
	    { 
		  print $tnow+$delay-time(), " sec until next capture\n"; 
		  print $max_shots-$shots, " shots until restart\n";
	    }
	    elsif ( $key eq 'w' )
	    {
		  print "waiting for enter...";
		  <STDIN>;
		  print "\n";
	    }
	    else { help(); }
      }

      return 0;
}



