package wire

import (
	
	

	
	
)

// A StreamFrame of QUIC
type StreamFrame struct {
	StreamID       protocol.StreamID
	Offset         protocol.ByteCount
	Data           []byte
	Fin            bool
	DataLenPresent bool

	fromPool bool
}

func parseStreamFrame( []byte,  uint64,  protocol.Version) (*StreamFrame, int, error) {
	 := len()
	 := &0b100 > 0
	 := &0b1 > 0
	 := &0b10 > 0

	, ,  := quicvarint.Parse()
	if  != nil {
		return nil, 0, replaceUnexpectedEOF()
	}
	 = [:]
	var  uint64
	if  {
		, ,  = quicvarint.Parse()
		if  != nil {
			return nil, 0, replaceUnexpectedEOF()
		}
		 = [:]
	}

	var  uint64
	if  {
		var  error
		var  int
		, ,  = quicvarint.Parse()
		if  != nil {
			return nil, 0, replaceUnexpectedEOF()
		}
		 = [:]
		if  > uint64(len()) {
			return nil, 0, io.EOF
		}
	} else {
		// The rest of the packet is data
		 = uint64(len())
	}

	var  *StreamFrame
	if  < protocol.MinStreamFrameBufferSize {
		 = &StreamFrame{}
		if  > 0 {
			.Data = make([]byte, )
		}
	} else {
		 = GetStreamFrame()
		// The STREAM frame can't be larger than the StreamFrame we obtained from the buffer,
		// since those StreamFrames have a buffer length of the maximum packet size.
		if  > uint64(cap(.Data)) {
			return nil, 0, io.EOF
		}
		.Data = .Data[:]
	}

	.StreamID = protocol.StreamID()
	.Offset = protocol.ByteCount()
	.Fin = 
	.DataLenPresent = 

	if  > 0 {
		copy(.Data, )
	}
	if .Offset+.DataLen() > protocol.MaxByteCount {
		return nil, 0, errors.New("stream data overflows maximum offset")
	}
	return ,  - len() + int(), nil
}

func ( *StreamFrame) ( []byte,  protocol.Version) ([]byte, error) {
	if len(.Data) == 0 && !.Fin {
		return nil, errors.New("StreamFrame: attempting to write empty frame without FIN")
	}

	 := byte(0x8)
	if .Fin {
		 ^= 0b1
	}
	 := .Offset != 0
	if .DataLenPresent {
		 ^= 0b10
	}
	if  {
		 ^= 0b100
	}
	 = append(, )
	 = quicvarint.Append(, uint64(.StreamID))
	if  {
		 = quicvarint.Append(, uint64(.Offset))
	}
	if .DataLenPresent {
		 = quicvarint.Append(, uint64(.DataLen()))
	}
	 = append(, .Data...)
	return , nil
}

// Length returns the total length of the STREAM frame
func ( *StreamFrame) (protocol.Version) protocol.ByteCount {
	 := 1 + quicvarint.Len(uint64(.StreamID))
	if .Offset != 0 {
		 += quicvarint.Len(uint64(.Offset))
	}
	if .DataLenPresent {
		 += quicvarint.Len(uint64(.DataLen()))
	}
	return protocol.ByteCount() + .DataLen()
}

// DataLen gives the length of data in bytes
func ( *StreamFrame) () protocol.ByteCount {
	return protocol.ByteCount(len(.Data))
}

// MaxDataLen returns the maximum data length
// If 0 is returned, writing will fail (a STREAM frame must contain at least 1 byte of data).
func ( *StreamFrame) ( protocol.ByteCount,  protocol.Version) protocol.ByteCount {
	 := 1 + protocol.ByteCount(quicvarint.Len(uint64(.StreamID)))
	if .Offset != 0 {
		 += protocol.ByteCount(quicvarint.Len(uint64(.Offset)))
	}
	if .DataLenPresent {
		// Pretend that the data size will be 1 byte.
		// If it turns out that varint encoding the length will consume 2 bytes, we need to adjust the data length afterward
		++
	}
	if  >  {
		return 0
	}
	 :=  - 
	if .DataLenPresent && quicvarint.Len(uint64()) != 1 {
		--
	}
	return 
}

// MaybeSplitOffFrame splits a frame such that it is not bigger than n bytes.
// It returns if the frame was actually split.
// The frame might not be split if:
// * the size is large enough to fit the whole frame
// * the size is too small to fit even a 1-byte frame. In that case, the frame returned is nil.
func ( *StreamFrame) ( protocol.ByteCount,  protocol.Version) (*StreamFrame, bool /* was splitting required */) {
	if  >= .Length() {
		return nil, false
	}

	 := .MaxDataLen(, )
	if  == 0 {
		return nil, true
	}

	 := GetStreamFrame()
	.StreamID = .StreamID
	.Offset = .Offset
	.Fin = false
	.DataLenPresent = .DataLenPresent

	// swap the data slices
	.Data, .Data = .Data, .Data
	.fromPool, .fromPool = .fromPool, .fromPool

	.Data = .Data[:protocol.ByteCount(len(.Data))-]
	copy(.Data, .Data[:])
	.Data = .Data[:]
	.Offset += 

	return , true
}

func ( *StreamFrame) () {
	putStreamFrame()
}