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

package proto

import (
	
	
	
	
)

// ChannelData represents The ChannelData Message.
//
// See RFC 5766 Section 11.4.
type ChannelData struct {
	Data   []byte // Can be sub slice of Raw
	Length int    // Ignored while encoding, len(Data) is used
	Number ChannelNumber
	Raw    []byte
}

// Equal returns true if compareTo == c.
func ( *ChannelData) ( *ChannelData) bool {
	if  == nil &&  == nil {
		return true
	}
	if  == nil ||  == nil {
		return false
	}
	if .Number != .Number {
		return false
	}
	if len(.Data) != len(.Data) {
		return false
	}

	return bytes.Equal(.Data, .Data)
}

// Grow ensures that internal buffer will fit v more bytes and
// increases it capacity if necessary.
//
// Similar to stun.Message.grow method.
func ( *ChannelData) ( int) {
	 := len(.Raw) + 
	for cap(.Raw) <  {
		.Raw = append(.Raw, 0)
	}
	.Raw = .Raw[:]
}

// Reset resets Length, Data and Raw length.
func ( *ChannelData) () {
	.Raw = .Raw[:0]
	.Length = 0
	.Data = .Data[:0]
}

// Encode encodes ChannelData Message to Raw.
func ( *ChannelData) () {
	.Raw = .Raw[:0]
	.WriteHeader()
	.Raw = append(.Raw, .Data...)
	 := nearestPaddedValueLength(len(.Raw))
	if  :=  - len(.Raw);  > 0 {
		for  := 0;  < ; ++ {
			.Raw = append(.Raw, 0)
		}
	}
}

const padding = 4

func nearestPaddedValueLength( int) int {
	 := padding * ( / padding)
	if  <  {
		 += padding
	}

	return 
}

// WriteHeader writes channel number and length.
func ( *ChannelData) () {
	if len(.Raw) < channelDataHeaderSize {
		// Making WriteHeader call valid even when c.Raw
		// is nil or len(c.Raw) is less than needed for header.
		.grow(channelDataHeaderSize)
	}
	// Early bounds check to guarantee safety of writes below.
	_ = .Raw[:channelDataHeaderSize]
	binary.BigEndian.PutUint16(.Raw[:channelDataNumberSize], uint16(.Number))
	binary.BigEndian.PutUint16(.Raw[channelDataNumberSize:channelDataHeaderSize],
		uint16(len(.Data)), // nolint:gosec // G115
	)
}

// ErrBadChannelDataLength means that channel data length is not equal
// to actual data length.
var ErrBadChannelDataLength = errors.New("channelData length != len(Data)")

// Decode decodes The ChannelData Message from Raw.
func ( *ChannelData) () error {
	 := .Raw
	if len() < channelDataHeaderSize {
		return io.ErrUnexpectedEOF
	}
	 := binary.BigEndian.Uint16([:channelDataNumberSize])
	.Number = ChannelNumber()
	 := binary.BigEndian.Uint16([channelDataNumberSize:channelDataHeaderSize])
	.Data = [channelDataHeaderSize:]
	.Length = int()
	if !.Number.Valid() {
		return ErrInvalidChannelNumber
	}
	if int() < len(.Data) {
		.Data = .Data[:int()]
	}
	if int() > len([channelDataHeaderSize:]) {
		return ErrBadChannelDataLength
	}

	return nil
}

const (
	channelDataLengthSize = 2
	channelDataNumberSize = channelDataLengthSize
	channelDataHeaderSize = channelDataLengthSize + channelDataNumberSize
)

// IsChannelData returns true if buf looks like the ChannelData Message.
func ( []byte) bool {
	if len() < channelDataHeaderSize {
		return false
	}

	if int(binary.BigEndian.Uint16([channelDataNumberSize:channelDataHeaderSize])) > len([channelDataHeaderSize:]) {
		return false
	}

	// Quick check for channel number.
	 := binary.BigEndian.Uint16([0:channelNumberSize])

	return isChannelNumberValid()
}