package huff0

import 

// BuildCTable builds a Huffman compression table from a precomputed symbol
// histogram and installs it as the previous (reuse) table on s.
//
// After this call:
//   - EstimateSize/CanUseTable can probe the table against other histograms.
//   - Compress1X/Compress4X with Reuse = ReusePolicyMust will encode without
//     emitting a new table header.
//   - TransferCTable can hand the table to a sibling Scratch.
//
// count[i] is the number of occurrences of symbol i. The histogram must have
// at least 2 distinct non-zero symbols; ErrUseRLE is returned for a single
// symbol and an error is returned for an empty histogram.
func ( *Scratch) ( *[256]uint32) error {
	if  == nil {
		return errors.New("huff0: BuildCTable on nil Scratch")
	}
	if  == nil {
		return errors.New("huff0: nil count passed to BuildCTable")
	}
	var  error
	,  = .prepare(nil)
	if  != nil {
		return 
	}
	.count = *
	var ,  int
	var  uint16
	for ,  := range .count {
		 += int()
		if int() >  {
			 = int()
		}
		if  != 0 {
			 = uint16() + 1
		}
	}
	if  == 0 {
		return errors.New("huff0: empty histogram")
	}
	if  < 2 ||  ==  {
		return ErrUseRLE
	}
	// huff0's internal rank table assumes total ≤ BlockSizeMax (it uses
	// highBit32(count+1) + 1 as a rank index into a fixed-size array).
	// Histograms summed across multiple blocks can exceed that; scale the
	// counts down preserving the distribution. Non-zero entries round up so
	// rare symbols stay representable.
	if  > BlockSizeMax {
		 := uint(0)
		for >> > BlockSizeMax {
			++
		}
		 := uint32(1<<) - 1
		var ,  int
		for ,  := range .count {
			if  == 0 {
				continue
			}
			 := ( + ) >> 
			if  == 0 {
				 = 1
			}
			.count[] = 
			 += int()
			if int() >  {
				 = int()
			}
		}
		 = 
		 = 
		if  ==  {
			return ErrUseRLE
		}
	}
	.symbolLen = 
	.maxCount = 
	.srcLen = 
	if  := .buildCTable();  != nil {
		return 
	}
	if cap(.prevTable) < len(.cTable) {
		.prevTable = make(cTable, 0, maxSymbolValue+1)
	}
	.prevTable = .prevTable[:len(.cTable)]
	copy(.prevTable, .cTable)
	.prevTableLog = .actualTableLog
	// Force the next Compress* to recount from real input.
	.clearCount = true
	.maxCount = 0
	return nil
}

// EstimateSize returns an estimated compressed payload size in bytes for the
// supplied histogram using the table currently stored in prevTable. It returns
// -1 when the table cannot encode every non-zero symbol of hist (i.e. when
// CanUseTable would return false). The estimate excludes the table header.
func ( *Scratch) ( *[256]uint32) int {
	if  == nil ||  == nil || len(.prevTable) == 0 {
		return -1
	}
	 := .prevTable
	 := uint32(7)
	for ,  := range  {
		if  == 0 {
			continue
		}
		if  >= len() || [].nBits == 0 {
			return -1
		}
		 += uint32([].nBits) * 
	}
	return int( >> 3)
}

// CanUseTable reports whether the table in prevTable can encode every
// non-zero symbol present in hist.
func ( *Scratch) ( *[256]uint32) bool {
	if  == nil ||  == nil || len(.prevTable) == 0 {
		return false
	}
	 := .prevTable
	for ,  := range  {
		if  == 0 {
			continue
		}
		if  >= len() || [].nBits == 0 {
			return false
		}
	}
	return true
}

// AppendTable serializes the table currently stored in prevTable (e.g. as
// installed by BuildCTable or carried over from a previous Compress call)
// into a self-delimiting zstd-style header and appends it to dst. The
// returned slice can be parsed back by ReadTable.
func ( *Scratch) ( []byte) ([]byte, error) {
	if  == nil || len(.prevTable) == 0 {
		return , errors.New("huff0: AppendTable with empty table")
	}
	// cTable.write reads s.actualTableLog, s.symbolLen, s.huffWeight, s.fse
	// and writes into s.Out. Save/restore Out so we don't disturb in-flight
	// compression buffers.
	 := .Out
	 := .actualTableLog
	 := .symbolLen
	if .fse == nil {
		// Lazily init in case AppendTable is called on a fresh Scratch.
		if ,  := .prepare(nil);  != nil {
			return , 
		}
		 = .Out
	}
	.Out = .Out[:0]
	.actualTableLog = .prevTableLog
	.symbolLen = uint16(len(.prevTable))
	if  := .prevTable.write();  != nil {
		.Out, .actualTableLog, .symbolLen = , , 
		return , 
	}
	 = append(, .Out...)
	.Out, .actualTableLog, .symbolLen = , , 
	return , nil
}