=begin
 ******************************************************************************
 * Copyright 1990-2009 MBARI
 * MBARI Proprietary Information. All rights reserved.
 ******************************************************************************
 * Summary  : What is contained within the file
 * Filename : 
 * Author   : 
 * Project  : Benthic Rover
 * Version  : 
 * Created  : 
 * Modified : 
 ******************************************************************************
=end

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

##########
# Deployment class - Container object for a Rover deployment specification.
# Contains Plan objects, which in turn contain behavior objects.
#
class Deployment
  include Dump
  include SyslogWriter

  attr_reader :name, :plans, :current_plan, :plan_sequence_number, \
              :behaviors, :hibernate, :resuming

  #####
  # Constructor - Create a Deployment object using the xml element argument
  #
  #               d_doc:REXML::Element
  def initialize(d_doc)
    @name = "deployment"
    @plans = Array.new
    @behaviors = Array.new
    @current_plan = nil
    @plan_sequence_number = 1
    @abort_plan = nil
    @hibernate = false
    @resuming = false

    # Give me a name
    #
    dname = d_doc.root.attributes["name"]
    @name = dname if dname
    puts("Supervisor...loading deployment #{@name}")

    # Simulation?
    #
    if ((sim = d_doc.root.attributes["sim"]) &&
	(sim.upcase == "TRUE"))
      @sim = true
    end

    # Should I hibernate?
    #
    if ((hib = d_doc.root.attributes["hibernate"]) &&
	(hib.upcase == "TRUE"))
      @hibernate = true
    end

    # Create a Plan object for each Plan element in the Deployment doc.
    #
    d_doc.root.elements.each do |e|
      e_type = e.name.to_s
      case e_type.downcase
      when "plan"
        puts("Supervisor...loading plan #{e.attributes['name']}")
        p = Plan.new(e)
        @plans.push(p)
        sleep(0.2)

      when "abortplan"
        puts("Supervisor...loading abort plan #{e.attributes['name']}")
        p = Plan.new(e)
        @abort_plan = p
        sleep(0.2)

      # Handle directives (CommsServer, etc)
      # These are behavior-like elements in deployment. Think of them
      # as non-sequential behaviors that run as part of the deployment,
      # not part of a plan.
      #
      when "commserver"
        puts("Supervisor...loading CommServer")
        b = Factory.behavior(e)
        @behaviors.push(b) if (b)

      when "batterymonitor"
        puts("Supervisor...loading BatteryMonitor")
        b = Factory.behavior(e)
        @behaviors.push(b) if (b)

      end

    end
  end
  #####


  #####
  def run
    RoverThread.new do
      start_behaviors
      execute_plans
    end
  end
  #####


  #####
  # Start non-sequential behaviors
  #
  def start_behaviors
    @behaviors.each do |b|
      b.run
    end
  end
  #####


  #####
  def stop_behaviors
    @behaviors.each do |b|
      b.abort
    end
  end
  #####


  #####
  # This method is called before resuming execution following
  # hibernation. We reset the state of the deployment here.
  #
  def resume_init
    @plan_sequence_number = 1
    this_plan = @plans[@plan_sequence_number-1]
    this_plan.resume_init
  end
  #####


  #####
  #
  def execute_plans
    # Iterate over the plans in the deployment.
    # Initialize and execute each.
    #
    console("========== Executing Deployment #{@name} ==========")
    for i in @plan_sequence_number..@plans.length
      this_plan = @plans[@plan_sequence_number-1]
      begin
        @current_plan = this_plan
        this_plan.init(@plan_sequence_number)
        this_plan.execute
      rescue Hibernate => e
        length = e.length_in_minutes
        syslog("_ prepare for hibernation")
        syslog("_ signal system for #{length} minute hibernation")


      ensure
      end
    end
    @current_plan = nil
  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
  # Test code here
  doc = REXML::Document.new(File.new(Misc.find_plan("test_deploy.xml")))
  d = Deployment.new(doc.root)
  puts(d.dump)
  #d.execute
end
