// Copyright 2014 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.

// Flow control

package http2

// inflowMinRefresh is the minimum number of bytes we'll send for a
// flow control window update.
const inflowMinRefresh = 4 << 10

// inflow accounts for an inbound flow control window.
// It tracks both the latest window sent to the peer (used for enforcement)
// and the accumulated unsent window.
type inflow struct {
	avail  int32
	unsent int32
}

// init sets the initial window.
func ( *inflow) ( int32) {
	.avail = 
}

// add adds n bytes to the window, with a maximum window size of max,
// indicating that the peer can now send us more data.
// For example, the user read from a {Request,Response} body and consumed
// some of the buffered data, so the peer can now send more.
// It returns the number of bytes to send in a WINDOW_UPDATE frame to the peer.
// Window updates are accumulated and sent when the unsent capacity
// is at least inflowMinRefresh or will at least double the peer's available window.
func ( *inflow) ( int) ( int32) {
	if  < 0 {
		panic("negative update")
	}
	 := int64(.unsent) + int64()
	// "A sender MUST NOT allow a flow-control window to exceed 2^31-1 octets."
	// RFC 7540 Section 6.9.1.
	const  = 1<<31 - 1
	if +int64(.avail) >  {
		panic("flow control update exceeds maximum window size")
	}
	.unsent = int32()
	if .unsent < inflowMinRefresh && .unsent < .avail {
		// If there aren't at least inflowMinRefresh bytes of window to send,
		// and this update won't at least double the window, buffer the update for later.
		return 0
	}
	.avail += .unsent
	.unsent = 0
	return int32()
}

// take attempts to take n bytes from the peer's flow control window.
// It reports whether the window has available capacity.
func ( *inflow) ( uint32) bool {
	if  > uint32(.avail) {
		return false
	}
	.avail -= int32()
	return true
}

// takeInflows attempts to take n bytes from two inflows,
// typically connection-level and stream-level flows.
// It reports whether both windows have available capacity.
func (,  *inflow,  uint32) bool {
	if  > uint32(.avail) ||  > uint32(.avail) {
		return false
	}
	.avail -= int32()
	.avail -= int32()
	return true
}

// outflow is the outbound flow control window's size.
type outflow struct {
	_ incomparable

	// n is the number of DATA bytes we're allowed to send.
	// An outflow is kept both on a conn and a per-stream.
	n int32

	// conn points to the shared connection-level outflow that is
	// shared by all streams on that conn. It is nil for the outflow
	// that's on the conn directly.
	conn *outflow
}

func ( *outflow) ( *outflow) { .conn =  }

func ( *outflow) () int32 {
	 := .n
	if .conn != nil && .conn.n <  {
		 = .conn.n
	}
	return 
}

func ( *outflow) ( int32) {
	if  > .available() {
		panic("internal error: took too much")
	}
	.n -= 
	if .conn != nil {
		.conn.n -= 
	}
}

// add adds n bytes (positive or negative) to the flow control window.
// It returns false if the sum would exceed 2^31-1.
func ( *outflow) ( int32) bool {
	 := .n + 
	if ( > ) == (.n > 0) {
		.n = 
		return true
	}
	return false
}