package huff0

import (
	
	
	
	
)

// Compress1X will compress the input.
// The output can be decoded using Decompress1X.
// Supply a Scratch object. The scratch object contains state about re-use,
// So when sharing across independent encodes, be sure to set the re-use policy.
func ( []byte,  *Scratch) ( []byte,  bool,  error) {
	,  = .prepare()
	if  != nil {
		return nil, false, 
	}
	return compress(, , .compress1X)
}

// Compress4X will compress the input. The input is split into 4 independent blocks
// and compressed similar to Compress1X.
// The output can be decoded using Decompress4X.
// Supply a Scratch object. The scratch object contains state about re-use,
// So when sharing across independent encodes, be sure to set the re-use policy.
func ( []byte,  *Scratch) ( []byte,  bool,  error) {
	,  = .prepare()
	if  != nil {
		return nil, false, 
	}
	if false {
		// TODO: compress4Xp only slightly faster.
		const  = 8 << 10
		if len() <  || runtime.GOMAXPROCS(0) == 1 {
			return compress(, , .compress4X)
		}
		return compress(, , .compress4Xp)
	}
	return compress(, , .compress4X)
}

func compress( []byte,  *Scratch,  func( []byte) ([]byte, error)) ( []byte,  bool,  error) {
	// Nuke previous table if we cannot reuse anyway.
	if .Reuse == ReusePolicyNone {
		.prevTable = .prevTable[:0]
	}

	// Create histogram, if none was provided.
	 := .maxCount
	var  = false
	if  == 0 {
		,  = .countSimple()
	} else {
		 = .canUseTable(.prevTable)
	}

	// We want the output size to be less than this:
	 := len()
	if .WantLogLess > 0 {
		 -=  >> .WantLogLess
	}

	// Reset for next run.
	.clearCount = true
	.maxCount = 0
	if  >= len() {
		if  > len() {
			return nil, false, fmt.Errorf("maxCount (%d) > length (%d)", , len())
		}
		if len() == 1 {
			return nil, false, ErrIncompressible
		}
		// One symbol, use RLE
		return nil, false, ErrUseRLE
	}
	if  == 1 ||  < (len()>>7) {
		// Each symbol present maximum once or too well distributed.
		return nil, false, ErrIncompressible
	}
	if .Reuse == ReusePolicyMust && ! {
		// We must reuse, but we can't.
		return nil, false, ErrIncompressible
	}
	if (.Reuse == ReusePolicyPrefer || .Reuse == ReusePolicyMust) &&  {
		 := .cTable
		 := .actualTableLog
		.cTable = .prevTable
		.actualTableLog = .prevTableLog
		.Out,  = ()
		.cTable = 
		.actualTableLog = 
		if  == nil && len(.Out) <  {
			.OutData = .Out
			return .Out, true, nil
		}
		if .Reuse == ReusePolicyMust {
			return nil, false, ErrIncompressible
		}
		// Do not attempt to re-use later.
		.prevTable = .prevTable[:0]
	}

	// Calculate new table.
	 = .buildCTable()
	if  != nil {
		return nil, false, 
	}

	if false && !.canUseTable(.cTable) {
		panic("invalid table generated")
	}

	if .Reuse == ReusePolicyAllow &&  {
		 := len(.Out)
		 := .prevTable.estimateSize(.count[:.symbolLen])
		 := .cTable.estimateSize(.count[:.symbolLen])
		if  <= + || +12 >=  {
			// Retain cTable even if we re-use.
			 := .cTable
			 := .actualTableLog

			.cTable = .prevTable
			.actualTableLog = .prevTableLog
			.Out,  = ()

			// Restore ctable.
			.cTable = 
			.actualTableLog = 
			if  != nil {
				return nil, false, 
			}
			if len(.Out) >=  {
				return nil, false, ErrIncompressible
			}
			.OutData = .Out
			return .Out, true, nil
		}
	}

	// Use new table
	 = .cTable.write()
	if  != nil {
		.OutTable = nil
		return nil, false, 
	}
	.OutTable = .Out

	// Compress using new table
	.Out,  = ()
	if  != nil {
		.OutTable = nil
		return nil, false, 
	}
	if len(.Out) >=  {
		.OutTable = nil
		return nil, false, ErrIncompressible
	}
	// Move current table into previous.
	.prevTable, .prevTableLog, .cTable = .cTable, .actualTableLog, .prevTable[:0]
	.OutData = .Out[len(.OutTable):]
	return .Out, false, nil
}

