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

package http2

import (
	
	
)

type roundRobinWriteScheduler struct {
	// control contains control frames (SETTINGS, PING, etc.).
	control writeQueue

	// streams maps stream ID to a queue.
	streams map[uint32]*writeQueue

	// stream queues are stored in a circular linked list.
	// head is the next stream to write, or nil if there are no streams open.
	head *writeQueue

	// pool of empty queues for reuse.
	queuePool writeQueuePool
}

// newRoundRobinWriteScheduler constructs a new write scheduler.
// The round robin scheduler priorizes control frames
// like SETTINGS and PING over DATA frames.
// When there are no control frames to send, it performs a round-robin
// selection from the ready streams.
func () WriteScheduler {
	 := &roundRobinWriteScheduler{
		streams: make(map[uint32]*writeQueue),
	}
	return 
}

func ( *roundRobinWriteScheduler) ( uint32,  OpenStreamOptions) {
	if .streams[] != nil {
		panic(fmt.Errorf("stream %d already opened", ))
	}
	 := .queuePool.get()
	.streams[] = 
	if .head == nil {
		.head = 
		.next = 
		.prev = 
	} else {
		// Queues are stored in a ring.
		// Insert the new stream before ws.head, putting it at the end of the list.
		.prev = .head.prev
		.next = .head
		.prev.next = 
		.next.prev = 
	}
}

func ( *roundRobinWriteScheduler) ( uint32) {
	 := .streams[]
	if  == nil {
		return
	}
	if .next ==  {
		// This was the only open stream.
		.head = nil
	} else {
		.prev.next = .next
		.next.prev = .prev
		if .head ==  {
			.head = .next
		}
	}
	delete(.streams, )
	.queuePool.put()
}

func ( *roundRobinWriteScheduler) ( uint32,  PriorityParam) {}

func ( *roundRobinWriteScheduler) ( FrameWriteRequest) {
	if .isControl() {
		.control.push()
		return
	}
	 := .streams[.StreamID()]
	if  == nil {
		// This is a closed stream.
		// wr should not be a HEADERS or DATA frame.
		// We push the request onto the control queue.
		if .DataSize() > 0 {
			panic("add DATA on non-open stream")
		}
		.control.push()
		return
	}
	.push()
}

func ( *roundRobinWriteScheduler) () (FrameWriteRequest, bool) {
	// Control and RST_STREAM frames first.
	if !.control.empty() {
		return .control.shift(), true
	}
	if .head == nil {
		return FrameWriteRequest{}, false
	}
	 := .head
	for {
		if ,  := .consume(math.MaxInt32);  {
			.head = .next
			return , true
		}
		 = .next
		if  == .head {
			break
		}
	}
	return FrameWriteRequest{}, false
}