require 'set'

class MetricsCollector
  def initialize
    @ids = Set.new
    @values = {}
  end
  
  def new_metric(id, value)
    if !is_test? id
      process_metric(id, value)
    end
  end
  
  def add_metric(id, value)
    if @ids.include?(id)
      process_metric(id, value, true)
    else
      new_metric(id, value)
    end
  end

  def metrics
    @ids.collect do |id|
      {:id => id, :value => @values[id]}
    end
  end
  
  def average
    total = metrics.inject(0) do |sum, metric|
      sum + metric[:value]
    end
    total/metrics.size
  end
  
  def std_dev
    mean = average
    total = metrics.inject(0) do |sum, metric|
      sum + (metric[:value] - mean)**2
    end
    Math.sqrt(total/(metrics.size - 1))
  end
  
  def min
    minMetric = metrics.min do |a, b|
      a[:value] <=> b[:value]
    end
    minMetric[:value]
  end
  
  def max
    maxMetric = metrics.max do |a, b|
      a[:value] <=> b[:value]
    end
    maxMetric[:value]
  end
  
  def result
    "# Average\tStdDev\tMin\tMax\tClasses: #{metrics.size}\n#{average}\t#{std_dev}\t#{min}\t#{max}"
  end

  private
  
  def process_metric(id, value, add=false)
    @ids.add(id)
    @values[id] = add ? @values[id] + value : value
  end
  
  def is_test?(id)
    id =~ /Test/i
  end
  
end
