package quic

import (
	
	
	

	
	
	
	
)

type streamError struct {
	message string
	nums    []protocol.StreamNum
}

func ( streamError) () string {
	return .message
}

func convertStreamError( error,  protocol.StreamType,  protocol.Perspective) error {
	,  := .(streamError)
	if ! {
		return 
	}
	 := make([]interface{}, len(.nums))
	for ,  := range .nums {
		[] = .StreamID(, )
	}
	return fmt.Errorf(.Error(), ...)
}

// StreamLimitReachedError is returned from Connection.OpenStream and Connection.OpenUniStream
// when it is not possible to open a new stream because the number of opens streams reached
// the peer's stream limit.
type StreamLimitReachedError struct{}

func ( StreamLimitReachedError) () string { return "too many open streams" }

type streamsMap struct {
	ctx         context.Context // not used for cancellations, but carries the values associated with the connection
	perspective protocol.Perspective

	maxIncomingBidiStreams uint64
	maxIncomingUniStreams  uint64

	sender            streamSender
	queueControlFrame func(wire.Frame)
	newFlowController func(protocol.StreamID) flowcontrol.StreamFlowController

	mutex               sync.Mutex
	outgoingBidiStreams *outgoingStreamsMap[streamI]
	outgoingUniStreams  *outgoingStreamsMap[sendStreamI]
	incomingBidiStreams *incomingStreamsMap[streamI]
	incomingUniStreams  *incomingStreamsMap[receiveStreamI]
	reset               bool
}

var _ streamManager = &streamsMap{}

func newStreamsMap(
	 context.Context,
	 streamSender,
	 func(wire.Frame),
	 func(protocol.StreamID) flowcontrol.StreamFlowController,
	 uint64,
	 uint64,
	 protocol.Perspective,
) *streamsMap {
	 := &streamsMap{
		ctx:                    ,
		perspective:            ,
		queueControlFrame:      ,
		newFlowController:      ,
		maxIncomingBidiStreams: ,
		maxIncomingUniStreams:  ,
		sender:                 ,
	}
	.initMaps()
	return 
}

func ( *streamsMap) () {
	.outgoingBidiStreams = newOutgoingStreamsMap(
		protocol.StreamTypeBidi,
		func( protocol.StreamNum) streamI {
			 := .StreamID(protocol.StreamTypeBidi, .perspective)
			return newStream(.ctx, , .sender, .newFlowController())
		},
		.queueControlFrame,
	)
	.incomingBidiStreams = newIncomingStreamsMap(
		protocol.StreamTypeBidi,
		func( protocol.StreamNum) streamI {
			 := .StreamID(protocol.StreamTypeBidi, .perspective.Opposite())
			return newStream(.ctx, , .sender, .newFlowController())
		},
		.maxIncomingBidiStreams,
		.queueControlFrame,
	)
	.outgoingUniStreams = newOutgoingStreamsMap(
		protocol.StreamTypeUni,
		func( protocol.StreamNum) sendStreamI {
			 := .StreamID(protocol.StreamTypeUni, .perspective)
			return newSendStream(.ctx, , .sender, .newFlowController())
		},
		.queueControlFrame,
	)
	.incomingUniStreams = newIncomingStreamsMap(
		protocol.StreamTypeUni,
		func( protocol.StreamNum) receiveStreamI {
			 := .StreamID(protocol.StreamTypeUni, .perspective.Opposite())
			return newReceiveStream(, .sender, .newFlowController())
		},
		.maxIncomingUniStreams,
		.queueControlFrame,
	)
}

func ( *streamsMap) () (Stream, error) {
	.mutex.Lock()
	 := .reset
	 := .outgoingBidiStreams
	.mutex.Unlock()
	if  {
		return nil, Err0RTTRejected
	}
	,  := .OpenStream()
	return , convertStreamError(, protocol.StreamTypeBidi, .perspective)
}

func ( *streamsMap) ( context.Context) (Stream, error) {
	.mutex.Lock()
	 := .reset
	 := .outgoingBidiStreams
	.mutex.Unlock()
	if  {
		return nil, Err0RTTRejected
	}
	,  := .OpenStreamSync()
	return , convertStreamError(, protocol.StreamTypeBidi, .perspective)
}

func ( *streamsMap) () (SendStream, error) {
	.mutex.Lock()
	 := .reset
	 := .outgoingUniStreams
	.mutex.Unlock()
	if  {
		return nil, Err0RTTRejected
	}
	,  := .OpenStream()
	return , convertStreamError(, protocol.StreamTypeBidi, .perspective)
}

func ( *streamsMap) ( context.Context) (SendStream, error) {
	.mutex.Lock()
	 := .reset
	 := .outgoingUniStreams
	.mutex.Unlock()
	if  {
		return nil, Err0RTTRejected
	}
	,  := .OpenStreamSync()
	return , convertStreamError(, protocol.StreamTypeUni, .perspective)
}

func ( *streamsMap) ( context.Context) (Stream, error) {
	.mutex.Lock()
	 := .reset
	 := .incomingBidiStreams
	.mutex.Unlock()
	if  {
		return nil, Err0RTTRejected
	}
	,  := .AcceptStream()
	return , convertStreamError(, protocol.StreamTypeBidi, .perspective.Opposite())
}

