package ackhandler

import (
	
	

	
	
	
	
)

const reorderingThreshold = 1

// The receivedPacketTracker tracks packets for the Initial and Handshake packet number space.
// Every received packet is acknowledged immediately.
type receivedPacketTracker struct {
	ect0, ect1, ecnce uint64

	packetHistory receivedPacketHistory

	lastAck   *wire.AckFrame
	hasNewAck bool // true as soon as we received an ack-eliciting new packet
}

func newReceivedPacketTracker() *receivedPacketTracker {
	return &receivedPacketTracker{packetHistory: *newReceivedPacketHistory()}
}

func ( *receivedPacketTracker) ( protocol.PacketNumber,  protocol.ECN,  bool) error {
	if  := .packetHistory.ReceivedPacket(); ! {
		return fmt.Errorf("receivedPacketTracker BUG: ReceivedPacket called for old / duplicate packet %d", )
	}

	//nolint:exhaustive // Only need to count ECT(0), ECT(1) and ECN-CE.
	switch  {
	case protocol.ECT0:
		.ect0++
	case protocol.ECT1:
		.ect1++
	case protocol.ECNCE:
		.ecnce++
	}
	if ! {
		return nil
	}
	.hasNewAck = true
	return nil
}

func ( *receivedPacketTracker) () *wire.AckFrame {
	if !.hasNewAck {
		return nil
	}

	// This function always returns the same ACK frame struct, filled with the most recent values.
	 := .lastAck
	if  == nil {
		 = &wire.AckFrame{}
	}
	.Reset()
	.ECT0 = .ect0
	.ECT1 = .ect1
	.ECNCE = .ecnce
	for  := range .packetHistory.Backward() {
		.AckRanges = append(.AckRanges, wire.AckRange{Smallest: .Start, Largest: .End})
	}

	.lastAck = 
	.hasNewAck = false
	return 
}

func ( *receivedPacketTracker) ( protocol.PacketNumber) bool {
	return .packetHistory.IsPotentiallyDuplicate()
}

// number of ack-eliciting app-data packets received before sending an ACK
const packetsBeforeAck = 10

// The appDataReceivedPacketTracker tracks packets received in the Application Data packet number space.
// It waits until enough packets were received before queueing an ACK, or until the max_ack_delay was reached.
type appDataReceivedPacketTracker struct {
	receivedPacketTracker

	largestObservedRcvdTime monotime.Time

	largestObserved protocol.PacketNumber
	ignoreBelow     protocol.PacketNumber

	maxAckDelay time.Duration
	ackQueued   bool // true if we need send a new ACK

	ackElicitingPacketsReceivedSinceLastAck int
	ackAlarm                                monotime.Time

	logger utils.Logger
}

func newAppDataReceivedPacketTracker( utils.Logger) *appDataReceivedPacketTracker {
	 := &appDataReceivedPacketTracker{
		receivedPacketTracker: *newReceivedPacketTracker(),
		maxAckDelay:           protocol.MaxAckDelay,
		logger:                ,
	}
	return 
}

func ( *appDataReceivedPacketTracker) ( protocol.PacketNumber,  protocol.ECN,  monotime.Time,  bool) error {
	if  := .receivedPacketTracker.ReceivedPacket(, , );  != nil {
		return 
	}
	if  >= .largestObserved {
		.largestObserved = 
		.largestObservedRcvdTime = 
	}
	if ! {
		return nil
	}
	.ackElicitingPacketsReceivedSinceLastAck++
	 := .isMissing()
	if !.ackQueued && .shouldQueueACK(, , ) {
		.ackQueued = true
		.ackAlarm = 0 // cancel the ack alarm
	}
	if !.ackQueued {
		// No ACK queued, but we'll need to acknowledge the packet after max_ack_delay.
		.ackAlarm = .Add(.maxAckDelay)
		if .logger.Debug() {
			.logger.Debugf("\tSetting ACK timer to max ack delay: %s", .maxAckDelay)
		}
	}
	return nil
}

// IgnoreBelow sets a lower limit for acknowledging packets.
// Packets with packet numbers smaller than p will not be acked.
func ( *appDataReceivedPacketTracker) ( protocol.PacketNumber) {
	if  <= .ignoreBelow {
		return
	}
	.ignoreBelow = 
	.packetHistory.DeleteBelow()
	if .logger.Debug() {
		.logger.Debugf("\tIgnoring all packets below %d.", )
	}
}

// isMissing says if a packet was reported missing in the last ACK.
func ( *appDataReceivedPacketTracker) ( protocol.PacketNumber) bool {
	if .lastAck == nil ||  < .ignoreBelow {
		return false
	}
	return  < .lastAck.LargestAcked() && !.lastAck.AcksPacket()
}

func ( *appDataReceivedPacketTracker) () bool {
	if .lastAck == nil {
		return false
	}
	if .largestObserved < reorderingThreshold {
		return false
	}
	 := .packetHistory.HighestMissingUpTo(.largestObserved - reorderingThreshold)
	if  == protocol.InvalidPacketNumber {
		return false
	}
	if  < .lastAck.LargestAcked() {
		// the packet was already reported missing in the last ACK
		return false
	}
	return  > .lastAck.LargestAcked()-reorderingThreshold
}

func ( *appDataReceivedPacketTracker) ( protocol.PacketNumber,  protocol.ECN,  bool) bool {
	// Send an ACK if this packet was reported missing in an ACK sent before.
	// Ack decimation with reordering relies on the timer to send an ACK, but if
	// missing packets we reported in the previous ACK, send an ACK immediately.
	if  {
		if .logger.Debug() {
			.logger.Debugf("\tQueueing ACK because packet %d was missing before.", )
		}
		return true
	}

	// send an ACK after enough ack-eliciting packets
	if .ackElicitingPacketsReceivedSinceLastAck >= packetsBeforeAck {
		if .logger.Debug() {
			.logger.Debugf("\tQueueing ACK because packet %d packets were received after the last ACK (using initial threshold: %d).", .ackElicitingPacketsReceivedSinceLastAck, packetsBeforeAck)
		}
		return true
	}

	// queue an ACK if there are new missing packets to report
	if .hasNewMissingPackets() {
		.logger.Debugf("\tQueuing ACK because there's a new missing packet to report.")
		return true
	}

	// queue an ACK if the packet was ECN-CE marked
	if  == protocol.ECNCE {
		.logger.Debugf("\tQueuing ACK because the packet was ECN-CE marked.")
		return true
	}
	return false
}

func ( *appDataReceivedPacketTracker) ( monotime.Time,  bool) *wire.AckFrame {
	if  && !.ackQueued {
		if .ackAlarm.IsZero() || .ackAlarm.After() {
			return nil
		}
		if .logger.Debug() && !.ackAlarm.IsZero() {
			.logger.Debugf("Sending ACK because the ACK timer expired.")
		}
	}
	 := .receivedPacketTracker.GetAckFrame()
	if  == nil {
		return nil
	}
	.DelayTime = max(0, .Sub(.largestObservedRcvdTime))
	.ackQueued = false
	.ackAlarm = 0
	.ackElicitingPacketsReceivedSinceLastAck = 0
	return 
}

func ( *appDataReceivedPacketTracker) () monotime.Time { return .ackAlarm }