// Copyright (c) 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "quic/tools/quic_tcp_like_trace_converter.h"

#include "quic/core/quic_constants.h"
#include "quic/platform/api/quic_bug_tracker.h"

namespace quic {

QuicTcpLikeTraceConverter::QuicTcpLikeTraceConverter()
    : largest_observed_control_frame_id_(kInvalidControlFrameId),
      connection_offset_(0) {}

QuicTcpLikeTraceConverter::StreamOffsetSegment::StreamOffsetSegment()
    : connection_offset(0) {}

QuicTcpLikeTraceConverter::StreamOffsetSegment::StreamOffsetSegment(
    QuicStreamOffset stream_offset,
    uint64_t connection_offset,
    QuicByteCount data_length)
    : stream_data(stream_offset, stream_offset + data_length),
      connection_offset(connection_offset) {}

QuicTcpLikeTraceConverter::StreamInfo::StreamInfo() : fin(false) {}

QuicIntervalSet<uint64_t> QuicTcpLikeTraceConverter::OnCryptoFrameSent(
    EncryptionLevel level,
    QuicStreamOffset offset,
    QuicByteCount data_length) {
  if (level >= NUM_ENCRYPTION_LEVELS) {
    QUIC_BUG(quic_bug_10907_1) << "Invalid encryption level";
    return {};
  }
  return OnFrameSent(offset, data_length, /*fin=*/false,
                     &crypto_frames_info_[level]);
}

QuicIntervalSet<uint64_t> QuicTcpLikeTraceConverter::OnStreamFrameSent(
    QuicStreamId stream_id,
    QuicStreamOffset offset,
    QuicByteCount data_length,
    bool fin) {
  return OnFrameSent(
      offset, data_length, fin,
      &streams_info_.emplace(stream_id, StreamInfo()).first->second);
}

QuicIntervalSet<uint64_t> QuicTcpLikeTraceConverter::OnFrameSent(
    QuicStreamOffset offset,
    QuicByteCount data_length,
    bool fin,
    StreamInfo* info) {
  QuicIntervalSet<uint64_t> connection_offsets;
  if (fin) {
    // Stream fin consumes a connection offset.
    ++data_length;
  }
  // Get connection offsets of retransmission data in this frame.
  for (const auto& segment : info->segments) {
    QuicInterval<QuicStreamOffset> retransmission(offset, offset + data_length);
    retransmission.IntersectWith(segment.stream_data);
    if (retransmission.Empty()) {
      continue;
    }
    const uint64_t connection_offset = segment.connection_offset +
                                       retransmission.min() -
                                       segment.stream_data.min();
    connection_offsets.Add(connection_offset,
                           connection_offset + retransmission.Length());
  }

  if (info->fin) {
    return connection_offsets;
  }

  // Get connection offsets of new data in this frame.
  QuicStreamOffset least_unsent_offset =
      info->segments.empty() ? 0 : info->segments.back().stream_data.max();
  if (least_unsent_offset >= offset + data_length) {
    return connection_offsets;
  }
  // Ignore out-of-order stream data so that as connection offset increases,
  // stream offset increases.
  QuicStreamOffset new_data_offset = std::max(least_unsent_offset, offset);
  QuicByteCount new_data_length = offset + data_length - new_data_offset;
  connection_offsets.Add(connection_offset_,
                         connection_offset_ + new_data_length);
  if (!info->segments.empty() && new_data_offset == least_unsent_offset &&
      connection_offset_ == info->segments.back().connection_offset +
                                info->segments.back().stream_data.Length()) {
    // Extend the last segment if both stream and connection offsets are
    // contiguous.
    info->segments.back().stream_data.SetMax(new_data_offset + new_data_length);
  } else {
    info->segments.emplace_back(new_data_offset, connection_offset_,
                                new_data_length);
  }
  info->fin = fin;
  connection_offset_ += new_data_length;

  return connection_offsets;
}

QuicInterval<uint64_t> QuicTcpLikeTraceConverter::OnControlFrameSent(
    QuicControlFrameId control_frame_id,
    QuicByteCount control_frame_length) {
  if (control_frame_id > largest_observed_control_frame_id_) {
    // New control frame.
    QuicInterval<uint64_t> connection_offset = QuicInterval<uint64_t>(
        connection_offset_, connection_offset_ + control_frame_length);
    connection_offset_ += control_frame_length;
    control_frames_info_[control_frame_id] = connection_offset;
    largest_observed_control_frame_id_ = control_frame_id;
    return connection_offset;
  }
  const auto iter = control_frames_info_.find(control_frame_id);
  if (iter == control_frames_info_.end()) {
    // Ignore out of order control frames.
    return {};
  }
  return iter->second;
}

}  // namespace quic
