// Copyright 2019+ Klaus Post. All rights reserved.
// License information can be found in the LICENSE file.
// Based on work by Yann Collet, released under BSD License.

package zstd

import (
	
	
	
	
	
)

type frameHeader struct {
	ContentSize   uint64
	WindowSize    uint32
	SingleSegment bool
	Checksum      bool
	DictID        uint32
}

const maxHeaderSize = 14

func ( frameHeader) ( []byte) []byte {
	 = append(, frameMagic...)
	var  uint8
	if .Checksum {
		 |= 1 << 2
	}
	if .SingleSegment {
		 |= 1 << 5
	}

	var  []byte
	if .DictID > 0 {
		var  [4]byte
		if .DictID < 256 {
			 |= 1
			[0] = uint8(.DictID)
			 = [:1]
		} else if .DictID < 1<<16 {
			 |= 2
			binary.LittleEndian.PutUint16([:2], uint16(.DictID))
			 = [:2]
		} else {
			 |= 3
			binary.LittleEndian.PutUint32([:4], .DictID)
			 = [:4]
		}
	}
	var  uint8
	if .ContentSize >= 256 {
		++
	}
	if .ContentSize >= 65536+256 {
		++
	}
	if .ContentSize >= 0xffffffff {
		++
	}

	 |=  << 6

	 = append(, )
	if !.SingleSegment {
		const  = 10
		 := (bits.Len32(.WindowSize-1) - ) << 3
		 = append(, uint8())
	}
	if .DictID > 0 {
		 = append(, ...)
	}
	switch  {
	case 0:
		if .SingleSegment {
			 = append(, uint8(.ContentSize))
		}
		// Unless SingleSegment is set, framessizes < 256 are not stored.
	case 1:
		.ContentSize -= 256
		 = append(, uint8(.ContentSize), uint8(.ContentSize>>8))
	case 2:
		 = append(, uint8(.ContentSize), uint8(.ContentSize>>8), uint8(.ContentSize>>16), uint8(.ContentSize>>24))
	case 3:
		 = append(, uint8(.ContentSize), uint8(.ContentSize>>8), uint8(.ContentSize>>16), uint8(.ContentSize>>24),
			uint8(.ContentSize>>32), uint8(.ContentSize>>40), uint8(.ContentSize>>48), uint8(.ContentSize>>56))
	default:
		panic("invalid fcs")
	}
	return 
}

const skippableFrameHeader = 4 + 4

// calcSkippableFrame will return a total size to be added for written
// to be divisible by multiple.
// The value will always be > skippableFrameHeader.
// The function will panic if written < 0 or wantMultiple <= 0.
func calcSkippableFrame(,  int64) int {
	if  <= 0 {
		panic("wantMultiple <= 0")
	}
	if  < 0 {
		panic("written < 0")
	}
	 :=  % 
	if  == 0 {
		return 0
	}
	 :=  - 
	for  < skippableFrameHeader {
		 += 
	}
	return int()
}

// skippableFrame will add a skippable frame with a total size of bytes.
// total should be >= skippableFrameHeader and < math.MaxUint32.
func skippableFrame( []byte,  int,  io.Reader) ([]byte, error) {
	if  == 0 {
		return , nil
	}
	if  < skippableFrameHeader {
		return , fmt.Errorf("requested skippable frame (%d) < 8", )
	}
	if int64() > math.MaxUint32 {
		return , fmt.Errorf("requested skippable frame (%d) > max uint32", )
	}
	 = append(, 0x50, 0x2a, 0x4d, 0x18)
	 := uint32( - skippableFrameHeader)
	 = append(, uint8(), uint8(>>8), uint8(>>16), uint8(>>24))
	 := len()
	 = append(, make([]byte, )...)
	,  := io.ReadFull(, [:])
	return , 
}