=begin
#******************************************************************************
 * Copyright 1990-2008 MBARI
 * MBARI Proprietary Information. All rights reserved.
 ******************************************************************************
 * Summary  : Interface to Prosilica camera (real and simulated)
 * Filename : prosilica.rb
 * Author   : Henthorn
 * Project  : Benthic Rover
 * Version  : V2.0
 * Created  : Apr-08   Basic functionality
 * Modified : Updated to lib.2 standards
 ******************************************************************************
=end

# Refer to Rover-code home directory as base
#
require "#{ENV['ROVER_HOME']}/utils/rover_environment"
#

require 'monitor'
require 'utils/datalog'
require 'utils/rover_thread'
require 'utils/misc'

class Prosilica
  include SyslogWriter

  attr_accessor :time_limit

  # Default configuration - no specific camera id
  #
  def initialize(id = "")
    @time_limit = 25 # seconds to accomplish the image capture task
    
    # The ip serves as the camera identifier
    # Will need to pass that into the Snap command
    #    
    @id = id
    syslog("_ Prosilica object instantiated for camera #{@id}")
  end


  $TRANSID = 53010
  def Prosilica.TransitCam
    return Prosilica.new($TRANSID)
  end

  $FLUOROID = 36132
  def Prosilica.FluoroCam
    return Prosilica.new($FLUOROID)
  end

  # Capture image and place the image file in the images directory.
  # The target filename is constructed using the given prefix
  # supplmented with a suffix that virtually guarantees a unique
  # filename.
  #
  # Thread syncronization is implemented here via MonitorMixin
  #
  # prefix - use to label the file (e.g., "measurement_site")
  #
  def capture_image(prefix="")
    ret_stat = false
    #syslog(  "_ Before frame grab: #{File.stat('ps.b16').mtime}")
    if (frame_grab())
      #syslog("_ After  frame grab: #{File.stat('ps.b16').mtime}")
      sleep(1)
      ret_stat = move_image(prefix)
    else
      syslog("! Frame grab failed")
    end
    ret_stat
  end

  # Kill lazy Snap processes
  #
  def kill_snap
    pid = 0

    # Look for Snap processes
    #prc = `ps | grep Snap | grep -v grep`
    prc = `ps | grep Snap | grep -v grep | grep -v " Z "`
    lines = prc.split('\n')

    # Kill all the ones we find
    if (lines.length > 0)
      lines.each { |line|
        tokens = line.split if line
        pid = tokens[0].to_i if tokens

        if (pid > 0)
          syslog("! Killing Snap process id #{pid}")
          syslog(line)
          `kill -9 #{pid}`
        end
      }
    else
      syslog("_ No Snap processes found")
    end
  end


  CheckupFailed = "failed check-up"

  #####
  # Basic health check-up. Perform a frame grab. If successful, we passed.
  #
  def check_up
    sleep(5)   # Assume power just turned on
    if (frame_grab())
      return nil
    else
      return CheckupFailed
    end
  end
  #####
  
  
#~~~~~~~~~~~~~~~~~~~~~~ PRIVATE METHODS ~~~~~~~~~~~~~~~~~~~~~~~~~

private

  # Capture image from camera. The image file is placed in the
  # current directory and named ps.b16
  #
  def frame_grab()
    ret_stat = false

    start_time = Time.now
    #before = File.stat('ps.b16').mtime
    #syslog(  "_ Before frame grab: #{before}")

    # Make sure this task does not hang us up
    # by watching the thread for a given time limit
    #
    @capture_thread = RoverThread.new do  
      # Take an image. If successful copy file to image directory
      #
      snapcmd =  "/cf/barbo/bin/Snap -v "
      snapcmd += " -i #{@id}" if (@id != "")
      #snapcmd += " >> /cf/barbo/logs/snap.log"
      snapcmd += " >> /cf/barbo/logs/latest/data-01-system_logs/syslog.csv"
      syslog("_ " + snapcmd)
      #`date >> /cf/barbo/logs/snap.log`
      `date >> /cf/barbo/logs/latest/data-01-system_logs/syslog.csv`
      ret_stat = system(snapcmd)
    end

    # See how long it takes up to @time_limit
    #
    elapsed = 0
    while ( (elapsed = (Time.now - start_time)) < @time_limit)
      unless (@capture_thread.alive?)
        syslog("_ Frame grab took #{elapsed} seconds")
        #`date >> /cf/barbo/logs/snap.log`
        #`echo "Success!" >> /cf/barbo/logs/snap.log`
        `date >> /cf/barbo/logs/latest/data-01-system_logs/syslog.csv`
        `echo "Success!" >> /cf/barbo/logs/latest/data-01-system_logs/syslog.csv`
        break
      end
      #`echo "Waiting..." >> /cf/barbo/logs/latest/data-01-system_logs/syslog.csv`
      sleep(1)
    end

    # Kill the hung snap command if it hasn't finished yet
    #
    if (@capture_thread.alive?)
      #`date >> /cf/barbo/logs/snap.log`
      #`echo "Fail! Snap hung up" >> /cf/barbo/logs/snap.log`
      `date >> /cf/barbo/logs/latest/data-01-system_logs/syslog.csv`
      `echo "Fail! Snap hung up" >> /cf/barbo/logs/latest/data-01-system_logs/syslog.csv`
      @capture_thread.kill
      kill_snap()
    end
    @capture_thread.join

    after  = File.exist?('ps.b16')
    syslog(  "_ After  frame grab: #{after}")

    unless (after)
      ret_stat = false
      syslog(  "! Image file not created")
    else
      ret_stat = true
    end

    ret_stat
  end

  # Move latest image file from local to the images directory. 
  # The target filename is constructed using the given prefix
  # supplmented with a suffix that virtually guarantees a unique
  # filename.
  #
  def move_image(prefix)
    
    # Create a unique suffix from the current time down to 1/100 of a second,
    # then copy the image to the log directory
    # 
    # suffix = "%10.2f" % t.to_f
    t = Time.now
    suffix = sprintf("%d%02d%02d-%02d%02d%02d",
                     t.year%2000, t.mon, t.day, t.hour, t.min, t.sec)
    cpcmd = "mv ps.b16 " + "#{prefix}_" + suffix + ".b16"
    #cpcmd = "cp ps.b16 " + "#{prefix}_" + suffix + ".b16"
    syslog(cpcmd)
    
    # On error, log it and return false
    #
    unless (system(cpcmd))
      syslog("! Fault: failed to move image")
      return false
    end
    
    true
  end
 
end   # class Prosilica


# SimProsilica class implements Prosilica interface. Logs calls, no real action
#
class SimProsilica < Prosilica
  # Simply log the command that would be executed
  #

  def frame_grab()

    getcmd = "snap"
    syslog("_ " + getcmd)

    # Make a fake image.jpg file
    #
    system("echo \"prosilica image\" > ps.b16")
    true
  end

end
