#  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/rtc_tools/
#  network_tester/network_tester_packet_pb2.py" next to this script.
#  The you can run this script with:
#  "python parse_packet_log.py -f packet_log.dat"
#  for more information call:
#  "python parse_packet_log.py --help"

from optparse import OptionParser
import struct

import matplotlib.pyplot as plt

import network_tester_packet_pb2

def GetSize(file_to_parse):
  data = file_to_parse.read(1)
  if data == '':
    return 0
  return struct.unpack('<b', data)[0]


def ParsePacketLog(packet_log_file_to_parse):
  packets = []
  with open(packet_log_file_to_parse, 'rb') as file_to_parse:
    while True:
      size = GetSize(file_to_parse)
      if size == 0:
        break
      try:
        packet = network_tester_packet_pb2.NetworkTesterPacket()
        packet.ParseFromString(file_to_parse.read(size))
        packets.append(packet)
      except IOError:
        break
  return packets


def GetTimeAxis(packets):
  first_arrival_time = packets[0].arrival_timestamp
  return [(packet.arrival_timestamp - first_arrival_time) / 1000000.0
          for packet in packets]


def CreateSendTimeDiffPlot(packets, plot):
  first_send_time_diff = (
      packets[0].arrival_timestamp - packets[0].send_timestamp)
  y = [(packet.arrival_timestamp - packet.send_timestamp) - first_send_time_diff
       for packet in packets]
  plot.grid(True)
  plot.set_title("SendTime difference [us]")
  plot.plot(GetTimeAxis(packets), y)


class MovingAverageBitrate(object):

  def __init__(self):
    self.packet_window = []
    self.window_time = 1000000
    self.bytes = 0
    self.latest_packet_time = 0
    self.send_interval = 0

  def RemoveOldPackets(self):
    for packet in self.packet_window:
      if (self.latest_packet_time - packet.arrival_timestamp >
          self.window_time):
        self.bytes = self.bytes - packet.packet_size
        self.packet_window.remove(packet)

  def AddPacket(self, packet):
    """This functions returns bits / second"""
    self.send_interval = packet.arrival_timestamp - self.latest_packet_time
    self.latest_packet_time = packet.arrival_timestamp
    self.RemoveOldPackets()
    self.packet_window.append(packet)
    self.bytes = self.bytes + packet.packet_size
    return self.bytes * 8


def CreateReceiveBiratePlot(packets, plot):
  bitrate = MovingAverageBitrate()
  y = [bitrate.AddPacket(packet) for packet in packets]
  plot.grid(True)
  plot.set_title("Receive birate [bps]")
  plot.plot(GetTimeAxis(packets), y)


def CreatePacketlossPlot(packets, plot):
  packets_look_up = {}
  first_sequence_number = packets[0].sequence_number
  last_sequence_number = packets[-1].sequence_number
  for packet in packets:
    packets_look_up[packet.sequence_number] = packet
  y = []
  x = []
  first_arrival_time = 0
  last_arrival_time = 0
  last_arrival_time_diff = 0
  for sequence_number in range(first_sequence_number, last_sequence_number + 1):
    if sequence_number in packets_look_up:
      y.append(0)
      if first_arrival_time == 0:
        first_arrival_time = packets_look_up[sequence_number].arrival_timestamp
      x_time = (packets_look_up[sequence_number].arrival_timestamp -
                first_arrival_time)
      if last_arrival_time != 0:
        last_arrival_time_diff = x_time - last_arrival_time
      last_arrival_time = x_time
      x.append(x_time / 1000000.0)
    else:
      if last_arrival_time != 0 and last_arrival_time_diff != 0:
        x.append((last_arrival_time + last_arrival_time_diff) / 1000000.0)
        y.append(1)
  plot.grid(True)
  plot.set_title("Lost packets [0/1]")
  plot.plot(x, y)


def main():
  parser = OptionParser()
  parser.add_option("-f",
                    "--packet_log_file",
                    dest="packet_log_file",
                    help="packet_log file to parse")

  options = parser.parse_args()[0]

  packets = ParsePacketLog(options.packet_log_file)
  f, plots = plt.subplots(3, sharex=True)
  plt.xlabel('time [sec]')
  CreateSendTimeDiffPlot(packets, plots[0])
  CreateReceiveBiratePlot(packets, plots[1])
  CreatePacketlossPlot(packets, plots[2])
  f.subplots_adjust(hspace=0.3)
  plt.show()


if __name__ == "__main__":
  main()
