#!/usr/bin/env ruby

LKP_SRC = ENV['LKP_SRC'] || File.dirname(File.dirname(File.realpath($PROGRAM_NAME)))

require 'gnuplot'
require 'optparse'
require "#{LKP_SRC}/lib/statistics"
require "#{LKP_SRC}/lib/stats"
require "#{LKP_SRC}/lib/yaml"
require "#{LKP_SRC}/lib/plot"
require "#{LKP_SRC}/lib/constant"

$opt_output_path = 'output.png'
$x_stat_key = nil
$x_relative = false
$xtics = false
$y_min = nil
$y_relative = false
$x_range = [nil, nil]
$opt_diff = nil
$opt_diff_distance = 1

opt_parser = OptionParser.new do |opts|
  opts.banner = 'Usage: mplot matrix.json stat_field [matrix.json stat_filed]... [OPTION...]'
  opts.separator ''
  opts.separator 'Example:'
  opts.separator ''

  opts.separator "mplot #{RESULT_ROOT_DIR}/fat/dd-write/1HDD-JBOD-cfq-btrfs-100dd/x86_64-rhel/matrix.json vmstat.system.in"
  opts.separator ''
  opts.separator 'options:'

  opts.on('-o FILE', '--output FILE', 'output file name') do |fn|
    $opt_output_path = fn
  end

  opts.on('-x KEY', '--x-stat-key KEY', 'x axis stat key name') do |key|
    $x_stat_key = key
  end

  opts.on('-r', '--relative-x', 'x axis relative to the first element') do
    $x_relative = true
  end

  opts.on('--xtics', 'draw x tics') do
    $xtics = true
  end

  opts.on('--y-min YMIN', 'The y range minimum') do |ymin|
    $y_min = ymin
  end

  opts.on('--relative-y', 'y axis relative to the first element') do
    $y_relative = true
  end

  opts.on('--x-range RANGE', 'The x range') do |range|
    $x_range = range.split(',').map(&:to_i)
  end

  opts.on('-d', '--diff', 'draw diff figure') do
    $opt_diff = true
  end

  opts.on('--diff-distance DISTANCE', 'The diff distance') do |distance|
    $opt_diff_distance = distance.to_i
  end

  opts.on_tail('-h', '--help', 'show help message') do
    puts opts
    exit
  end
end

opt_parser.parse!(ARGV)

if ARGV.empty? || ARGV.length.odd?
  puts opt_parser
  exit
end

def plot_it(matrix_stat_arr)
  plotter = MMatrixPlotter.new
  plotter.set_x_stat_key($x_stat_key)
         .set_xtics($xtics)
         .set_y_range([$y_min, nil])
         .set_x_range($x_range)
  lines = []
  matrix_stat_arr.each_slice(2) do |matrix_fn, stat|
    matrix = load_json matrix_fn
    if $x_relative
      rel_x = "rel-#{$x_stat_key}"
      xs = matrix[$x_stat_key]
      x0 = xs.first
      matrix[rel_x] = xs.map { |xi| xi - x0 }
      plotter.set_x_stat_key(rel_x)
    end
    if $opt_diff
      dstat = "diff#{$opt_diff_distance}-#{stat}"
      ys = matrix[stat]
      next unless ys

      dys = ($opt_diff_distance...ys.length).map { |i| ys[i] - ys[i - $opt_diff_distance] }
      matrix[dstat] = [0] * $opt_diff_distance + dys
      stat = dstat
    elsif $y_relative
      rstat = "rel-#{stat}"
      ys = matrix[stat]
      next unless ys

      y0 = ys[0]
      rys = ys.map { |yi| yi - y0 }
      matrix[rstat] = rys
      stat = rstat
    end
    lines << [matrix, stat, stat]
  end
  plotter.set_output_file_name($opt_output_path)
         .set_lines(lines)
         .plot
end

plot_it(ARGV)
