require 'thread'

# The Runnable module is a generic mixin for including state and
# status information in a class
module ServiceState
  # state constants
  NOT_STARTED = 0
  STARTED = 1
  STOPPED = 2
  CONFIGURED = 3
  
  attr_reader :startTime, :endTime
  
  # Initialize the state information
  def initializeState()
    @configured = false
    @startTime = 0
    @stopTime = 0
    
    @stateMutex = Mutex.new()
    @stopWhen = nil
    setState(NOT_STARTED)
  end
  
  # Set the callback for when someone calls setState. You
  # will be passed the state CONSTANT being set
  def onStateChange(&callbackBlock)
    @stateCallback = callbackBlock
  end
  
  # All methods, inside this class or not, should use this
  # method to change the state of the JobRunner
  # @param newState The new state value
  def setState(newState)
    @stateMutex.synchronize {
      if newState == CONFIGURED then
	@configured = true
      else
	@state = newState
	if isStarted? then
	  @startTime = Time.now()
	elsif isStopped?
	  @stopTime = Time.now()
	end
      end
    }
    
    if defined?(@stateCallback) then
      @stateCallback.call(newState)
    end
  end
  
  def isConfigured?
    return @configured
  end

  def isStarted?
    return @state == STARTED
  end

  def isStopped?
    if @state == STOPPED then
      return true
    elsif @stopWhen && @stopWhen.call() then
      setState(STOPPED)
      return true
    else
      return false
    end
  end   

  def stopWhen(&block)
    @stopWhen = block
  end
end
