=begin
 ******************************************************************************
 * Copyright 1990-2010 MBARI
 * MBARI Proprietary Information. All rights reserved.
 ******************************************************************************
 * Summary  : Communication utilities that acquire messages and dispatch to
 *          : to message handlers.
 * Filename : comms.rb
 * Author   : Henthorn
 * Project  : Benthic Rover
 * Version  : 1
 * Created  : Feb 2010
 * Modified : 
 ******************************************************************************
=end

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

#

# Now use subdirectory name for remaining rover-code require statements.
# Example:
# require 'utils/datalog'
#

##########
# Comms
# Comms attempts to abstracts the acquisition of messages from an external
# channel and simply dispatchs messages to a generic message handler object.
# The mechanics are very simple. The first revision was written for an
# acoustic modem, but is intended to also be used for other forms of comms
# (socket, pipes, etc).
#
class Comms
  include SyslogWriter

  attr_reader :name, :dev, :handler

  #####
  # initialize
  # name: "string"
  # device: Communication device driver (e.g., BenthosModem object)
  # msg_handler: Message handler object. Must have a public method
  #              handle_comms_msg(string_msg, source) which should be
  #              non-blocking.
  #
  def initialize(name, device, msg_handler)
    @name = name
    @dev  = device         # The communication device interface
    @handler = msg_handler # Message handler object
    @thread = nil
  end
  #####


  #####
  # Start a listening thread to wait for a message to arrive
  #
  def run
    @thread = RoverThread.new do
      while (true)
        msg = @dev.get_msg
        dispatch(msg) if (msg.length > 0)
      end
    end
  end
  #####


  #####
  # Dispatch the message to the handler. The handler 
  #
  def dispatch(msg)
    begin
      syslog("_ dispatching #{msg} to handler")
      @handler.handle_comms_msg(msg, self)
    rescue Exception
      syslog("! Exception raised in handler")
    end
  end
  #####


  #####
  # Send the message to the client
  #
  def send_msg(msg)
    begin
      syslog("_ sending #{msg} to client")
      @dev.send_msg(msg)
    rescue Exception
      syslog("! Exception raised in handler")
    end
  end
  #####


  #####
  # Is the listener running
  #
  def running?
    return true if (@thread && @thread.alive?)
    return false
  end
  #####


  #####
  # Stop the listener
  #
  def stop
    @thread.kill if (@thread && @thread.alive?)
    @thread = nil
  end
  #####


  #####
  # Test method. Use to run standard test of MyClass from
  # a ruby script.
  # 
  #def MyClass.test
  #end

end

class SampleHandler
  include SyslogWriter
  
  def handle_comms_msg(msg, channel=nil)
    syslog("_ got comms message '#{msg}'") if (msg)
    sleep(1)
    channel.send_msg("Ack") if (msg && channel)
  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 including the command line options
# (e.g., "$ ruby my_class.rb --sim").
#
if __FILE__ == $0
  # Test code here. Using the MyClass.test function is often enough
  # MyClass.test
end
