libs = %W(
            #{File.dirname(__FILE__)}/mrsh_settings.rb
            #{File.dirname(__FILE__)}/mrsh_reporter.rb
          )

libs.each {|lib| require lib}

require 'resolv'

class Machine
  def initialize(host,config)
    @host   = host
    @config = config
    
    @host.hostname = @host.hostname.gsub(/\..*$/,'') # This might not make sense in the general use case
  end
  def ==(b)
    return @host.hostname == b.hostname
  end
  def <=>(b)
    return @host.hostname <=> b.hostname
  end
  def process
    resolve or return
    
    ping?   or return
    
    execute if rpc?
  end
  def resolve
    @host.ip        = Resolv.getaddress @host.hostname
  rescue Resolv::ResolvError => e
    @host.ip        = nil
    @host.status    = :nodns
  ensure
    @host.resolved  = @host.ip.nil? ? false : true
  end
  def ping?
    @host.online  = false
    @host.status  = :offline
    
    command = sprintf @config.ping, @host.hostname
    output  = %x( #{command} ).chomp
    status  = ($?.exitstatus == 0)
    
    if (status)
      @host.online      = true
      @host.status      = :online
    elsif (output.match(/no answer from/) or output.match(/ 0( packets)? received,/))
      # Handled by default values
    elsif (output.match(/unknown host/)
      @host.resolved    = false
      @host.status      = :nodns
    else
      @host.ping_output = output.split.chomp
    end
    
    return @host.online
  end
  def execute
    @host.output  = Array.new
    flags         = '-T -o BatchMode=yes -nq'
    
    return unless @config.command
    
    begin
      Timeout::timeout(@config.timeout) do
        IO.popen(%Q{ssh #{flags} #{@host.hostname} "#{config.command}" 2>&1, "r") do |pipe|
          while (line = pipe.gets) do
            @host.output.push [ Time.now, line.chomp ]
          end
          pipe.close
          @host.returncode = $?.exitstatus
        end
      end
    rescue Timeout::Error
      @host.returncode = 999
      @host.output.push [ Time.now, "-- Timeout encountered, command did not return within #{@config.timeout} seconds -- " ]
    rescue Exception => e
      @host.returncode = 998
      @host.output.push [ Time.now, " Exception: #{ e }" ]
      e.backtrace.each do |line|
        @host.output.push [ Time.now, line ]
      end
    end
  end
  def rpc?
    not @host.os.match(/Windows/Firmware/ESXi/i)
  end
  def method_missing(func,*args,&block)
    @host.send(func,*args,&block)
  end
end