// EstimateSizes will estimate the data sizes
func ( []byte,  *Scratch) (, ,  int,  error) {
	,  = .prepare()
	if  != nil {
		return 0, 0, 0, 
	}

	// Create histogram, if none was provided.
	, ,  = -1, -1, -1
	 := .maxCount
	var  = false
	if  == 0 {
		,  = .countSimple()
	} else {
		 = .canUseTable(.prevTable)
	}

	// We want the output size to be less than this:
	 := len()
	if .WantLogLess > 0 {
		 -=  >> .WantLogLess
	}

	// Reset for next run.
	.clearCount = true
	.maxCount = 0
	if  >= len() {
		if  > len() {
			return 0, 0, 0, fmt.Errorf("maxCount (%d) > length (%d)", , len())
		}
		if len() == 1 {
			return 0, 0, 0, ErrIncompressible
		}
		// One symbol, use RLE
		return 0, 0, 0, ErrUseRLE
	}
	if  == 1 ||  < (len()>>7) {
		// Each symbol present maximum once or too well distributed.
		return 0, 0, 0, ErrIncompressible
	}

	// Calculate new table.
	 = .buildCTable()
	if  != nil {
		return 0, 0, 0, 
	}

	if false && !.canUseTable(.cTable) {
		panic("invalid table generated")
	}

	,  = .cTable.estTableSize()
	if  != nil {
		return 0, 0, 0, 
	}
	if  {
		 = .prevTable.estimateSize(.count[:.symbolLen])
	}
	 = .cTable.estimateSize(.count[:.symbolLen])

	// Restore
	return , , , nil
}

func ( *Scratch) ( []byte) ([]byte, error) {
	return .compress1xDo(.Out, ), nil
}

func ( *Scratch) (,  []byte) []byte {
	var  = bitWriter{out: }

	// N is length divisible by 4.
	 := len()
	 -=  & 3
	 := .cTable[:256]

	// Encode last bytes.
	for  := len() & 3;  > 0; -- {
		.encSymbol(, [+-1])
	}
	 -= 4
	if .actualTableLog <= 8 {
		for ;  >= 0;  -= 4 {
			 := [ : +4]
			// tmp should be len 4
			.flush32()
			.encFourSymbols([[3]], [[2]], [[1]], [[0]])
		}
	} else {
		for ;  >= 0;  -= 4 {
			 := [ : +4]
			// tmp should be len 4
			.flush32()
			.encTwoSymbols(, [3], [2])
			.flush32()
			.encTwoSymbols(, [1], [0])
		}
	}
	.close()
	return .out
}

var sixZeros [6]byte

func ( *Scratch) ( []byte) ([]byte, error) {
	if len() < 12 {
		return nil, ErrIncompressible
	}
	 := (len() + 3) / 4

	// Add placeholder for output length
	 := len(.Out)
	.Out = append(.Out, sixZeros[:]...)

	for  := range 4 {
		 := 
		if len() >  {
			 = [:]
		}
		 = [len():]

		 := len(.Out)
		.Out = .compress1xDo(.Out, )
		if len(.Out)- > math.MaxUint16 {
			// We cannot store the size in the jump table
			return nil, ErrIncompressible
		}
		// Write compressed length as little endian before block.
		if  < 3 {
			// Last length is not written.
			 := len(.Out) - 
			.Out[*2+] = byte()
			.Out[*2++1] = byte( >> 8)
		}
	}

	return .Out, nil
}

// compress4Xp will compress 4 streams using separate goroutines.
func ( *Scratch) ( []byte) ([]byte, error) {
	if len() < 12 {
		return nil, ErrIncompressible
	}
	// Add placeholder for output length
	.Out = .Out[:6]

	 := (len() + 3) / 4
	var  sync.WaitGroup
	.Add(4)
	for  := range 4 {
		 := 
		if len() >  {
			 = [:]
		}
		 = [len():]

		// Separate goroutine for each block.
		go func( int) {
			.tmpOut[] = .compress1xDo(.tmpOut[][:0], )
			.Done()
		}()
	}
	.Wait()
	for  := range 4 {
		 := .tmpOut[]
		if len() > math.MaxUint16 {
			// We cannot store the size in the jump table
			return nil, ErrIncompressible
		}
		// Write compressed length as little endian before block.
		if  < 3 {
			// Last length is not written.
			.Out[*2] = byte(len())
			.Out[*2+1] = byte(len() >> 8)
		}

		// Write output.
		.Out = append(.Out, ...)
	}
	return .Out, nil
}

