/*
 * Number base conversion
 * (C) Copyright by Rafael Vuijk (aka Dark Fader)
 */

function BaseConvert(inputNumber, inputBase, outputBase, inputChars, outputChars)
{
	if (inputBase < 2) return null;
	if (outputBase < 2) return null;
	var inputBits = Math.log(inputBase) / Math.log(2);
	var outputBits = Math.log(outputBase) / Math.log(2);

	var result;
	if ((inputBits != Math.floor(inputBits)) || (outputBits != Math.floor(outputBits)))
	{
		outputNumber = NonBase2NConvert(inputNumber, inputBase, outputBase, inputChars, outputChars);
	}
	else
	{
		outputNumber = Base2NConvert(inputNumber, inputBase, outputBase, inputChars, outputChars, inputBits, outputBits);
	}

	return outputNumber;
}

// -1 on error, null on ignore
function GetDigitValue(inputNumber, i, inputBase, inputChars)
{
	var c = inputNumber.charAt(i);
	var digitValue = inputChars.indexOf(c);
	if (digitValue < 0) digitValue = inputChars.indexOf(c.toUpperCase());	// allow lowercase
	if ((digitValue < 0) && (".,;%= \t\r\n".indexOf(c) >= 0)) return null;	// ignore delimiters
	if (digitValue >= inputBase) return -1;
	return digitValue;	// indexOf returns -1 when not found
}

function NonBase2NConvert(inputNumber, inputBase, outputBase, inputChars, outputChars)
{
	var total = new VLI();

	// input
	var inputBaseMul = new VLI(inputBase);
	for (var i=0; i<inputNumber.length; i++)
	{
		var digitValue = GetDigitValue(inputNumber, i, inputBase, inputChars);
		if (digitValue == null) continue;
		if (digitValue < 0) return null;
		total = total.mul(inputBaseMul);
		total = total.add(new VLI(digitValue));
	}
	//debug.value += "total=" + total + "\n"; debug.createTextRange().scrollIntoView(false);

	// output
	var result = "";
	var outputBaseDiv = new VLI(outputBase);
	while (!total.isNul())
	{
		total = total.div(outputBaseDiv);
		//debug.value += "total2=" + total + "\n"; debug.createTextRange().scrollIntoView(false);
		//debug.value += VLI_remainder + "\n"; debug.createTextRange().scrollIntoView(false);

		var digitValue = VLI_remainder;
		if (digitValue >= outputChars.length) return null;
		result = outputChars.charAt(digitValue) + result;
	}

	// padding (wrong...)
	/*var multiple = Math.floor(Math.log(inputBase) / Math.log(outputBase));
	while (Math.floor(result.length / multiple) != (result.length / multiple))
	{
		result = outputChars.charAt(0) + result;
	}*/

	return result;
}

function Base2NConvert(inputNumber, inputBase, outputBase, inputChars, outputChars, inputBits, outputBits)
{
	var bits = "";
	for (var i=0; i<inputNumber.length; i++)
	{
		var digitValue = GetDigitValue(inputNumber, i, inputBase, inputChars);
		if (digitValue == null) continue;
		if (digitValue < 0) return null;
		for (var b=inputBits-1; b>=0; b--)
		{
			bits += (digitValue >>> b & 1);
		}
	}

	// input padding (LSB first)
	//if (padding.checked) while (Math.floor(bits.length / outputBits) != (bits.length / outputBits))
	if (padding.checked) while ((bits.length % outputBits) != 0)
	{
		bits = bits + "0";
	}

	// output
	var result = "";
	for (var i=0; i<bits.length; i+=outputBits)
	{
		var digitValue = 0;
		for (var b=0; b<outputBits; b++)
		{
			digitValue += bits.charAt(bits.length-1-i-b) << b;
		}
		if (digitValue >= outputChars.length) return null;
		result = outputChars.charAt(digitValue) + result;
	}

	// pad output to multiple of 2 (hexadecimal will be padded to hexbytes for example)
	//if (padding.checked) while (Math.floor(result.length / 2) != (result.length / 2))
	if (padding.checked) while (result.length & 1)
	{
		result = result + outputChars.charAt(0);
	}

	return result;
}
