#!/usr/bin/python2
#  Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
#
#  Use of this source code is governed by a BSD-style license
#  that can be found in the LICENSE file in the root of the source
#  tree. An additional intellectual property rights grant can be found
#  in the file PATENTS.  All contributing project authors may
#  be found in the AUTHORS file in the root of the source tree.

#  To run this script please copy "out/<build_name>//pyproto/webrtc/modules/
#  audio_coding/audio_network_adaptor/debug_dump_pb2.py" to this folder.
#  The you can run this script with:
#  "python parse_ana_dump.py -m uplink_bandwidth_bps -f dump_file.dat"
#  You can add as may metrics or decisions to the plot as you like.
#  form more information call:
#  "python parse_ana_dump.py --help"

import struct
from optparse import OptionParser

import matplotlib.pyplot as plt

import debug_dump_pb2


def GetNextMessageSize(file_to_parse):
  data = file_to_parse.read(4)
  if data == '':
    return 0
  return struct.unpack('<I', data)[0]


def GetNextMessageFromFile(file_to_parse):
  message_size = GetNextMessageSize(file_to_parse)
  if message_size == 0:
    return None
  try:
    event = debug_dump_pb2.Event()
    event.ParseFromString(file_to_parse.read(message_size))
  except IOError:
    print 'Invalid message in file'
    return None
  return event


def InitMetrics():
  metrics = {}
  event = debug_dump_pb2.Event()
  for metric in event.network_metrics.DESCRIPTOR.fields:
    metrics[metric.name] = {'time': [], 'value': []}
  return metrics


def InitDecisions():
  decisions = {}
  event = debug_dump_pb2.Event()
  for decision in event.encoder_runtime_config.DESCRIPTOR.fields:
    decisions[decision.name] = {'time': [], 'value': []}
  return decisions


def ParseAnaDump(dump_file_to_parse):
  with open(dump_file_to_parse, 'rb') as file_to_parse:
    metrics = InitMetrics()
    decisions = InitDecisions()
    first_time_stamp = None
    while True:
      event = GetNextMessageFromFile(file_to_parse)
      if event == None:
        break
      if first_time_stamp == None:
        first_time_stamp = event.timestamp
      if event.type == debug_dump_pb2.Event.ENCODER_RUNTIME_CONFIG:
        for decision in event.encoder_runtime_config.DESCRIPTOR.fields:
          if event.encoder_runtime_config.HasField(decision.name):
            decisions[decision.name]['time'].append(event.timestamp -
                                                    first_time_stamp)
            decisions[decision.name]['value'].append(
                getattr(event.encoder_runtime_config, decision.name))
      if event.type == debug_dump_pb2.Event.NETWORK_METRICS:
        for metric in event.network_metrics.DESCRIPTOR.fields:
          if event.network_metrics.HasField(metric.name):
            metrics[metric.name]['time'].append(event.timestamp -
                                                first_time_stamp)
            metrics[metric.name]['value'].append(
                getattr(event.network_metrics, metric.name))
  return (metrics, decisions)


def main():
  parser = OptionParser()
  parser.add_option(
      "-f", "--dump_file", dest="dump_file_to_parse", help="dump file to parse")
  parser.add_option(
      '-m',
      '--metric_plot',
      default=[],
      type=str,
      help='metric key (name of the metric) to plot',
      dest='metric_keys',
      action='append')

  parser.add_option(
      '-d',
      '--decision_plot',
      default=[],
      type=str,
      help='decision key (name of the decision) to plot',
      dest='decision_keys',
      action='append')

  options = parser.parse_args()[0]
  if options.dump_file_to_parse == None:
    print "No dump file to parse is set.\n"
    parser.print_help()
    exit()
  (metrics, decisions) = ParseAnaDump(options.dump_file_to_parse)
  metric_keys = options.metric_keys
  decision_keys = options.decision_keys
  plot_count = len(metric_keys) + len(decision_keys)
  if plot_count == 0:
    print "You have to set at least one metric or decision to plot.\n"
    parser.print_help()
    exit()
  plots = []
  if plot_count == 1:
    f, mp_plot = plt.subplots()
    plots.append(mp_plot)
  else:
    f, mp_plots = plt.subplots(plot_count, sharex=True)
    plots.extend(mp_plots.tolist())

  for key in metric_keys:
    plot = plots.pop()
    plot.grid(True)
    plot.set_title(key + " (metric)")
    plot.plot(metrics[key]['time'], metrics[key]['value'])
  for key in decision_keys:
    plot = plots.pop()
    plot.grid(True)
    plot.set_title(key + " (decision)")
    plot.plot(decisions[key]['time'], decisions[key]['value'])
  f.subplots_adjust(hspace=0.3)
  plt.show()

if __name__ == "__main__":
  main()
