/*
 *  Copyright (c) 2018 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.
 */
// Based on the Quic implementation in Chromium.

#include "modules/congestion_controller/bbr/bandwidth_sampler.h"

#include <algorithm>

#include "rtc_base/logging.h"

namespace webrtc {
namespace bbr {
namespace {
constexpr int64_t kMaxTrackedPackets = 10000;
}

BandwidthSampler::BandwidthSampler()
    : total_data_sent_(DataSize::Zero()),
      total_data_acked_(DataSize::Zero()),
      total_data_sent_at_last_acked_packet_(DataSize::Zero()),
      last_acked_packet_sent_time_(),
      last_acked_packet_ack_time_(),
      last_sent_packet_(0),
      is_app_limited_(false),
      end_of_app_limited_phase_(0),
      connection_state_map_() {}

BandwidthSampler::~BandwidthSampler() {}

void BandwidthSampler::OnPacketSent(Timestamp sent_time,
                                    int64_t packet_number,
                                    DataSize data_size,
                                    DataSize data_in_flight) {
  last_sent_packet_ = packet_number;

  total_data_sent_ += data_size;

  // If there are no packets in flight, the time at which the new transmission
  // opens can be treated as the A_0 point for the purpose of bandwidth
  // sampling. This underestimates bandwidth to some extent, and produces some
  // artificially low samples for most packets in flight, but it provides with
  // samples at important points where we would not have them otherwise, most
  // importantly at the beginning of the connection.
  if (data_in_flight.IsZero()) {
    last_acked_packet_ack_time_ = sent_time;
    total_data_sent_at_last_acked_packet_ = total_data_sent_;

    // In this situation ack compression is not a concern, set send rate to
    // effectively infinite.
    last_acked_packet_sent_time_ = sent_time;
  }

  if (!connection_state_map_.IsEmpty() &&
      packet_number >
          connection_state_map_.last_packet() + kMaxTrackedPackets) {
    RTC_LOG(LS_WARNING)
        << "BandwidthSampler in-flight packet map has exceeded maximum "
           "number "
           "of tracked packets.";
  }

  bool success =
      connection_state_map_.Emplace(packet_number, sent_time, data_size, *this);
  if (!success)
    RTC_LOG(LS_WARNING) << "BandwidthSampler failed to insert the packet "
                           "into the map, most likely because it's already "
                           "in it.";
}

BandwidthSample BandwidthSampler::OnPacketAcknowledged(Timestamp ack_time,
                                                       int64_t packet_number) {
  ConnectionStateOnSentPacket* sent_packet_pointer =
      connection_state_map_.GetEntry(packet_number);
  if (sent_packet_pointer == nullptr) {
    return BandwidthSample();
  }
  BandwidthSample sample =
      OnPacketAcknowledgedInner(ack_time, packet_number, *sent_packet_pointer);
  connection_state_map_.Remove(packet_number);
  return sample;
}

BandwidthSample BandwidthSampler::OnPacketAcknowledgedInner(
    Timestamp ack_time,
    int64_t packet_number,
    const ConnectionStateOnSentPacket& sent_packet) {
  total_data_acked_ += sent_packet.size;
  total_data_sent_at_last_acked_packet_ = sent_packet.total_data_sent;
  last_acked_packet_sent_time_ = sent_packet.sent_time;
  last_acked_packet_ack_time_ = ack_time;

  // Exit app-limited phase once a packet that was sent while the connection is
  // not app-limited is acknowledged.
  if (is_app_limited_ && packet_number > end_of_app_limited_phase_) {
    is_app_limited_ = false;
  }

  // There might have been no packets acknowledged at the moment when the
  // current packet was sent. In that case, there is no bandwidth sample to
  // make.
  if (!sent_packet.last_acked_packet_sent_time ||
      !sent_packet.last_acked_packet_ack_time) {
    return BandwidthSample();
  }

  // Infinite rate indicates that the sampler is supposed to discard the
  // current send rate sample and use only the ack rate.
  DataRate send_rate = DataRate::Infinity();
  if (sent_packet.sent_time > *sent_packet.last_acked_packet_sent_time) {
    DataSize sent_delta = sent_packet.total_data_sent -
                          sent_packet.total_data_sent_at_last_acked_packet;
    TimeDelta time_delta =
        sent_packet.sent_time - *sent_packet.last_acked_packet_sent_time;
    send_rate = sent_delta / time_delta;
  }

  // During the slope calculation, ensure that ack time of the current packet is
  // always larger than the time of the previous packet, otherwise division by
  // zero or integer underflow can occur.
  if (ack_time <= *sent_packet.last_acked_packet_ack_time) {
    RTC_LOG(LS_WARNING)
        << "Time of the previously acked packet is larger than the time "
           "of the current packet.";
    return BandwidthSample();
  }
  DataSize ack_delta =
      total_data_acked_ - sent_packet.total_data_acked_at_the_last_acked_packet;
  TimeDelta time_delta = ack_time - *sent_packet.last_acked_packet_ack_time;
  DataRate ack_rate = ack_delta / time_delta;

  BandwidthSample sample;
  sample.bandwidth = std::min(send_rate, ack_rate);
  // Note: this sample does not account for delayed acknowledgement time.  This
  // means that the RTT measurements here can be artificially high, especially
  // on low bandwidth connections.
  sample.rtt = ack_time - sent_packet.sent_time;
  // A sample is app-limited if the packet was sent during the app-limited
  // phase.
  sample.is_app_limited = sent_packet.is_app_limited;
  return sample;
}

void BandwidthSampler::OnPacketLost(int64_t packet_number) {
  connection_state_map_.Remove(packet_number);
}

void BandwidthSampler::OnAppLimited() {
  is_app_limited_ = true;
  end_of_app_limited_phase_ = last_sent_packet_;
}

void BandwidthSampler::RemoveObsoletePackets(int64_t least_unacked) {
  while (!connection_state_map_.IsEmpty() &&
         connection_state_map_.first_packet() < least_unacked) {
    connection_state_map_.Remove(connection_state_map_.first_packet());
  }
}

DataSize BandwidthSampler::total_data_acked() const {
  return total_data_acked_;
}

bool BandwidthSampler::is_app_limited() const {
  return is_app_limited_;
}

int64_t BandwidthSampler::end_of_app_limited_phase() const {
  return end_of_app_limited_phase_;
}

BandwidthSampler::ConnectionStateOnSentPacket::ConnectionStateOnSentPacket(
    Timestamp sent_time,
    DataSize size,
    const BandwidthSampler& sampler)
    : sent_time(sent_time),
      size(size),
      total_data_sent(sampler.total_data_sent_),
      total_data_sent_at_last_acked_packet(
          sampler.total_data_sent_at_last_acked_packet_),
      last_acked_packet_sent_time(sampler.last_acked_packet_sent_time_),
      last_acked_packet_ack_time(sampler.last_acked_packet_ack_time_),
      total_data_acked_at_the_last_acked_packet(sampler.total_data_acked_),
      is_app_limited(sampler.is_app_limited_) {}

BandwidthSampler::ConnectionStateOnSentPacket::ConnectionStateOnSentPacket()
    : sent_time(Timestamp::MinusInfinity()),
      size(DataSize::Zero()),
      total_data_sent(DataSize::Zero()),
      total_data_sent_at_last_acked_packet(DataSize::Zero()),
      last_acked_packet_sent_time(),
      last_acked_packet_ack_time(),
      total_data_acked_at_the_last_acked_packet(DataSize::Zero()),
      is_app_limited(false) {}

BandwidthSampler::ConnectionStateOnSentPacket::~ConnectionStateOnSentPacket() {}

}  // namespace bbr
}  // namespace webrtc