func ( *streamsMap) ( context.Context) (ReceiveStream, error) {
	.mutex.Lock()
	 := .reset
	 := .incomingUniStreams
	.mutex.Unlock()
	if  {
		return nil, Err0RTTRejected
	}
	,  := .AcceptStream()
	return , convertStreamError(, protocol.StreamTypeUni, .perspective.Opposite())
}

func ( *streamsMap) ( protocol.StreamID) error {
	 := .StreamNum()
	switch .Type() {
	case protocol.StreamTypeUni:
		if .InitiatedBy() == .perspective {
			return convertStreamError(.outgoingUniStreams.DeleteStream(), protocol.StreamTypeUni, .perspective)
		}
		return convertStreamError(.incomingUniStreams.DeleteStream(), protocol.StreamTypeUni, .perspective.Opposite())
	case protocol.StreamTypeBidi:
		if .InitiatedBy() == .perspective {
			return convertStreamError(.outgoingBidiStreams.DeleteStream(), protocol.StreamTypeBidi, .perspective)
		}
		return convertStreamError(.incomingBidiStreams.DeleteStream(), protocol.StreamTypeBidi, .perspective.Opposite())
	}
	panic("")
}

func ( *streamsMap) ( protocol.StreamID) (receiveStreamI, error) {
	,  := .getOrOpenReceiveStream()
	if  != nil {
		return nil, &qerr.TransportError{
			ErrorCode:    qerr.StreamStateError,
			ErrorMessage: .Error(),
		}
	}
	return , nil
}

func ( *streamsMap) ( protocol.StreamID) (receiveStreamI, error) {
	 := .StreamNum()
	switch .Type() {
	case protocol.StreamTypeUni:
		if .InitiatedBy() == .perspective {
			// an outgoing unidirectional stream is a send stream, not a receive stream
			return nil, fmt.Errorf("peer attempted to open receive stream %d", )
		}
		,  := .incomingUniStreams.GetOrOpenStream()
		return , convertStreamError(, protocol.StreamTypeUni, .perspective)
	case protocol.StreamTypeBidi:
		var  receiveStreamI
		var  error
		if .InitiatedBy() == .perspective {
			,  = .outgoingBidiStreams.GetStream()
		} else {
			,  = .incomingBidiStreams.GetOrOpenStream()
		}
		return , convertStreamError(, protocol.StreamTypeBidi, .InitiatedBy())
	}
	panic("")
}

func ( *streamsMap) ( protocol.StreamID) (sendStreamI, error) {
	,  := .getOrOpenSendStream()
	if  != nil {
		return nil, &qerr.TransportError{
			ErrorCode:    qerr.StreamStateError,
			ErrorMessage: .Error(),
		}
	}
	return , nil
}

func ( *streamsMap) ( protocol.StreamID) (sendStreamI, error) {
	 := .StreamNum()
	switch .Type() {
	case protocol.StreamTypeUni:
		if .InitiatedBy() == .perspective {
			,  := .outgoingUniStreams.GetStream()
			return , convertStreamError(, protocol.StreamTypeUni, .perspective)
		}
		// an incoming unidirectional stream is a receive stream, not a send stream
		return nil, fmt.Errorf("peer attempted to open send stream %d", )
	case protocol.StreamTypeBidi:
		var  sendStreamI
		var  error
		if .InitiatedBy() == .perspective {
			,  = .outgoingBidiStreams.GetStream()
		} else {
			,  = .incomingBidiStreams.GetOrOpenStream()
		}
		return , convertStreamError(, protocol.StreamTypeBidi, .InitiatedBy())
	}
	panic("")
}

func ( *streamsMap) ( *wire.MaxStreamsFrame) {
	switch .Type {
	case protocol.StreamTypeUni:
		.outgoingUniStreams.SetMaxStream(.MaxStreamNum)
	case protocol.StreamTypeBidi:
		.outgoingBidiStreams.SetMaxStream(.MaxStreamNum)
	}
}

func ( *streamsMap) ( *wire.TransportParameters) {
	.outgoingBidiStreams.UpdateSendWindow(.InitialMaxStreamDataBidiRemote)
	.outgoingBidiStreams.SetMaxStream(.MaxBidiStreamNum)
	.outgoingUniStreams.UpdateSendWindow(.InitialMaxStreamDataUni)
	.outgoingUniStreams.SetMaxStream(.MaxUniStreamNum)
}

func ( *streamsMap) ( error) {
	.outgoingBidiStreams.CloseWithError()
	.outgoingUniStreams.CloseWithError()
	.incomingBidiStreams.CloseWithError()
	.incomingUniStreams.CloseWithError()
}

// ResetFor0RTT resets is used when 0-RTT is rejected. In that case, the streams maps are
// 1. closed with an Err0RTTRejected, making calls to Open{Uni}Stream{Sync} / Accept{Uni}Stream return that error.
// 2. reset to their initial state, such that we can immediately process new incoming stream data.
// Afterwards, calls to Open{Uni}Stream{Sync} / Accept{Uni}Stream will continue to return the error,
// until UseResetMaps() has been called.
func ( *streamsMap) () {
	.mutex.Lock()
	defer .mutex.Unlock()
	.reset = true
	.CloseWithError(Err0RTTRejected)
	.initMaps()
}

func ( *streamsMap) () {
	.mutex.Lock()
	.reset = false
	.mutex.Unlock()
}