package ackhandler

import (
	
	

	
)

// interval is an interval from one PacketNumber to the other
type interval struct {
	Start protocol.PacketNumber
	End   protocol.PacketNumber
}

// The receivedPacketHistory stores if a packet number has already been received.
// It generates ACK ranges which can be used to assemble an ACK frame.
// It does not store packet contents.
type receivedPacketHistory struct {
	ranges []interval // maximum length: protocol.MaxNumAckRanges

	deletedBelow protocol.PacketNumber
}

func newReceivedPacketHistory() *receivedPacketHistory {
	return &receivedPacketHistory{
		deletedBelow: protocol.InvalidPacketNumber,
	}
}

// ReceivedPacket registers a packet with PacketNumber p and updates the ranges
func ( *receivedPacketHistory) ( protocol.PacketNumber) bool /* is a new packet (and not a duplicate / delayed packet) */ {
	// ignore delayed packets, if we already deleted the range
	if  < .deletedBelow {
		return false
	}

	 := .addToRanges()
	// Delete old ranges, if we're tracking too many of them.
	// This is a DoS defense against a peer that sends us too many gaps.
	if len(.ranges) > protocol.MaxNumAckRanges {
		.ranges = slices.Delete(.ranges, 0, len(.ranges)-protocol.MaxNumAckRanges)
	}
	return 
}

func ( *receivedPacketHistory) ( protocol.PacketNumber) bool /* is a new packet (and not a duplicate / delayed packet) */ {
	if len(.ranges) == 0 {
		.ranges = append(.ranges, interval{Start: , End: })
		return true
	}

	for  := len(.ranges) - 1;  >= 0; -- {
		// p already included in an existing range. Nothing to do here
		if  >= .ranges[].Start &&  <= .ranges[].End {
			return false
		}

		if .ranges[].End == -1 { // extend a range at the end
			.ranges[].End = 
			return true
		}
		if .ranges[].Start == +1 { // extend a range at the beginning
			.ranges[].Start = 

			if  > 0 && .ranges[-1].End+1 == .ranges[].Start { // merge two ranges
				.ranges[-1].End = .ranges[].End
				.ranges = slices.Delete(.ranges, , +1)
			}
			return true
		}

		// create a new range after the current one
		if  > .ranges[].End {
			.ranges = slices.Insert(.ranges, +1, interval{Start: , End: })
			return true
		}
	}

	// create a new range at the beginning
	.ranges = slices.Insert(.ranges, 0, interval{Start: , End: })
	return true
}

// DeleteBelow deletes all entries below (but not including) p
func ( *receivedPacketHistory) ( protocol.PacketNumber) {
	if  < .deletedBelow {
		return
	}
	.deletedBelow = 

	if len(.ranges) == 0 {
		return
	}

	 := -1
	for  := 0;  < len(.ranges); ++ {
		if .ranges[].End <  { // delete a whole range
			 = 
		} else if  > .ranges[].Start &&  <= .ranges[].End {
			.ranges[].Start = 
			break
		} else { // no ranges affected. Nothing to do
			break
		}
	}
	if  >= 0 {
		.ranges = slices.Delete(.ranges, 0, +1)
	}
}

// Backward returns an iterator over the ranges in reverse order
func ( *receivedPacketHistory) () iter.Seq[interval] {
	return func( func(interval) bool) {
		for  := len(.ranges) - 1;  >= 0; -- {
			if !(.ranges[]) {
				return
			}
		}
	}
}

func ( *receivedPacketHistory) ( protocol.PacketNumber) protocol.PacketNumber {
	if len(.ranges) == 0 || (.deletedBelow != protocol.InvalidPacketNumber &&  < .deletedBelow) {
		return protocol.InvalidPacketNumber
	}
	 = min(.ranges[len(.ranges)-1].End, )
	for  := len(.ranges) - 1;  >= 0; -- {
		 := .ranges[]
		if  >= .Start &&  <= .End { // p is contained in this range
			 := .Start - 1 // highest packet in the gap before this range
			if .deletedBelow != protocol.InvalidPacketNumber &&  < .deletedBelow {
				return protocol.InvalidPacketNumber
			}
			return 
		}
		if  >= 1 &&  > .ranges[-1].End &&  <= .Start {
			// p is in the gap between the previous range and this range
			return 
		}
	}
	return 
}

func ( *receivedPacketHistory) ( protocol.PacketNumber) bool {
	if  < .deletedBelow {
		return true
	}
	// Iterating over the slices is faster than using a binary search (using slices.BinarySearchFunc).
	for  := len(.ranges) - 1;  >= 0; -- {
		if  > .ranges[].End {
			return false
		}
		if  <= .ranges[].End &&  >= .ranges[].Start {
			return true
		}
	}
	return false
}