package smb2

// ----------------------------------------------------------------------------
// SMB2 Packet Header
//

type PacketHeader struct {
	CreditCharge          uint16
	ChannelSequence       uint16
	Status                uint32
	Command               uint16
	CreditRequestResponse uint16
	Flags                 uint32
	MessageId             uint64
	AsyncId               uint64
	TreeId                uint32
	SessionId             uint64
}

func ( *PacketHeader) ( []byte) {
	 := PacketCodec()

	.SetProtocolId()
	.SetStructureSize()
	.SetCreditCharge(.CreditCharge)

	switch {
	case .ChannelSequence != 0:
		.SetChannelSequence(.ChannelSequence)
	case .Status != 0:
		.SetStatus(.Status)
	}

	.SetCommand(.Command)
	.SetCreditRequest(.CreditRequestResponse)
	.SetFlags(.Flags)
	.SetMessageId(.MessageId)

	switch {
	case .TreeId != 0:
		.SetTreeId(.TreeId)
	case .AsyncId != 0:
		.SetAsyncId(.AsyncId)
	}

	.SetSessionId(.SessionId)
}

// ----------------------------------------------------------------------------
// SMB2 Packet Interface
//

type Packet interface {
	Encoder

	Header() *PacketHeader
}

// ----------------------------------------------------------------------------
// SMB2 Packet Header
//

type PacketCodec []byte

func ( PacketCodec) () bool {
	if len() < 64 {
		return true
	}

	 := .ProtocolId()
	if [0] != 0xfe {
		return true
	}
	if [1] != 'S' {
		return true
	}
	if [2] != 'M' {
		return true
	}
	if [3] != 'B' {
		return true
	}

	if .StructureSize() != 64 {
		return true
	}

	if .NextCommand()&7 != 0 {
		return true
	}

	return false
}

func ( PacketCodec) () []byte {
	return [:4]
}

func ( PacketCodec) () {
	copy(, MAGIC)
}

func ( PacketCodec) () uint16 {
	return le.Uint16([4:6])
}

func ( PacketCodec) () {
	le.PutUint16([4:6], 64)
}

func ( PacketCodec) () uint16 {
	return le.Uint16([6:8])
}

func ( PacketCodec) ( uint16) {
	le.PutUint16([6:8], )
}

func ( PacketCodec) () uint32 {
	return le.Uint32([8:12])
}

func ( PacketCodec) ( uint32) {
	le.PutUint32([8:12], )
}

func ( PacketCodec) () uint16 {
	return le.Uint16([12:14])
}

func ( PacketCodec) ( uint16) {
	le.PutUint16([12:14], )
}

func ( PacketCodec) () uint16 {
	return le.Uint16([14:16])
}

func ( PacketCodec) ( uint16) {
	le.PutUint16([14:16], )
}

func ( PacketCodec) () uint16 {
	return le.Uint16([14:16])
}

func ( PacketCodec) ( uint16) {
	le.PutUint16([14:16], )
}

func ( PacketCodec) () uint32 {
	return le.Uint32([16:20])
}

func ( PacketCodec) ( uint32) {
	le.PutUint32([16:20], )
}

func ( PacketCodec) () uint32 {
	return le.Uint32([20:24])
}

func ( PacketCodec) ( uint32) {
	le.PutUint32([20:24], )
}

func ( PacketCodec) () uint64 {
	return le.Uint64([24:32])
}

func ( PacketCodec) ( uint64) {
	le.PutUint64([24:32], )
}

func ( PacketCodec) () uint64 {
	return le.Uint64([32:40])
}

func ( PacketCodec) ( uint64) {
	le.PutUint64([32:40], )
}

func ( PacketCodec) () uint32 {
	return le.Uint32([36:40])
}

func ( PacketCodec) ( uint32) {
	le.PutUint32([36:40], )
}

func ( PacketCodec) () uint64 {
	return le.Uint64([40:48])
}

func ( PacketCodec) ( uint64) {
	le.PutUint64([40:48], )
}

func ( PacketCodec) () []byte {
	return [48:64]
}

func ( PacketCodec) ( []byte) {
	copy([48:64], )
}

func ( PacketCodec) () []byte {
	return [64:]
}

// From SMB3

func ( PacketCodec) () uint16 {
	return le.Uint16([8:10])
}

func ( PacketCodec) ( uint16) {
	le.PutUint16([8:10], )
}

// ----------------------------------------------------------------------------
// SMB2 TRANSFORM_HEADER
//

// From SMB3

type TransformCodec []byte

func ( TransformCodec) () bool {
	if len() < 52 {
		return true
	}

	 := .ProtocolId()
	if [0] != 0xfd {
		return true
	}
	if [1] != 'S' {
		return true
	}
	if [2] != 'M' {
		return true
	}
	if [3] != 'B' {
		return true
	}

	return false
}

func ( TransformCodec) () []byte {
	return [:4]
}

func ( TransformCodec) () {
	copy([:4], MAGIC2)
}

func ( TransformCodec) () []byte {
	return [4:20]
}

func ( TransformCodec) ( []byte) {
	copy([4:20], )
}

func ( TransformCodec) () []byte {
	return [20:36]
}

func ( TransformCodec) ( []byte) {
	copy([20:36], )
}

func ( TransformCodec) () uint32 {
	return le.Uint32([36:40])
}

func ( TransformCodec) ( uint32) {
	le.PutUint32([36:40], )
}

func ( TransformCodec) () uint16 {
	return le.Uint16([42:44])
}

func ( TransformCodec) ( uint16) {
	le.PutUint16([42:44], )
}

func ( TransformCodec) () uint64 {
	return le.Uint64([44:52])
}

func ( TransformCodec) ( uint64) {
	le.PutUint64([44:52], )
}

func ( TransformCodec) () []byte {
	return [20:52]
}

func ( TransformCodec) () []byte {
	return [52:]
}

// From SMB311

func ( TransformCodec) () uint16 {
	return le.Uint16([42:44])
}

func ( TransformCodec) ( uint16) {
	le.PutUint16([42:44], )
}