package wire

import (
	
	
	
	

	
	
	
)

// ErrInvalidReservedBits is returned when the reserved bits are incorrect.
// When this error is returned, parsing continues, and an ExtendedHeader is returned.
// This is necessary because we need to decrypt the packet in that case,
// in order to avoid a timing side-channel.
var ErrInvalidReservedBits = errors.New("invalid reserved bits")

// ExtendedHeader is the header of a QUIC packet.
type ExtendedHeader struct {
	Header

	typeByte byte

	KeyPhase protocol.KeyPhaseBit

	PacketNumberLen protocol.PacketNumberLen
	PacketNumber    protocol.PacketNumber

	parsedLen protocol.ByteCount
}

func ( *ExtendedHeader) ( []byte) (bool /* reserved bits valid */, error) {
	// read the (now unencrypted) first byte
	.typeByte = [0]
	.PacketNumberLen = protocol.PacketNumberLen(.typeByte&0x3) + 1
	if protocol.ByteCount(len()) < .Header.ParsedLen()+protocol.ByteCount(.PacketNumberLen) {
		return false, io.EOF
	}

	,  := readPacketNumber([.Header.ParsedLen():], .PacketNumberLen)
	if  != nil {
		return true, nil
	}
	.PacketNumber = 
	 := .typeByte&0xc == 0

	.parsedLen = .Header.ParsedLen() + protocol.ByteCount(.PacketNumberLen)
	return , 
}

// Append appends the Header.
func ( *ExtendedHeader) ( []byte,  protocol.Version) ([]byte, error) {
	if .DestConnectionID.Len() > protocol.MaxConnIDLen {
		return nil, fmt.Errorf("invalid connection ID length: %d bytes", .DestConnectionID.Len())
	}
	if .SrcConnectionID.Len() > protocol.MaxConnIDLen {
		return nil, fmt.Errorf("invalid connection ID length: %d bytes", .SrcConnectionID.Len())
	}

	var  uint8
	if  == protocol.Version2 {
		switch .Type {
		case protocol.PacketTypeInitial:
			 = 0b01
		case protocol.PacketType0RTT:
			 = 0b10
		case protocol.PacketTypeHandshake:
			 = 0b11
		case protocol.PacketTypeRetry:
			 = 0b00
		}
	} else {
		switch .Type {
		case protocol.PacketTypeInitial:
			 = 0b00
		case protocol.PacketType0RTT:
			 = 0b01
		case protocol.PacketTypeHandshake:
			 = 0b10
		case protocol.PacketTypeRetry:
			 = 0b11
		}
	}
	 := 0xc0 | <<4
	if .Type != protocol.PacketTypeRetry {
		// Retry packets don't have a packet number
		 |= uint8(.PacketNumberLen - 1)
	}

	 = append(, )
	 = append(, make([]byte, 4)...)
	binary.BigEndian.PutUint32([len()-4:], uint32(.Version))
	 = append(, uint8(.DestConnectionID.Len()))
	 = append(, .DestConnectionID.Bytes()...)
	 = append(, uint8(.SrcConnectionID.Len()))
	 = append(, .SrcConnectionID.Bytes()...)

	//nolint:exhaustive
	switch .Type {
	case protocol.PacketTypeRetry:
		 = append(, .Token...)
		return , nil
	case protocol.PacketTypeInitial:
		 = quicvarint.Append(, uint64(len(.Token)))
		 = append(, .Token...)
	}
	 = quicvarint.AppendWithLen(, uint64(.Length), 2)
	return appendPacketNumber(, .PacketNumber, .PacketNumberLen)
}

// ParsedLen returns the number of bytes that were consumed when parsing the header
func ( *ExtendedHeader) () protocol.ByteCount {
	return .parsedLen
}

// GetLength determines the length of the Header.
func ( *ExtendedHeader) ( protocol.Version) protocol.ByteCount {
	 := 1 /* type byte */ + 4 /* version */ + 1 /* dest conn ID len */ + protocol.ByteCount(.DestConnectionID.Len()) + 1 /* src conn ID len */ + protocol.ByteCount(.SrcConnectionID.Len()) + protocol.ByteCount(.PacketNumberLen) + 2 /* length */
	if .Type == protocol.PacketTypeInitial {
		 += protocol.ByteCount(quicvarint.Len(uint64(len(.Token))) + len(.Token))
	}
	return 
}

// Log logs the Header
func ( *ExtendedHeader) ( utils.Logger) {
	var  string
	if .Type == protocol.PacketTypeInitial || .Type == protocol.PacketTypeRetry {
		if len(.Token) == 0 {
			 = "Token: (empty), "
		} else {
			 = fmt.Sprintf("Token: %#x, ", .Token)
		}
		if .Type == protocol.PacketTypeRetry {
			.Debugf("\tLong Header{Type: %s, DestConnectionID: %s, SrcConnectionID: %s, %sVersion: %s}", .Type, .DestConnectionID, .SrcConnectionID, , .Version)
			return
		}
	}
	.Debugf("\tLong Header{Type: %s, DestConnectionID: %s, SrcConnectionID: %s, %sPacketNumber: %d, PacketNumberLen: %d, Length: %d, Version: %s}", .Type, .DestConnectionID, .SrcConnectionID, , .PacketNumber, .PacketNumberLen, .Length, .Version)
}

func appendPacketNumber( []byte,  protocol.PacketNumber,  protocol.PacketNumberLen) ([]byte, error) {
	switch  {
	case protocol.PacketNumberLen1:
		 = append(, uint8())
	case protocol.PacketNumberLen2:
		 := make([]byte, 2)
		binary.BigEndian.PutUint16(, uint16())
		 = append(, ...)
	case protocol.PacketNumberLen3:
		 := make([]byte, 4)
		binary.BigEndian.PutUint32(, uint32())
		 = append(, [1:]...)
	case protocol.PacketNumberLen4:
		 := make([]byte, 4)
		binary.BigEndian.PutUint32(, uint32())
		 = append(, ...)
	default:
		return nil, fmt.Errorf("invalid packet number length: %d", )
	}
	return , nil
}