#!/usr/bin/env python

MODE_MONO=0
MODE_DUAL=1
MODE_STEREO=2
MODE_JOINT=3

def mode_str(mode):
	if mode == MODE_MONO:
		return "MONO"
	elif mode == MODE_DUAL:
		return "DUAL"
	elif mode == MODE_STEREO:
		return "STEREO"
	elif mode == MODE_JOINT:
		return "JOINT"
	else:
		raise Exception("Invalid mode")

def validate_config(mode, channels, subbands, blocks, bitpool):
	if mode == MODE_MONO and channels != 1:
		return False
	elif channels != 2:
		return False
	
	if channels == 0 or channels > 2:
		return False
	
	if blocks != 4 and blocks != 8 and blocks != 12 and blocks != 16:
		return False
	
	if subbands != 4 and subbands != 8:
		return False
	
	if mode == MODE_MONO or mode == MODE_DUAL:
		if bitpool > (16 * subbands):
			return False
	elif mode == MODE_STEREO or mode == MODE_JOINT:
		if bitpool > (32 * subbands):
			return False
	
	return True

def header_length_gst_orig(mode, channels, subbands, blocks, bitpool):
	if not validate_config(mode, channels, subbands, blocks, bitpool):
		raise Exception("error!")
	
	if mode == MODE_MONO:
		return 4 + (subbands * 1) / 2 + (blocks * 1 * bitpool) / 8;
	elif mode == MODE_DUAL:
		return 4 + (subbands * 2) / 2 + (blocks * 2 * bitpool) / 8;
	elif mode == MODE_STEREO:
		return 4 + (subbands * 2) / 2 + (blocks * bitpool) / 8;
	elif mode == MODE_JOINT:
		return 4 + (subbands * 2) / 2 + (subbands + blocks * bitpool) / 8;

def header_length_gst_ts_patch(mode, channels, subbands, blocks, bitpool):
	if not validate_config(mode, channels, subbands, blocks, bitpool):
		raise Exception("Invalid config")
	
	if mode == MODE_MONO:
		return 4 + (subbands * 1) / 2 + (blocks * 1 * bitpool) / 8;
	elif mode == MODE_DUAL:
		return 4 + (subbands * 2) / 2 + (blocks * 2 * bitpool) / 8;
	elif mode == MODE_STEREO:
		return 4 + (subbands * 2) / 2 + (blocks * bitpool) / 8;
	elif mode == MODE_JOINT:
		return 5 + (subbands * 2) / 2 + (subbands + blocks * bitpool) / 8;

def header_length_gst_round_up(mode, channels, subbands, blocks, bitpool):
	if not validate_config(mode, channels, subbands, blocks, bitpool):
		raise Exception("Invalid config")
	
	if mode == MODE_MONO:
		return 4 + (subbands * 1) / 2 + ((blocks * 1 * bitpool) + 7) / 8;
	elif mode == MODE_DUAL:
		return 4 + (subbands * 2) / 2 + ((blocks * 2 * bitpool) + 7) / 8;
	elif mode == MODE_STEREO:
		return 4 + (subbands * 2) / 2 + ((blocks * bitpool) + 7) / 8;
	elif mode == MODE_JOINT:
		return 4 + (subbands * 2) / 2 + ((subbands + blocks * bitpool) + 7) / 8;

def header_length_bluez(mode, channels, subbands, blocks, bitpool):
	if not validate_config(mode, channels, subbands, blocks, bitpool):
		raise Exception("Invalid config")
	
	if mode == MODE_JOINT:
		joint = 1
	else:
		joint = 0

	ret = 4 + (4 * subbands * channels) / 8;
	# This term is not always evenly divide so we round it up
	if (channels == 1 or mode == MODE_DUAL):
		ret += ((blocks * channels * bitpool) + 7) / 8;
	else:
		if joint == 1:
			ret += (((subbands) + blocks * bitpool) + 7) / 8;
		else:
			ret += (((0) + blocks * bitpool) + 7) / 8;

	return ret;

def generate_configs():
	for mode in [MODE_MONO, MODE_STEREO, MODE_DUAL, MODE_JOINT]:
		for channels in [1, 2]:
			for subbands in [4, 8]:
				for blocks in [4, 8, 12, 16]:
					for bitpool in range((32 * subbands) + 1):
						if validate_config(mode, channels, subbands, blocks, bitpool):
							yield (mode, channels, subbands, blocks, bitpool)

if __name__ == "__main__":
	for config in generate_configs():
		mode     = config[0]
		channels = config[1]
		subbands = config[2]
		blocks   = config[3]
		bitpool  = config[4]
		
		gst_orig     = header_length_gst_orig    (mode, channels, subbands, blocks, bitpool)
		gst_ts_patch = header_length_gst_ts_patch(mode, channels, subbands, blocks, bitpool)
		gst_round_up = header_length_gst_round_up(mode, channels, subbands, blocks, bitpool)
		bluez        = header_length_bluez       (mode, channels, subbands, blocks, bitpool)
		
		len1 = bluez
		len2 = gst_round_up
		#len2 = gst_orig # XXX
		#len2 = gst_ts_patch
		
		if len1 != len2:
			print("Error: {0} != {1}".format(len1, len2))
			print("	mode:     {0}".format(mode_str(mode)))
			print("	channels: {0}".format(channels))
			print("	subbands: {0}".format(subbands))
			print("	blocks:   {0}".format(blocks))
			print("	bitpool:  {0}".format(bitpool))
