=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
  $TRANSID = 123528      # Spare installed 06/19/2015
  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
    if (frame_grab())
      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`
    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())
      `rm *.b16`
      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
    
    # 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/rover/lib/Snap "
      snapcmd += " -i #{@id}" if (@id != "")
      syslog("_ " + snapcmd)
      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")
        break
      end
      sleep(1)
    end

    # Kill the hung snap command if it hasn't finished yet
    #
    if (@capture_thread.alive?)
      @capture_thread.kill
      kill_snap()
    end
    @capture_thread.join

    # See if the image was captured
    #
    after  = File.exist?('ps.b16')
    syslog(  "_ File exists after frame grab: #{after}")

    if (after)
      ret_stat = true
    else
      ret_stat = false
      syslog(  "! Image file not created")
    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 date and time down to the second,
    # then copy the image to the log directory. Image name adheres to the
    # Smith Lab standard: LLLL_PuSt_InstrmAct_TTMMDD_hh_mm_ss  local time
    #                   : StaM_5802_RoverTrans_120203_06_27_32.b16
    # Script no longer inserts '_' between prefix and suffix.
    # 
    t = Time.now
    suffix = t.localtime.strftime("%y%m%d_%H_%M_%S")

    #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"
    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
