/*

numbaseconv.js v1.0 02/10/15

class NumBaseConvertor
	- converts a given number from one base to another
	- support of bases: 2..36 inclusive
	- support of floating numbers

Copyright (c) 2001-2002 Borislav Manolov

@version 1.0 15 Oct 2002
@author Borislav Manolov
	b.manolov [-at-] gmail [-dot-] com
	http://purl.org/NET/borislav

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

*/

function NumBaseConvertor() {
	// --- fields ---
	this.fromBase = 10;
	this.toBase = 10;
	// Anzahl der berechneten Nachkommastellen
	this.fractionPrecision = 35;
	this.alphas = new Array('0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
		'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
		'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
		'U', 'V', 'W', 'X', 'Y', 'Z');
	this.nums = new Array(this.alphas.length);
	for (var i=0; i < this.alphas.length; i++) {
		this.nums[this.alphas[i]] = i;
	}
	this.errLayer = null;
	this.ERROR = "<ERROR>"

	// --- methods ---

	// takes the number from a field
	// and sets the new one into the same field
	this.convertWithOneField = convertWithOneField

	this.convertTo10 = convertTo10
	this.convertFrom10 = convertFrom10
	this.convertFrac = convertFrac
	this.setBases = setBases
	this.getAlphaFromNum = getAlphaFromNum
	this.getNumFromAlpha = getNumFromAlpha
	this.getFrac = getFrac
	this.showHelpForBase = showHelpForBase

	return this;
}

/* --------------------------- *** --------------------------- */
/* Converts from decimal to p-ic system	*/

function convertFrom10(decNumberToConvert) {
	var first = String(decNumberToConvert).charAt(0);
	var num1 = parseInt(decNumberToConvert);
	if (isNaN(num1) || first == '-' || first == '+') {
		return this.ERROR
	}
	var result = "", rest;

	while(num1 >= this.toBase) {
		rest = num1 % this.toBase;
		num1 = Math.floor(num1 / this.toBase);
		result += this.getAlphaFromNum(rest);
	}

	result += this.getAlphaFromNum(num1);
	var reversedResult = ""
	for (var i = result.length-1; i >= 0; i--) {
		reversedResult += result.charAt(i);
	}

	result = reversedResult + this.convertFrac(decNumberToConvert)
	return result;
} // end convertFrom10()

/* --------------------------- *** --------------------------- */
/* Converts from p-ic to decimal system */
// parseInt(valueToConvert, this.fromBase)
function convertTo10(valueToConvert) {
	var numstr = valueToConvert;
	var point, result = 0;
	var decNumber;

	if (this.fromBase == 10) {
		decNumber = numstr;
	}
	else {
		// check for decimal point
		if (numstr.indexOf(".") != -1) {
			point = numstr.indexOf(".");
			var secondPoint  = numstr.indexOf(".", point+1);
			if (secondPoint != -1)	 // if there is second point
				// remove the rest after the second point
				numstr = numstr.substring(0, secondPoint);
			else
				numstr = numstr.substring(0);
			// we remove the first point from numstr
			// but we keep its position in $point
			numstr = numstr.replace(/\./,"");
		} // end if
		else point = numstr.length;

		var isCorect = true;
		for (var i=0; i <= numstr.length-1; i++) {
			charnum = this.getNumFromAlpha(numstr.charAt(i));
			// if there is number greater or equal the base
			if (charnum >= this.fromBase)   {
				isCorect = false;
				break;
			}
			// if there is a letter by non-letter system
			if (this.fromBase <= 10 && (numstr.charAt(i) < "0" || numstr.charAt(i) > "9")) {
				isCorect = false;
				break;
			}
		}// end for
		if (isCorect) {
			// start of conversion
			var pos
			for (var i=0; i <= numstr.length-1; i++) {
				pos = (point - 1) - i;
				result += this.getNumFromAlpha(numstr.charAt(i)) * Math.pow(this.fromBase, pos);
			}// end for
			// end of conversion
			if (isNaN(result)) {
				return this.ERROR
			} else
				decNumber = result;
		}// end if (isCorect)
		else return this.ERROR
	}// end else
	return decNumber
}	// end convertTo10()


/* --------------------------- *** --------------------------- */
function setBases(toBase) {
	this.fromBase = this.toBase
	this.toBase = parseInt(toBase)
}

/* --------------------------- *** --------------------------- */
function getAlphaFromNum(num) {
	if (num < this.alphas.length)
		return this.alphas[num];
	else return false;
	//return num >=10 ? this.alphas[num-10] : num;
}	// end getAlphaFromNum()

/* --------------------------- *** --------------------------- */
function getNumFromAlpha(letter) {
	/*for (i=0; i < this.alphas.length; i++)
		if (letter.toUpperCase() == this.alphas[i]) {
			return i;
		}
	return letter;*/
	if (this.nums[letter.toUpperCase()] != undefined) {
		return this.nums[letter.toUpperCase()];
	} else return false;
}

/* --------------------------- *** --------------------------- */
function getFrac(numstr) {
	var frac = '';
	numstr = parseFloat(numstr);        // numstr is "number"
	numstr = String(numstr);            // numstr is again "string"

	decpoint = numstr.indexOf('.')
	if (decpoint != -1)
		// in format '.xxx'
		frac = numstr.substr(decpoint);
	else
		frac='';

	return frac;
}	// end getFrac

/* --------------------------- *** --------------------------- */
/* converts the fraction part of @param[decNumber] ----------- */
/* (which is in dec system) to base $this.toBase  ----------- */
function convertFrac(decNumber) {
	var frac = this.getFrac(decNumber);
	var convertedFrac = ""
	if (frac != 0) {
		var str = "";
		var p;

		for (var i=0; i < this.fractionPrecision && p!=Math.floor(p); i++) {
			p = frac * this.toBase;
			str +=  this.getAlphaFromNum(Math.floor(p));
			frac = this.getFrac(String(p));
		}// end for
		convertedFrac = "." + str;
	}// end if

    return convertedFrac
}// end convertFrac()

/* --------------------------- *** --------------------------- */
/* takes a number from @param[inputOutputField] and sets ----- */
/* the converted one into the same @param[inputOutputField] -- */
/* @param[base] -> the base for conversion ------------------- */
function convertWithOneField(toBase, inputOutputField) {
	this.setBases(toBase);
	var decNumber = this.convertTo10(inputOutputField.value);
	if (decNumber != this.ERROR) {
		if (this.toBase == 10) {
			inputOutputField.value =  decNumber;
		} else {
			var convertedNum = this.convertFrom10(decNumber)
			inputOutputField.value =  convertedNum == this.ERROR ? this.ERROR : convertedNum
		}
	} else inputOutputField.value = this.ERROR
}

/* --------------------------- *** --------------------------- */
// shows the letters used from the corresponding base
// and their equivalent in base 10
function showHelpForBase(base) {
	if (base!=11)
		// we use plural
		var ends = new Array("s","their")
	else
		// singular
		var ends = new Array("","its")

	var msg = "The used alpha"+ends[0]+" in base " + base + " and "
	msg += ends[1] + " corresponding value"+ends[0]+" in base 10 are:\n\n"

	for (var i=10; i < base; i++) {
		msg += this.alphas[i] + ' = ' + (i) + ',    \t'
		if ((i+1)%5 == 0)
			msg += '\n';
	}
	msg = msg.substring(0, msg.lastIndexOf(','));
	alert(msg);
}

