require 'puppet/util/instance_loader'
require 'puppet/reports'

# A simple server for triggering a new run on a Puppet client.
class Puppet::Network::Handler
  class Report < Handler
    desc "Accepts a Puppet transaction report and processes it."

    @interface = XMLRPC::Service::Interface.new("puppetreports") { |iface|
      iface.add_method("string report(array)")
    }

    # Add a new report type.
    def self.newreport(name, options = {}, &block)
      Puppet.warning "The interface for registering report types has changed; use Puppet::Reports.register_report for report type #{name}"
      Puppet::Reports.register_report(name, options, &block)
    end

    def initialize(*args)
      super
      Puppet.settings.use(:main, :reporting, :metrics)
    end

    # Accept a report from a client.
    def report(report, client = nil, clientip = nil)
      # Unescape the report
      report = CGI.unescape(report) unless @local

      Puppet.info "Processing reports #{reports().join(", ")} for #{client}"
      begin
        process(report)
      rescue => detail
        Puppet.err "Could not process report for #{client}: #{detail}"
        puts detail.backtrace if Puppet[:trace]
      end
    end

    private

    # Process the report using all of the existing hooks.
    def process(yaml)
      return if Puppet[:reports] == "none"

      # First convert the report to real objects
      begin
        report = YAML.load(yaml)
      rescue => detail
        Puppet.warning "Could not load report: #{detail}"
        return
      end

      # Used for those reports that accept yaml
      client = report.host

      reports.each do |name|
        if mod = Puppet::Reports.report(name)
          # We have to use a dup because we're including a module in the
          # report.
          newrep = report.dup
          begin
            newrep.extend(mod)
            newrep.process
          rescue => detail
            puts detail.backtrace if Puppet[:trace]
            Puppet.err "Report #{name} failed: #{detail}"
          end
        else
          Puppet.warning "No report named '#{name}'"
        end
      end
    end

    # Handle the parsing of the reports attribute.
    def reports
      # LAK:NOTE See http://snurl.com/21zf8  [groups_google_com]
      x = Puppet[:reports].gsub(/(^\s+)|(\s+$)/, '').split(/\s*,\s*/)
    end
  end
end

