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

package sctp

import (
	
	
	
)

/*
chunkHeader represents a SCTP Chunk header, defined in https://tools.ietf.org/html/rfc4960#section-3.2
The figure below illustrates the field format for the chunks to be
transmitted in the SCTP packet.  Each chunk is formatted with a Chunk
Type field, a chunk-specific Flag field, a Chunk Length field, and a
Value field.

	 0                   1                   2                   3
	 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
	|   Chunk Type  | Chunk  Flags  |        Chunk Length           |
	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
	|                                                               |
	|                          Chunk Value                          |
	|                                                               |
	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
type chunkHeader struct {
	typ   chunkType
	flags byte
	raw   []byte
}

const (
	chunkHeaderSize = 4
)

// SCTP chunk header errors.
var (
	ErrChunkHeaderTooSmall       = errors.New("raw is too small for a SCTP chunk")
	ErrChunkHeaderNotEnoughSpace = errors.New("not enough data left in SCTP packet to satisfy requested length")
	ErrChunkHeaderPaddingNonZero = errors.New("chunk padding is non-zero at offset")
)

func ( *chunkHeader) ( []byte) error {
	if len() < chunkHeaderSize {
		return fmt.Errorf(
			"%w: raw only %d bytes, %d is the minimum length",
			ErrChunkHeaderTooSmall, len(), chunkHeaderSize,
		)
	}

	.typ = chunkType([0])
	.flags = [1]
	 := binary.BigEndian.Uint16([2:])

	// Length includes Chunk header
	 := int( - chunkHeaderSize)
	 := len() - (chunkHeaderSize + )

	if  < 0 {
		return fmt.Errorf("%w: remain %d req %d ", ErrChunkHeaderNotEnoughSpace, , len()-chunkHeaderSize)
	} else if  < 4 {
		// https://tools.ietf.org/html/rfc4960#section-3.2
		// The Chunk Length field does not count any chunk padding.
		// Chunks (including Type, Length, and Value fields) are padded out
		// by the sender with all zero bytes to be a multiple of 4 bytes
		// long.  This padding MUST NOT be more than 3 bytes in total.  The
		// Chunk Length value does not include terminating padding of the
		// chunk.  However, it does include padding of any variable-length
		// parameter except the last parameter in the chunk.  The receiver
		// MUST ignore the padding.
		for  := ;  > 0; -- {
			 := chunkHeaderSize +  + ( - 1)
			if [] != 0 {
				return fmt.Errorf("%w: %d ", ErrChunkHeaderPaddingNonZero, )
			}
		}
	}

	.raw = [chunkHeaderSize : chunkHeaderSize+]

	return nil
}

func ( *chunkHeader) () ([]byte, error) {
	 := make([]byte, 4+len(.raw))

	[0] = uint8(.typ)
	[1] = .flags
	binary.BigEndian.PutUint16([2:], uint16(len(.raw)+chunkHeaderSize)) //nolint:gosec // G115
	copy([4:], .raw)

	return , nil
}

func ( *chunkHeader) () int {
	return len(.raw)
}

// String makes chunkHeader printable.
func ( chunkHeader) () string {
	return .typ.String()
}