// SPDX-FileCopyrightText: 2023 The Pion community <https://pion.ly>
// SPDX-License-Identifier: MIT

package rtcp

import (
	
	
)

// A CompoundPacket is a collection of RTCP packets transmitted as a single packet with
// the underlying protocol (for example UDP).
//
// To maximize the resolution of receiption statistics, the first Packet in a CompoundPacket
// must always be either a SenderReport or a ReceiverReport.  This is true even if no data
// has been sent or received, in which case an empty ReceiverReport must be sent, and even
// if the only other RTCP packet in the compound packet is a Goodbye.
//
// Next, a SourceDescription containing a CNAME item must be included in each CompoundPacket
// to identify the source and to begin associating media for purposes such as lip-sync.
//
// Other RTCP packet types may follow in any order. Packet types may appear more than once.
type CompoundPacket []Packet

// Validate returns an error if this is not an RFC-compliant CompoundPacket.
func ( CompoundPacket) () error {
	if len() == 0 {
		return errEmptyCompound
	}

	// SenderReport and ReceiverReport are the only types that
	// are allowed to be the first packet in a compound datagram
	switch [0].(type) {
	case *SenderReport, *ReceiverReport:
		// ok
	default:
		return errBadFirstPacket
	}

	for ,  := range [1:] {
		switch p := .(type) {
		// If the number of RecetpionReports exceeds 31 additional ReceiverReports
		// can be included here.
		case *ReceiverReport:
			continue

		// A SourceDescription containing a CNAME must be included in every
		// CompoundPacket.
		case *SourceDescription:
			var  bool
			for ,  := range .Chunks {
				for ,  := range .Items {
					if .Type == SDESCNAME {
						 = true
					}
				}
			}

			if ! {
				return errMissingCNAME
			}

			return nil

		// Other packets are not permitted before the CNAME
		default:
			return errPacketBeforeCNAME
		}
	}

	// CNAME never reached
	return errMissingCNAME
}

// CNAME returns the CNAME that *must* be present in every CompoundPacket
func ( CompoundPacket) () (string, error) {
	var  error

	if len() < 1 {
		return "", errEmptyCompound
	}

	for ,  := range [1:] {
		,  := .(*SourceDescription)
		if  {
			for ,  := range .Chunks {
				for ,  := range .Items {
					if .Type == SDESCNAME {
						return .Text, 
					}
				}
			}
		} else {
			,  := .(*ReceiverReport)
			if ! {
				 = errPacketBeforeCNAME
			}
		}
	}
	return "", errMissingCNAME
}

// Marshal encodes the CompoundPacket as binary.
func ( CompoundPacket) () ([]byte, error) {
	if  := .Validate();  != nil {
		return nil, 
	}

	 := []Packet()
	return Marshal()
}

// MarshalSize returns the size of the packet once marshaled
func ( CompoundPacket) () int {
	 := 0
	for ,  := range  {
		 += .MarshalSize()
	}
	return 
}

// Unmarshal decodes a CompoundPacket from binary.
func ( *CompoundPacket) ( []byte) error {
	 := make(CompoundPacket, 0)
	for len() != 0 {
		, ,  := unmarshal()
		if  != nil {
			return 
		}

		 = append(, )
		 = [:]
	}
	* = 

	return .Validate()
}

// DestinationSSRC returns the synchronization sources associated with this
// CompoundPacket's reception report.
func ( CompoundPacket) () []uint32 {
	if len() == 0 {
		return nil
	}

	return [0].DestinationSSRC()
}

func ( CompoundPacket) () string {
	 := "CompoundPacket\n"
	for ,  := range  {
		,  := .(fmt.Stringer)
		if  {
			 += .String()
		} else {
			 += stringify()
		}
	}
	 = strings.TrimSuffix(strings.ReplaceAll(, "\n", "\n\t"), "\t")
	return 
}