#!/usr/bin/env ruby

#%# family=auto
#%# capabilities=autoconf

require 'English'
require 'strscan'

label = ENV["label"]

@log_path = ENV["log_path"]

command = ARGV.shift

case command
when "autoconf", "detect"
  if @log_path.nil?
    puts "no (query log file path isn't specified by env.log_path)"
    exit(false)
  end
  unless File.readable?(@log_path)
    puts "no (query log file isn't readable: <#{@log_path}>)"
    exit(false)
  end
  puts "yes"
  exit(true)
when "config"
  if label.nil?
    title = "groonga: query performance"
  else
    title = "groonga: #{label}: query performance"
  end
  puts <<EOF
graph_title #{title}
graph_vlabel seconds
graph_category groonga
graph_info groonga query performance

longest.label Longest
average.label Average
median.label Median
EOF
  exit(true)
end

class ReverseLineReader
  def initialize(io)
    @io = io
    @io.seek(0, IO::SEEK_END)
    @buffer = ""
    @data = ""
  end

  def each
    separator = $/
    separator_length = separator.length
    while read_to_buffer
      loop do
        index = @buffer.rindex(separator, @buffer.length - 1 - separator_length)
        break if index.nil? or index.zero?
        last_line = @buffer.slice!((index + separator_length)..-1)
        yield(last_line)
      end
    end
    yield(@buffer) unless @buffer.empty?
  end

  private
  BYTES_PER_READ = 4096
  def read
    position = @io.pos
    if position < BYTES_PER_READ
      bytes_per_read = position
    else
      bytes_per_read = BYTES_PER_READ
    end

    if bytes_per_read.zero?
      @data.replace("")
    else
      @io.seek(-bytes_per_read, IO::SEEK_CUR)
      @io.read(bytes_per_read, @data)
      @io.seek(-bytes_per_read, IO::SEEK_CUR)
    end

    @data
  end

  def read_to_buffer
    data = read
    if data.empty?
      false
    else
      @buffer.insert(0, data)
      true
    end
  end
end

span = 60 * 5 # 5min
mega = 1_000_000.0
now = Time.now
elapsed_times = []
File.open(@log_path) do |log_file|
  ReverseLineReader.new(log_file).each do |line|
    case line
    when /\A(\d+)-(\d+)-(\d+) (\d+):(\d+):(\d+)\.(\d+)\|([\da-f])+\|<(\d+) rc=0$/
      _, year, month, day, hour, minutes, seconds, milliseconds,
        context, elapsed = $LAST_MATCH_INFO.to_a
      time_stamp = Time.local(year, month, day,
                              hour, minutes, seconds, milliseconds)
      difference = now - time_stamp
      break if difference > span
      elapsed_in_micro_seconds = elapsed.to_i / mega
      elapsed_times << elapsed_in_micro_seconds
    end
  end
end

sorted_elapsed_times = elapsed_times.sort
if sorted_elapsed_times.empty?
  longest = 0
  average = 0
  median = 0
else
  longest = sorted_elapsed_times.last
  average = sorted_elapsed_times.inject(&:+) / sorted_elapsed_times.size.to_f
  median = sorted_elapsed_times[sorted_elapsed_times.size / 2]
end

puts "longest.value #{longest}"
puts "average.value #{average}"
puts "median.value #{median}"
