package brotli

import 

/* The distance symbols effectively used by "Large Window Brotli" (32-bit). */
const numHistogramDistanceSymbols = 544

type histogramLiteral struct {
	data_        [numLiteralSymbols]uint32
	total_count_ uint
	bit_cost_    float64
}

func histogramClearLiteral( *histogramLiteral) {
	.data_ = [numLiteralSymbols]uint32{}
	.total_count_ = 0
	.bit_cost_ = math.MaxFloat64
}

func clearHistogramsLiteral( []histogramLiteral,  uint) {
	var  uint
	for  = 0;  < ; ++ {
		histogramClearLiteral(&[:][0])
	}
}

func histogramAddLiteral( *histogramLiteral,  uint) {
	.data_[]++
	.total_count_++
}

func histogramAddVectorLiteral( *histogramLiteral,  []byte,  uint) {
	.total_count_ += 
	 += 1
	for {
		--
		if  == 0 {
			break
		}
		.data_[[0]]++
		 = [1:]
	}
}

func histogramAddHistogramLiteral( *histogramLiteral,  *histogramLiteral) {
	var  uint
	.total_count_ += .total_count_
	for  = 0;  < numLiteralSymbols; ++ {
		.data_[] += .data_[]
	}
}

func histogramDataSizeLiteral() uint {
	return numLiteralSymbols
}

type histogramCommand struct {
	data_        [numCommandSymbols]uint32
	total_count_ uint
	bit_cost_    float64
}

func histogramClearCommand( *histogramCommand) {
	.data_ = [numCommandSymbols]uint32{}
	.total_count_ = 0
	.bit_cost_ = math.MaxFloat64
}

func clearHistogramsCommand( []histogramCommand,  uint) {
	var  uint
	for  = 0;  < ; ++ {
		histogramClearCommand(&[:][0])
	}
}

func histogramAddCommand( *histogramCommand,  uint) {
	.data_[]++
	.total_count_++
}

func histogramAddVectorCommand( *histogramCommand,  []uint16,  uint) {
	.total_count_ += 
	 += 1
	for {
		--
		if  == 0 {
			break
		}
		.data_[[0]]++
		 = [1:]
	}
}

func histogramAddHistogramCommand( *histogramCommand,  *histogramCommand) {
	var  uint
	.total_count_ += .total_count_
	for  = 0;  < numCommandSymbols; ++ {
		.data_[] += .data_[]
	}
}

func histogramDataSizeCommand() uint {
	return numCommandSymbols
}

type histogramDistance struct {
	data_        [numDistanceSymbols]uint32
	total_count_ uint
	bit_cost_    float64
}

func histogramClearDistance( *histogramDistance) {
	.data_ = [numDistanceSymbols]uint32{}
	.total_count_ = 0
	.bit_cost_ = math.MaxFloat64
}

func clearHistogramsDistance( []histogramDistance,  uint) {
	var  uint
	for  = 0;  < ; ++ {
		histogramClearDistance(&[:][0])
	}
}

func histogramAddDistance( *histogramDistance,  uint) {
	.data_[]++
	.total_count_++
}

func histogramAddVectorDistance( *histogramDistance,  []uint16,  uint) {
	.total_count_ += 
	 += 1
	for {
		--
		if  == 0 {
			break
		}
		.data_[[0]]++
		 = [1:]
	}
}

func histogramAddHistogramDistance( *histogramDistance,  *histogramDistance) {
	var  uint
	.total_count_ += .total_count_
	for  = 0;  < numDistanceSymbols; ++ {
		.data_[] += .data_[]
	}
}

func histogramDataSizeDistance() uint {
	return numDistanceSymbols
}

type blockSplitIterator struct {
	split_  *blockSplit
	idx_    uint
	type_   uint
	length_ uint
}

func initBlockSplitIterator( *blockSplitIterator,  *blockSplit) {
	.split_ = 
	.idx_ = 0
	.type_ = 0
	if len(.lengths) > 0 {
		.length_ = uint(.lengths[0])
	} else {
		.length_ = 0
	}
}

func blockSplitIteratorNext( *blockSplitIterator) {
	if .length_ == 0 {
		.idx_++
		.type_ = uint(.split_.types[.idx_])
		.length_ = uint(.split_.lengths[.idx_])
	}

	.length_--
}

func buildHistogramsWithContext( []command,  *blockSplit,  *blockSplit,  *blockSplit,  []byte,  uint,  uint,  byte,  byte,  []int,  []histogramLiteral,  []histogramCommand,  []histogramDistance) {
	var  uint = 
	var  blockSplitIterator
	var  blockSplitIterator
	var  blockSplitIterator

	initBlockSplitIterator(&, )
	initBlockSplitIterator(&, )
	initBlockSplitIterator(&, )
	for  := range  {
		var  *command = &[]
		var  uint
		blockSplitIteratorNext(&)
		histogramAddCommand(&[.type_], uint(.cmd_prefix_))

		/* TODO: unwrap iterator blocks. */
		for  = uint(.insert_len_);  != 0; -- {
			var  uint
			blockSplitIteratorNext(&)
			 = .type_
			if  != nil {
				var  contextLUT = getContextLUT([])
				 = ( << literalContextBits) + uint(getContext(, , ))
			}

			histogramAddLiteral(&[], uint([&]))
			 = 
			 = [&]
			++
		}

		 += uint(commandCopyLen())
		if commandCopyLen() != 0 {
			 = [(-2)&]
			 = [(-1)&]
			if .cmd_prefix_ >= 128 {
				var  uint
				blockSplitIteratorNext(&)
				 = uint(uint32(.type_<<distanceContextBits) + commandDistanceContext())
				histogramAddDistance(&[], uint(.dist_prefix_)&0x3FF)
			}
		}
	}
}