// countSimple will create a simple histogram in s.count.
// Returns the biggest count.
// Does not update s.clearCount.
func ( *Scratch) ( []byte) ( int,  bool) {
	 = true
	_ = .count // Assert that s != nil to speed up the following loop.
	for ,  := range  {
		.count[]++
	}
	 := uint32(0)
	if len(.prevTable) > 0 {
		for ,  := range .count[:] {
			if  == 0 {
				continue
			}
			if  >  {
				 = 
			}
			.symbolLen = uint16() + 1
			if  >= len(.prevTable) {
				 = false
			} else if .prevTable[].nBits == 0 {
				 = false
			}
		}
		return int(), 
	}
	for ,  := range .count[:] {
		if  == 0 {
			continue
		}
		if  >  {
			 = 
		}
		.symbolLen = uint16() + 1
	}
	return int(), false
}

func ( *Scratch) ( cTable) bool {
	if len() < int(.symbolLen) {
		return false
	}
	for ,  := range .count[:.symbolLen] {
		if  != 0 && [].nBits == 0 {
			return false
		}
	}
	return true
}

//lint:ignore U1000 used for debugging
func ( *Scratch) ( cTable) bool {
	if len() < int(.symbolLen) {
		return false
	}
	for ,  := range .count[:.symbolLen] {
		if  != 0 {
			if [].nBits == 0 {
				return false
			}
			if [].nBits > .actualTableLog {
				return false
			}
		}
	}
	return true
}

// minTableLog provides the minimum logSize to safely represent a distribution.
func ( *Scratch) () uint8 {
	 := highBit32(uint32(.srcLen)) + 1
	 := highBit32(uint32(.symbolLen-1)) + 2
	if  <  {
		return uint8()
	}
	return uint8()
}

// optimalTableLog calculates and sets the optimal tableLog in s.actualTableLog
func ( *Scratch) () {
	 := .TableLog
	 := .minTableLog()
	 := uint8(highBit32(uint32(.srcLen-1))) - 1
	if  <  {
		// Accuracy can be reduced
		 = 
	}
	if  >  {
		 = 
	}
	// Need a minimum to safely represent all symbol values
	if  < minTablelog {
		 = minTablelog
	}
	if  > tableLogMax {
		 = tableLogMax
	}
	.actualTableLog = 
}

type cTableEntry struct {
	val   uint16
	nBits uint8
	// We have 8 bits extra
}

const huffNodesMask = huffNodesLen - 1

func ( *Scratch) () error {
	.optimalTableLog()
	.huffSort()
	if cap(.cTable) < maxSymbolValue+1 {
		.cTable = make([]cTableEntry, .symbolLen, maxSymbolValue+1)
	} else {
		.cTable = .cTable[:.symbolLen]
		for  := range .cTable {
			.cTable[] = cTableEntry{}
		}
	}

	var  = int16(.symbolLen)
	 := .symbolLen - 1

	 := 
	 := .nodes[1 : huffNodesLen+1]

	// This overlays the slice above, but allows "-1" index lookups.
	// Different from reference implementation.
	 := .nodes[0 : huffNodesLen+1]

	for [].count() == 0 {
		--
	}

	 := int16()
	 :=  +  - 1
	 := 
	[].setCount([].count() + [-1].count())
	[].setParent()
	[-1].setParent()
	++
	 -= 2
	for  := ;  <= ; ++ {
		[].setCount(1 << 30)
	}
	// fake entry, strong barrier
	[0].setCount(1 << 31)

	// create parents
	for  <=  {
		var ,  int16
		if [+1].count() < [+1].count() {
			 = 
			--
		} else {
			 = 
			++
		}
		if [+1].count() < [+1].count() {
			 = 
			--
		} else {
			 = 
			++
		}

		[].setCount([+1].count() + [+1].count())
		[+1].setParent()
		[+1].setParent()
		++
	}

	// distribute weights (unlimited tree height)
	[].setNbBits(0)
	for  :=  - 1;  >= ; -- {
		[].setNbBits([[].parent()].nbBits() + 1)
	}
	for  := uint16(0);  <= ; ++ {
		[].setNbBits([[].parent()].nbBits() + 1)
	}
	.actualTableLog = .setMaxHeight(int())
	 := .actualTableLog

	// fill result into tree (val, nbBits)
	if  > tableLogMax {
		return fmt.Errorf("internal error: maxNbBits (%d) > tableLogMax (%d)", , tableLogMax)
	}
	var  [tableLogMax + 1]uint16
	var  [16]uint16
	for ,  := range [:+1] {
		[.nbBits()]++
	}
	// determine stating value per rank
	{
		 := uint16(0)
		for  := ;  > 0; -- {
			// get starting value within each rank
			[] = 
			 += []
			 >>= 1
		}
	}

	// push nbBits per symbol, symbol order
	for ,  := range [:+1] {
		.cTable[.symbol()].nBits = .nbBits()
	}

	// assign value within rank, symbol order
	 := .cTable[:.symbolLen]
	for ,  := range  {
		 := .nBits & 15
		 := []
		[].val = 
		[] =  + 1
	}

	return nil
}

