package brotli

const fastOnePassCompressionQuality = 0

const fastTwoPassCompressionQuality = 1

const zopflificationQuality = 10

const hqZopflificationQuality = 11

const maxQualityForStaticEntropyCodes = 2

const minQualityForBlockSplit = 4

const minQualityForNonzeroDistanceParams = 4

const minQualityForOptimizeHistograms = 4

const minQualityForExtensiveReferenceSearch = 5

const minQualityForContextModeling = 5

const minQualityForHqContextModeling = 7

const minQualityForHqBlockSplitting = 10

/* For quality below MIN_QUALITY_FOR_BLOCK_SPLIT there is no block splitting,
   so we buffer at most this much literals and commands. */
const maxNumDelayedSymbols = 0x2FFF

/* Returns hash-table size for quality levels 0 and 1. */
func maxHashTableSize( int) uint {
	if  == fastOnePassCompressionQuality {
		return 1 << 15
	} else {
		return 1 << 17
	}
}

/* The maximum length for which the zopflification uses distinct distances. */
const maxZopfliLenQuality10 = 150

const maxZopfliLenQuality11 = 325

/* Do not thoroughly search when a long copy is found. */
const longCopyQuickStep = 16384

func maxZopfliLen( *encoderParams) uint {
	if .quality <= 10 {
		return maxZopfliLenQuality10
	} else {
		return maxZopfliLenQuality11
	}
}

/* Number of best candidates to evaluate to expand Zopfli chain. */
func maxZopfliCandidates( *encoderParams) uint {
	if .quality <= 10 {
		return 1
	} else {
		return 5
	}
}

func sanitizeParams( *encoderParams) {
	.quality = brotli_min_int(maxQuality, brotli_max_int(minQuality, .quality))
	if .quality <= maxQualityForStaticEntropyCodes {
		.large_window = false
	}

	if .lgwin < minWindowBits {
		.lgwin = minWindowBits
	} else {
		var  int
		if .large_window {
			 = largeMaxWindowBits
		} else {
			 = maxWindowBits
		}
		if .lgwin > uint() {
			.lgwin = uint()
		}
	}
}

/* Returns optimized lg_block value. */
func computeLgBlock( *encoderParams) int {
	var  int = .lgblock
	if .quality == fastOnePassCompressionQuality || .quality == fastTwoPassCompressionQuality {
		 = int(.lgwin)
	} else if .quality < minQualityForBlockSplit {
		 = 14
	} else if  == 0 {
		 = 16
		if .quality >= 9 && .lgwin > uint() {
			 = brotli_min_int(18, int(.lgwin))
		}
	} else {
		 = brotli_min_int(maxInputBlockBits, brotli_max_int(minInputBlockBits, ))
	}

	return 
}

/* Returns log2 of the size of main ring buffer area.
   Allocate at least lgwin + 1 bits for the ring buffer so that the newly
   added block fits there completely and we still get lgwin bits and at least
   read_block_size_bits + 1 bits because the copy tail length needs to be
   smaller than ring-buffer size. */
func computeRbBits( *encoderParams) int {
	return 1 + brotli_max_int(int(.lgwin), .lgblock)
}

func maxMetablockSize( *encoderParams) uint {
	var  int = brotli_min_int(computeRbBits(), maxInputBlockBits)
	return uint(1) << uint()
}

/* When searching for backward references and have not seen matches for a long
   time, we can skip some match lookups. Unsuccessful match lookups are very
   expensive and this kind of a heuristic speeds up compression quite a lot.
   At first 8 byte strides are taken and every second byte is put to hasher.
   After 4x more literals stride by 16 bytes, every put 4-th byte to hasher.
   Applied only to qualities 2 to 9. */
func literalSpreeLengthForSparseSearch( *encoderParams) uint {
	if .quality < 9 {
		return 64
	} else {
		return 512
	}
}

func chooseHasher( *encoderParams,  *hasherParams) {
	if .quality > 9 {
		.type_ = 10
	} else if .quality == 4 && .size_hint >= 1<<20 {
		.type_ = 54
	} else if .quality < 5 {
		.type_ = .quality
	} else if .lgwin <= 16 {
		if .quality < 7 {
			.type_ = 40
		} else if .quality < 9 {
			.type_ = 41
		} else {
			.type_ = 42
		}
	} else if .size_hint >= 1<<20 && .lgwin >= 19 {
		.type_ = 6
		.block_bits = .quality - 1
		.bucket_bits = 15
		.hash_len = 5
		if .quality < 7 {
			.num_last_distances_to_check = 4
		} else if .quality < 9 {
			.num_last_distances_to_check = 10
		} else {
			.num_last_distances_to_check = 16
		}
	} else {
		.type_ = 5
		.block_bits = .quality - 1
		if .quality < 7 {
			.bucket_bits = 14
		} else {
			.bucket_bits = 15
		}
		if .quality < 7 {
			.num_last_distances_to_check = 4
		} else if .quality < 9 {
			.num_last_distances_to_check = 10
		} else {
			.num_last_distances_to_check = 16
		}
	}

	if .lgwin > 24 {
		/* Different hashers for large window brotli: not for qualities <= 2,
		   these are too fast for large window. Not for qualities >= 10: their
		   hasher already works well with large window. So the changes are:
		   H3 --> H35: for quality 3.
		   H54 --> H55: for quality 4 with size hint > 1MB
		   H6 --> H65: for qualities 5, 6, 7, 8, 9. */
		if .type_ == 3 {
			.type_ = 35
		}

		if .type_ == 54 {
			.type_ = 55
		}

		if .type_ == 6 {
			.type_ = 65
		}
	}
}