=begin
 ******************************************************************************
 * Copyright 1990-2009 MBARI
 * MBARI Proprietary Information. All rights reserved.
 ******************************************************************************
 * Summary  : Implemetation of the Rover OptodeMeasure behavior
 * Filename : optode_measure.rb
 * Author   : Henthorn
 * Project  : Benthic Rover
 * Version  : 1
 * Created  : Dec 08
 * Modified : 
 ******************************************************************************
=end

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

require "utils/misc"
require "control/behavior"
require 'device/rover'

##########
# OptodeMeasure class.
# Controls the optode measurement behavior of a Rover deployment.
#
class OptodeMeasure < Behavior
  include RoverTime

  attr_reader :name, :duration, :iterations, :current_iteration, :interval

  #####
  # Accept a behavior element and extract parameters
  #
  def initialize(p_behavior_element)
    super

    @iterations = 1          # Default iterations is 1
    @duration = 1            # Default duration is 1 minute
    @interval = 1            # Default interval is 1 minute
    @shutdown_interval = 3   # Minimum interval required to initiate shutdown
    @current_iteration = 1

    load_attrs(p_behavior_element)
  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

        # Number of measurement iterations
        when "iterations"
        @iterations = attrs[k].to_i

        # Optode duration
        when "duration"
        @duration = attrs[k].to_f

        # Interval duration
        when "interval"
        @interval = attrs[k].to_f

        # Interval duration
        when "shutdown_interval"
        @shutdown_interval = attrs[k].to_f

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

      end
    end

    # Option: Throw an exception if there any required attributes
    # 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")
    self.data_home = p_seq_number

    # Perform initialization procedures
    @state = READY
  end
  #####




  #####
  # Create directory to hold optode data files
  #
  def data_home=(p_seq_num)
    mn_zero = p_seq_num > 9 ? "" : "0"
    home_prefix = mn_zero + p_seq_num.to_s
    DataLog.behavior_data_home = home_prefix + "-optodes"
  end
  #####


  #####
  # Execute the behavior
  #
  def execute
    # Execute if ready.
    unless (@state == READY)
      syslog("! #{name} not in ready state")
      return
    end

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

    # Perform the behavior
    # 
    begin

      # Acquire_data - sleep or shutdown for the interval - repeat
      #
      for i in @current_iteration..@iterations
        begin_stirring()

        syslog("_ iteration #{i} of #{@iterations} data acquisition")
        acquire_data()

        # No need to sleep after the last data acquisition
        #
        break if (@current_iteration >= @iterations)

        # Signal a shutdown if configured to do so.
        # Otherwise just sleep
        #
        if (true) #(deployment.shutdown && deployment.shutdown_min>=@interval)
          syslog("_ Signaling hibernate for #{@interval} minutes")
          stop_optodes()
          raise Hibernate.new(@interval)

        else
          syslog("_ Simply wait here for #{@interval} minutes")
          r_sleep(@interval*60)
        end

      end

      stop_stirring()
    ensure
#      self.clean_up
    end
  end
  #####


  #####
  def begin_stirring
    Rover.instance.relay.stirOn
  end
  #####


  #####
  def stop_stirring
    Rover.instance.relay.stirOff
  end
  #####


  #####
  def acquire_data
    start_optodes()
    sleep(@duration*60)
    stop_optodes()
  end
  #####


  #####
  # Start optode threads and turn on power
  #
  def start_optodes
    # Start Aanderaa drivers
    Rover.instance.ref_optode.run(DataLog.behavior_data_home)
    Rover.instance.port_optode.run(DataLog.behavior_data_home)
    Rover.instance.starboard_optode.run(DataLog.behavior_data_home)
    Rover.instance.starboardB_optode.run(DataLog.behavior_data_home)
    Rover.instance.relay.optodesOn
  end
  #####

  #####
  # Stop optode threads and turn off power
  #
  def stop_optodes
    # Stop Aanderaa drivers
    Rover.instance.relay.optodesOff
    Rover.instance.ref_optode.stop
    Rover.instance.port_optode.stop
    Rover.instance.starboard_optode.stop
    Rover.instance.starboardB_optode.stop
  end
  #####


  #####
  # Clean-up steps in the case of an exception or an abort
  #
  def clean_up
    stop_optodes()
    stop_stirring()
    @state = FINISHED
  end
  #####

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

      # Kill the run thread, clean up
      @my_thread.kill if @my_thread
      clean_up
    else
      syslog("_ #{@name} not executing, aborting...")
    end
  end
  #####


  #####
  def OptodeMeasure.test
    require 'rexml/document'
    require 'device/rover'

    Rover.instance

    # Test code here
    # Straight ahead test
    puts("Monitor testlogs/syslog.csv")
    puts("Straight ahead test")
    measure_xml = REXML::Document.new(File.new(Misc.find_plan("test_measure.xml")))
    om = OptodeMeasure.new(measure_xml.root)
    om.init
    puts(om.dump)
    om.execute

    # Abort test in thread
    puts("Abort test")
    om.init
    t=om.run
    sleep(2)
    puts("Aborting now...")
    om.abort
    t.join

  end
  #####

end

##
# Standalone unit test (recommended)
# Include at the end of the file as a hook to run a unit test of
# the code from the command line (e.g., "$ ruby  my_class.rb")
#
if __FILE__ == $0
  OptodeMeasure.test
  puts("Done")
end