// huffSort will sort symbols, decreasing order.
func ( *Scratch) () {
	type  struct {
		    uint32
		 uint32
	}

	// Clear nodes
	 := .nodes[:huffNodesLen+1]
	.nodes = 
	 = [1 : huffNodesLen+1]

	// Sort into buckets based on length of symbol count.
	var  [32]
	for ,  := range .count[:.symbolLen] {
		 := highBit32(+1) & 31
		[].++
	}
	// maxBitLength is log2(BlockSizeMax) + 1
	const  = 18 + 1
	for  := ;  > 0; -- {
		[-1]. += [].
	}
	for  := range [:] {
		[]. = [].
	}
	for ,  := range .count[:.symbolLen] {
		 := (highBit32(+1) + 1) & 31
		 := [].
		[].++
		 := [(-1)&huffNodesMask]
		for  > []. &&  > .count() {
			[&huffNodesMask] = 
			--
			 = [(-1)&huffNodesMask]
		}
		[&huffNodesMask] = makeNodeElt(, byte())
	}
}

func ( *Scratch) ( int) uint8 {
	 := .actualTableLog
	 := .nodes[1 : huffNodesLen+1]
	//huffNode = huffNode[: huffNodesLen]

	 := [].nbBits()

	// early exit : no elt > maxNbBits
	if  <=  {
		return 
	}
	 := int(0)
	 := int(1) << ( - )
	 := uint32()

	for [].nbBits() >  {
		 +=  - (1 << ( - [].nbBits()))
		[].setNbBits()
		--
	}
	// n stops at huffNode[n].nbBits <= maxNbBits

	for [].nbBits() ==  {
		--
	}
	// n end at index of smallest symbol using < maxNbBits

	// renorm totalCost
	 >>=  -  /* note : totalCost is necessarily a multiple of baseCost */

	// repay normalized cost
	{
		const  = 0xF0F0F0F0
		var  [tableLogMax + 2]uint32

		for  := range [:] {
			[] = 
		}

		// Get pos of last (smallest) symbol per rank
		{
			 := 
			for  := int();  >= 0; -- {
				if [].nbBits() >=  {
					continue
				}
				 = [].nbBits() // < maxNbBits
				[-] = uint32()
			}
		}

		for  > 0 {
			 := uint8(highBit32(uint32())) + 1

			for ;  > 1; -- {
				 := []
				 := [-1]
				if  ==  {
					continue
				}
				if  ==  {
					break
				}
				 := [].count()
				 := 2 * [].count()
				if  <=  {
					break
				}
			}
			// only triggered when no more rank 1 symbol left => find closest one (note : there is necessarily at least one !)
			// HUF_MAX_TABLELOG test just to please gcc 5+; but it should not be necessary
			// FIXME: try to remove
			for ( <= tableLogMax) && ([] == ) {
				++
			}
			 -= 1 << ( - 1)
			if [-1] ==  {
				// this rank is no longer empty
				[-1] = []
			}
			[[]].setNbBits(1 +
				[[]].nbBits())
			if [] == 0 {
				/* special case, reached largest symbol */
				[] = 
			} else {
				[]--
				if [[]].nbBits() != - {
					[] =  /* this rank is now empty */
				}
			}
		}

		for  < 0 { /* Sometimes, cost correction overshoot */
			if [1] ==  { /* special case : no rank 1 symbol (using maxNbBits-1); let's create one from largest rank 0 (using maxNbBits) */
				for [].nbBits() ==  {
					--
				}
				[+1].setNbBits([+1].nbBits() - 1)
				[1] =  + 1
				++
				continue
			}
			[[1]+1].setNbBits([[1]+1].nbBits() - 1)
			[1]++
			++
		}
	}
	return 
}

// A nodeElt is the fields
//
//	count  uint32
//	parent uint16
//	symbol byte
//	nbBits uint8
//
// in some order, all squashed into an integer so that the compiler
// always loads and stores entire nodeElts instead of separate fields.
type nodeElt uint64

func makeNodeElt( uint32,  byte) nodeElt {
	return nodeElt() | nodeElt()<<48
}

func ( *nodeElt) () uint32  { return uint32(*) }
func ( *nodeElt) () uint16 { return uint16(* >> 32) }
func ( *nodeElt) () byte   { return byte(* >> 48) }
func ( *nodeElt) () uint8  { return uint8(* >> 56) }

func ( *nodeElt) ( uint32) { * = (*)&0xffffffff00000000 | nodeElt() }
func ( *nodeElt) ( int16) { * = (*)&0xffff0000ffffffff | nodeElt(uint16())<<32 }
func ( *nodeElt) ( uint8) { * = (*)&0x00ffffffffffffff | nodeElt()<<56 }