=begin
 ******************************************************************************
 * Copyright 1990-2011 MBARI
 * MBARI Proprietary Information. All rights reserved.
 ******************************************************************************
 * Summary  : Take fluorometry measurements using the fluorometer driver
 * Filename : measure_fluorometry.rb
 * Author   : Henthorn
 * Project  : Benthic Rover
 * Version  : 1
 * Created  : Aug 2011
 * Modified :
 ******************************************************************************
=end

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

require 'device/rover'
require 'utils/misc'
require 'utils/datalog'

##########
# 
class MeasureFluorometry < Behavior
  include SyslogWriter
  include Dump

  attr_reader :name, :state, :write_log
  attr_reader :dark_time, :ref_time, :lum_time, :flu_time, :phos_time

  ##
  # Create Behavior husk
  #
  def initialize(p_behavior_element)
    super

    ##
    # Deployment file attributes
    @name  = self.class.name
    @comment = ""
    ##

    @state = HERE
    @my_thread = nil
    @data_home = nil
    @b_status = false
 
    ##
    # Using class variables for log data
    #
    @write_log = false
    @dark_time = @ref_time = @lum_time = @flu_time = @phos_time = 0
    @@dark_590  = @@ref_590  = @@lum_590  = @@flu_590  = @@phos_590  = @@const_590  = -1
    @@dark_690  = @@ref_690  = @@lum_690  = @@flu_690  = @@phos_690  = @@const_690  = -1
    @@dark_t = @@ref_t = @@lum_t = @@flu_t = @@phos_t = @@const_t = 0

    load_attrs(p_behavior_element)
  end
  #####

  #####
  # Standard usage format
  #
  def MeasureFluorometry.usage_format
    "%16s  %32s  %10s  %16s\n"
  end

  #####
  # A crude documentation feature. Each subclass should provide
  # one that begins by calling this method. Make sure every
  # attribute available to the behavior is documented.
  #
  def MeasureFluorometry.usage
    u  = sprintf("%-16s  %-32s  %-10s  %-16s\n", \
                 "Attribute Name","Description","Type","Default Value")
    u += sprintf("%-16s  %-32s  %-10s  %-16s\n", \
                 "----------------","--------------------------------", \
                 "----------","----------------")
    u += sprintf(Behavior.usage_format, \
                 "name","Behavior name","String","name of class")
    u += sprintf(Behavior.usage_format, \
                 "comment","Concise description","String","blank")
  end

  ##
  # Iterate over attributes in the element, extract parameters.
  #
  def load_attrs(p_behavior_element)
    super

    attrs = p_behavior_element.attributes
    attrs.keys.each do |k|
      case k

        # Load behavior attributes
        #
        # Integration times in milliseconds (defaults to 1000)
        #
	when "write_log"
	@write_log =  attrs[k].downcase == "true"

	when "dark_time"
	@dark_time =  attrs[k].to_i

	when "ref_time"
	@ref_time =  attrs[k].to_i

	when "lum_time"
	@lum_time =  attrs[k].to_i

  when "flu_time"
  @flu_time =  attrs[k].to_i

  when "const_time"
  @const_time =  attrs[k].to_i

	when "phos_time"
	@phos_time =  attrs[k].to_i

        else
        puts("Unrecognized attr: #{k}")

      end
    end

    # Option: Throw an exception if there any required attributes
    # are missing
    #
  end
  #####

  ##
  # Initialize behavior and make ready for execution.
  # Should be called just before executing the behavior.
  #
  def init(p_seq_number=1)   # Where in the plan behavior sequence I am
    syslog("_ #{@name} init")

    # Throw an exception if @my_thread != nil and @my_thread.alive?
    # Perform initialization procedures

    @my_thread = nil
    @state = READY
    @b_status = "ready"
  end
  #####


  #####
  # Clean-up method. Use this to restore state of vehicle
  # after behavior execution, whether successful or not.
  #
  def clean_up
    Rover.instance.relay.fluorometerOff
    # Rover.instance.wakey.v12_off
    Rover.instance.wakey_msg("v12_off")
  end
  #####

  ##
  # Execute the behavior
  #
  def execute
    # Execute if ready.
    # This need not be enforced by behaviors, just an example.
    # Alternatively, you could run init method if not ready.
    #
    unless (@state == READY)
      syslog("_ #{@name} not ready to execute")
    end

    syslog("_ #{@name} execute")
    @state = EXECUTING

    @b_status = "running"
    begin
      # Perform the behavior
      # Rover.instance.wakey.v12_on
      Rover.instance.wakey_msg("v12_on")
      Rover.instance.relay.fluorometerOn
      sleep(1)
      fluoro = Rover.instance.fluorometer
      
      msg = fluoro.get_msg
      if (msg)
        syslog("_ Fluorometer on and ready")
      else
        syslog("! Fluorometer not on or ready")
        clean_up
        return
      end
      
      if (@dark_time > 0)
        ##
        # Get dark measurement
        #
        @b_status = "Dark Measurement"
        fluoro.time_set(@dark_time)
        @@dark_t = @dark_time           # Remember time for logging
        if (vals = fluoro.dark)
          @@dark_690 = vals[1]
          @@dark_590 = vals[2]
          syslog("_ dark-690 = #{@@dark_690}, dark-590 = #{@@dark_590}")
        end
      end
      
      if (@ref_time > 0)
        ##
        # Get reference measurement
        #
        @b_status = "Reference Measurement"
        fluoro.time_set(@ref_time)
        @@ref_t = @ref_time           # Remember time for logging
        if (vals = fluoro.measure)
          @@ref_690 = vals[1]
          @@ref_590 = vals[2]
          syslog("_ ref-690 = #{@@ref_690}, ref-590 = #{@@ref_590}")
        end
      end
      
      if (@lum_time > 0)
        ##
        # Get luminescense measurement
        #
        @b_status = "Luminescense Measurement"
        fluoro.time_set(@lum_time)
        @@lum_t = @lum_time           # Remember time for logging
        if (vals = fluoro.dark)
          @@lum_690 = vals[1]
          @@lum_590 = vals[2]
          syslog("_ lum-690 = #{@@lum_690}, lum-590 = #{@@lum_590}")
        end
      end
      
      if (@flu_time > 0)
        ##
        # Get fluoroescense measurement
        #
        @b_status = "Fluorescense Measurement"
        fluoro.time_set(@flu_time)
        @@flu_t = @flu_time           # Remember time for logging
        if (vals = fluoro.measure)
          @@flu_690 = vals[1]
          @@flu_590 = vals[2]
          syslog("_ flu-690 = #{@@flu_690}, flu-590 = #{@@flu_590}")
        end
      end
      
      if (@const_time > 0)
        ##
        # Get fluoroescense measurement against the constant background
        #
        @b_status = "Constant Fluorescense Measurement"
        fluoro.time_set(@const_time)
        @@const_t = @const_time           # Remember time for logging
        if (vals = fluoro.measure)
          @@const_690 = vals[1]
          @@const_590 = vals[2]
          syslog("_ const-690 = #{@@const_690}, const-590 = #{@@const_590}")
        end
      end
      
      if (@phos_time > 0)
        ##
        # Get phosphorescense measurement
        #
        @b_status = "Phosphorescense Measurement"
        fluoro.time_set(@phos_time)
        @@phos_t = @phos_time           # Remember time for logging
        if (vals = fluoro.dark)
          @@phos_690 = vals[1]
          @@phos_590 = vals[2]
          syslog("_ phos-690 = #{@@phos_690}, phos-590 = #{@@phos_590}")
        end
      end
      
      if (@write_log)
        # syslog("_ logging my data now")
        fluoro.log_data(@@dark_t,@@dark_690,@@dark_590,
                        @@ref_t,   @@ref_690,   @@ref_590,
                        @@lum_t,   @@lum_690,   @@lum_590,
                        @@flu_t,   @@flu_690,   @@flu_590,
                        @@phos_t,  @@phos_690,  @@phos_590,
                        @@const_t, @@const_690, @@const_590)
      end
      
    rescue
      # Handle exceptions
    ensure
      self.clean_up
      @state = FINISHED
    end
  end
  #####


  ##
  # Abort the behavior
  #
  def abort
    syslog("_ #{@name} abort")
    if (@state == EXECUTING)
      @state = ABORTING 

      # Perform aborting procedure
      @my_thread.kill if @my_thread
    else
      syslog("_ #{@name} not executing, aborting...")
    end
    self.clean_up()
    @state = FINISHED
  end
  #####


  #####
  # My data files go in the plan data dir by default.
  # Specialized behaviors are free to point to new or other directories.
  #
  def data_home=(p_seq_num)
    @data_home = DataLog.plan_data_home
  end
  #####

  #####
  def data_home
    return @data_home
  end
  #####

end


##
# Standalone unit test (recommended)
#
if __FILE__ == $0

  if "usage" == ARGV[0]
    puts(Behavior.usage)
    exit(0)
  end

  require 'rexml/document'
  require 'control/sample_behavior'

  include SyslogWriter

  # Test code here
  # Typical behavior usage
  b = Behavior.new
  syslog("# Typical behavior usage")
  b.init
  b.execute
  b.abort
  sleep(1)

  # Typical behavior usage
  syslog("# Try to execute when not ready")
  b.execute
  b.abort
  sleep(1)

  # Make ready, then abort
  syslog("# Make ready, then abort")
  b.init
  b.init
  b.abort
  sleep(1)

  # Re-init and run again
  syslog("# Re-init and run again")
  b.init
  b.execute
  sleep(1)

  puts("Done")
end
