// mredkj.com
// http://www.mredkj.com/javascript/nf_api.html
/*

    * The constructor
    * getOriginal
    * setCommas
    * setCurrency
    * setCurrencyPosition
    * setCurrencyPrefix
    * setCurrencyValue
    * setInputDecimal
    * setNegativeFormat
    * setNegativeRed
    * setNumber
    * setPlaces
    * setSeparators
    * toFormatted
    * toPercentage
    * toUnformatted

The constructor

NumberFormat(num, inputDecimal)

    * num - The number to be formatted.
      Also refer to setNumber
    * inputDecimal - (Optional) The decimal character for the input
      Also refer to setInputDecimal

getOriginal

Returns the number as it was passed in, which may include non-number characters. Added in v1.0.2

getOriginal()

    * No arguments

setCommas

Sets a switch that indicates if there should be commas. The separator value is set to a comma and the decimal value is set to a period. Modified in v1.5.0

setCommas(isC)

    * isC - true: the number should be formatted with commas; false: no commas

setCurrency

Sets a switch that indicates if the number should be displayed as currency

setCurrency(isC)

    * isC - true: display currency; false: don't display currency

setCurrencyPosition

Sets the position for currency, which includes position relative to the numbers and negative sign. This method does not automatically put the negative sign at the left or right. They are left by default, and would need to be set right with setNegativeFormat. New in v1.5.0
LEFT_OUTSIDE example: $-1.00
LEFT_INSIDE example: -$1.00
RIGHT_INSIDE example: 1.00$-
RIGHT_OUTSIDE example: 1.00-$

setCurrencyPosition(cp)

    * cp - The position. Use one of the constants.

setCurrencyPrefix

Sets the symbol for currency. The symbol will show up on the left of the numbers and outside a negative sign. Modified in v1.5.0 so it now calls setCurrencyValue and setCurrencyPosition(this.LEFT_OUTSIDE)

setCurrencyPrefix(cp)

    * cp - The symbol

setCurrencyValue

Sets the symbol for currency.

setCurrencyValue(val)

    * val - The symbol. e.g. '$'

setInputDecimal

Set the decimal value for the input. New in v1.5.0

setInputDecimal(val)

    * val - The decimal value for the input.

setNegativeFormat

Set the format for negative numbers. New in v1.5.0
LEFT_DASH example: -1000
RIGHT_DASH example: 1000-
PARENTHESIS example: (1000)

setNegativeFormat(format)

    * format - The format. Use one of the constants.

setNegativeRed

Format the number red if it's negative. For use in HTML markup, not in text boxes. New in v1.5.0

setNegativeRed(isRed)

    * isRed - true: to format the number red if negative, black if positive; false: for it to always be black font.

setNumber

Sets the number. If there is a non-period decimal format for the input, setInputDecimal should be called before calling setNumber. Modified in v1.5.0

setNumber(num, inputDecimal)

    * num - The number to be formatted
    * inputDecimal - (Optional) The decimal character for the input
      Also refer to setInputDecimal

setPlaces

Sets the precision of decimal places. Modified in v1.5.1 and v1.5.4

setPlaces(p, tr)

    * p - The number of places. The constant NO_ROUNDING (which equals -1) turns off rounding to a set number of places. Any other number of places less than or equal to zero is considered zero.
    * tr - Whether to truncate instead of rounding. (optional) Values can be true or false, or if left blank will count as false.

setSeparators

One purpose of this method is to set a switch that indicates if there should be separators between groups of numbers. Also, can use it to set the values for the separator and decimal. For example, in the value 1,000.00 the comma (,) is the separator and the period (.) is the decimal. Both separator and decimal are optional. The separator and decimal cannot be the same value. If they are, decimal with be changed. New in v1.5.0

Can use the following constants (via the instantiated object) for separator or decimal:
COMMA
PERIOD

setSeparators(isC, separator, decimal)

    * isC - true, if there should be separators; false, if there should be no separators
    * separator - the value of the separator (optional).
    * decimal - the value of the decimal (optional).

toFormatted

Returns the number as a string formatted according to the settings. Modified in v1.5.0 and v1.5.1

toFormatted()

    * No arguments

toPercentage

Format the current number as a percentage. This is separate from most of the regular formatting settings. The exception is the number of decimal places. If a number is 0.123 it will be formatted as 12.3%

toPercentage()

    * No arguments

toUnformatted

toUnformatted - Returns the number as just a number. If the original value was '100,000', then this method will return the number 100000 Modified comments in v1.0.2, because this method no longer returns the original value. Refer to getOriginal instead.

toUnformatted()

    * No arguments
*/

function NumberFormat(num, inputDecimal)
{
this.VERSION = 'Number Format v1.5.4';
this.COMMA = ',';
this.PERIOD = '.';
this.DASH = '-'; 
this.LEFT_PAREN = '('; 
this.RIGHT_PAREN = ')'; 
this.LEFT_OUTSIDE = 0; 
this.LEFT_INSIDE = 1;  
this.RIGHT_INSIDE = 2;  
this.RIGHT_OUTSIDE = 3;  
this.LEFT_DASH = 0; 
this.RIGHT_DASH = 1; 
this.PARENTHESIS = 2; 
this.NO_ROUNDING = -1 
this.num;
this.numOriginal;
this.hasSeparators = false;  
this.separatorValue;  
this.inputDecimalValue; 
this.decimalValue;  
this.negativeFormat; 
this.negativeRed; 
this.hasCurrency;  
this.currencyPosition;  
this.currencyValue;  
this.places;
this.roundToPlaces; 
this.truncate; 
this.setNumber = setNumberNF;
// by Gerd
this.setNumberFromGerman = function() {
	var Arg0 = ""+arguments[0];
	return this.setNumber(Arg0.replace(/[^0123456789,]/g, "").replace(/,/,"."), arguments[1]);
}
// by Gerd
this.toUnformatted = toUnformattedNF;
this.setInputDecimal = setInputDecimalNF; 
this.setSeparators = setSeparatorsNF; 
this.setCommas = setCommasNF;
this.setNegativeFormat = setNegativeFormatNF; 
this.setNegativeRed = setNegativeRedNF; 
this.setCurrency = setCurrencyNF;
this.setCurrencyPrefix = setCurrencyPrefixNF;
this.setCurrencyValue = setCurrencyValueNF; 
this.setCurrencyPosition = setCurrencyPositionNF; 
this.setPlaces = setPlacesNF;
this.toFormatted = toFormattedNF;
this.toPercentage = toPercentageNF;
this.getOriginal = getOriginalNF;
this.moveDecimalRight = moveDecimalRightNF;
this.moveDecimalLeft = moveDecimalLeftNF;
this.getRounded = getRoundedNF;
this.preserveZeros = preserveZerosNF;
this.justNumber = justNumberNF;
this.expandExponential = expandExponentialNF;
this.getZeros = getZerosNF;
this.moveDecimalAsString = moveDecimalAsStringNF;
this.moveDecimal = moveDecimalNF;
this.addSeparators = addSeparatorsNF;
if (inputDecimal == null) {
this.setNumber(num, this.PERIOD);
} else {
this.setNumber(num, inputDecimal); 
}
this.setCommas(true);
this.setNegativeFormat(this.LEFT_DASH); 
this.setNegativeRed(false); 
this.setCurrency(false); 
this.setCurrencyPrefix('$');
this.setPlaces(2);
}
function setInputDecimalNF(val)
{
this.inputDecimalValue = val;
}
function setNumberNF(num, inputDecimal)
{
	if (inputDecimal != null) {
		this.setInputDecimal(inputDecimal); 
	}
	this.numOriginal = num;
	this.num = this.justNumber(num);

	// by Gerd
	return this;
	// by Gerd
}
function toUnformattedNF()
{
return (this.num);
}
function getOriginalNF()
{
return (this.numOriginal);
}
function setNegativeFormatNF(format)
{
this.negativeFormat = format;
}
function setNegativeRedNF(isRed)
{
this.negativeRed = isRed;
}
function setSeparatorsNF(isC, separator, decimal)
{
this.hasSeparators = isC;
if (separator == null) separator = this.COMMA;
if (decimal == null) decimal = this.PERIOD;
if (separator == decimal) {
this.decimalValue = (decimal == this.PERIOD) ? this.COMMA : this.PERIOD;
} else {
this.decimalValue = decimal;
}
this.separatorValue = separator;
}
function setCommasNF(isC)
{
this.setSeparators(isC, this.COMMA, this.PERIOD);
}
function setCurrencyNF(isC)
{
this.hasCurrency = isC;
}
function setCurrencyValueNF(val)
{
this.currencyValue = val;
}
function setCurrencyPrefixNF(cp)
{
this.setCurrencyValue(cp);
this.setCurrencyPosition(this.LEFT_OUTSIDE);
}
function setCurrencyPositionNF(cp)
{
this.currencyPosition = cp
}
function setPlacesNF(p, tr)
{
this.roundToPlaces = !(p == this.NO_ROUNDING); 
this.truncate = (tr != null && tr); 
this.places = (p < 0) ? 0 : p; 
}
function addSeparatorsNF(nStr, inD, outD, sep)
{
nStr += '';
var dpos = nStr.indexOf(inD);
var nStrEnd = '';
if (dpos != -1) {
nStrEnd = outD + nStr.substring(dpos + 1, nStr.length);
nStr = nStr.substring(0, dpos);
}
var rgx = /(\d+)(\d{3})/;
while (rgx.test(nStr)) {
nStr = nStr.replace(rgx, '$1' + sep + '$2');
}
return nStr + nStrEnd;
}
function toFormattedNF()
{	
// by Gerd
if (isNaN(this.numOriginal))
	return "NaN";
// by Gerd
var pos;
var nNum = this.num; 
var nStr;            
var splitString = new Array(2);   
if (this.roundToPlaces) {
nNum = this.getRounded(nNum);
nStr = this.preserveZeros(Math.abs(nNum)); 
} else {
nStr = this.expandExponential(Math.abs(nNum)); 
}
if (this.hasSeparators) {
nStr = this.addSeparators(nStr, this.PERIOD, this.decimalValue, this.separatorValue);
} else {
nStr = nStr.replace(new RegExp('\\' + this.PERIOD), this.decimalValue); 
}
var c0 = '';
var n0 = '';
var c1 = '';
var n1 = '';
var n2 = '';
var c2 = '';
var n3 = '';
var c3 = '';
var negSignL = (this.negativeFormat == this.PARENTHESIS) ? this.LEFT_PAREN : this.DASH;
var negSignR = (this.negativeFormat == this.PARENTHESIS) ? this.RIGHT_PAREN : this.DASH;
if (this.currencyPosition == this.LEFT_OUTSIDE) {
if (nNum < 0) {
if (this.negativeFormat == this.LEFT_DASH || this.negativeFormat == this.PARENTHESIS) n1 = negSignL;
if (this.negativeFormat == this.RIGHT_DASH || this.negativeFormat == this.PARENTHESIS) n2 = negSignR;
}
if (this.hasCurrency) c0 = this.currencyValue;
} else if (this.currencyPosition == this.LEFT_INSIDE) {
if (nNum < 0) {
if (this.negativeFormat == this.LEFT_DASH || this.negativeFormat == this.PARENTHESIS) n0 = negSignL;
if (this.negativeFormat == this.RIGHT_DASH || this.negativeFormat == this.PARENTHESIS) n3 = negSignR;
}
if (this.hasCurrency) c1 = this.currencyValue;
}
else if (this.currencyPosition == this.RIGHT_INSIDE) {
if (nNum < 0) {
if (this.negativeFormat == this.LEFT_DASH || this.negativeFormat == this.PARENTHESIS) n0 = negSignL;
if (this.negativeFormat == this.RIGHT_DASH || this.negativeFormat == this.PARENTHESIS) n3 = negSignR;
}
if (this.hasCurrency) c2 = this.currencyValue;
}
else if (this.currencyPosition == this.RIGHT_OUTSIDE) {
if (nNum < 0) {
if (this.negativeFormat == this.LEFT_DASH || this.negativeFormat == this.PARENTHESIS) n1 = negSignL;
if (this.negativeFormat == this.RIGHT_DASH || this.negativeFormat == this.PARENTHESIS) n2 = negSignR;
}
if (this.hasCurrency) c3 = this.currencyValue;
}
nStr = c0 + n0 + c1 + n1 + nStr + n2 + c2 + n3 + c3;
if (this.negativeRed && nNum < 0) {
nStr = '<font color="red">' + nStr + '</font>';
}
return (nStr);
}
function toPercentageNF()
{
	nNum = this.num * 100;
	nNum = this.getRounded(nNum);
	nTemp = new NumberFormat();
	nTemp.COMMA = this.COMMA;
	nTemp.PERIOD = this.PERIOD;
	nTemp.DASH = this.DASH; 
	nTemp.LEFT_PAREN = this.LEFT_PAREN; 
	nTemp.RIGHT_PAREN = this.RIGHT_PAREN; 
	nTemp.LEFT_OUTSIDE = this.LEFT_OUTSIDE; 
	nTemp.LEFT_INSIDE = this.LEFT_INSIDE;  
	nTemp.RIGHT_INSIDE = this.RIGHT_INSIDE;  
	nTemp.RIGHT_OUTSIDE = this.RIGHT_OUTSIDE;  
	nTemp.LEFT_DASH = this.LEFT_DASH; 
	nTemp.RIGHT_DASH = this.RIGHT_DASH; 
	nTemp.PARENTHESIS = this.PARENTHESIS; 
	nTemp.NO_ROUNDING = this.NO_ROUNDING; 
	nTemp.num = nNum;
	nTemp.numOriginal = nNum;
	nTemp.hasSeparators = this.hasSeparators;  
	nTemp.separatorValue = this.separatorValue;  
	nTemp.inputDecimalValue = this.inputDecimalValue; 
	nTemp.decimalValue = this.decimalValue;  
	nTemp.negativeFormat = this.negativeFormat; 
	nTemp.negativeRed = this.negativeRed; 
	nTemp.hasCurrency = this.hasCurrency;  
	nTemp.currencyPosition = this.currencyPosition;  
	nTemp.currencyValue = this.currencyValue;  
	nTemp.places = this.places;
	nTemp.roundToPlaces = this.roundToPlaces; 
	nTemp.truncate = this.truncate; 
	
	return nTemp.toFormatted() + '%';
}
function getZerosNF(places)
{
var extraZ = '';
var i;
for (i=0; i<places; i++) {
extraZ += '0';
}
return extraZ;
}
function expandExponentialNF(origVal)
{
if (isNaN(origVal)) return origVal;
var newVal = parseFloat(origVal) + ''; 
var eLoc = newVal.toLowerCase().indexOf('e');
if (eLoc != -1) {
var plusLoc = newVal.toLowerCase().indexOf('+');
var negLoc = newVal.toLowerCase().indexOf('-', eLoc); 
var justNumber = newVal.substring(0, eLoc);
if (negLoc != -1) {
var places = newVal.substring(negLoc + 1, newVal.length);
justNumber = this.moveDecimalAsString(justNumber, true, parseInt(places));
} else {
if (plusLoc == -1) plusLoc = eLoc;
var places = newVal.substring(plusLoc + 1, newVal.length);
justNumber = this.moveDecimalAsString(justNumber, false, parseInt(places));
}
newVal = justNumber;
}
return newVal;
} 
function moveDecimalRightNF(val, places)
{
var newVal = '';
if (places == null) {
newVal = this.moveDecimal(val, false);
} else {
newVal = this.moveDecimal(val, false, places);
}
return newVal;
}
function moveDecimalLeftNF(val, places)
{
var newVal = '';
if (places == null) {
newVal = this.moveDecimal(val, true);
} else {
newVal = this.moveDecimal(val, true, places);
}
return newVal;
}
function moveDecimalAsStringNF(val, left, places)
{
var spaces = (arguments.length < 3) ? this.places : places;
if (spaces <= 0) return val; 
var newVal = val + '';
var extraZ = this.getZeros(spaces);
var re1 = new RegExp('([0-9.]+)');
if (left) {
newVal = newVal.replace(re1, extraZ + '$1');
var re2 = new RegExp('(-?)([0-9]*)([0-9]{' + spaces + '})(\\.?)');		
newVal = newVal.replace(re2, '$1$2.$3');
} else {
var reArray = re1.exec(newVal); 
if (reArray != null) {
newVal = newVal.substring(0,reArray.index) + reArray[1] + extraZ + newVal.substring(reArray.index + reArray[0].length); 
}
var re2 = new RegExp('(-?)([0-9]*)(\\.?)([0-9]{' + spaces + '})');
newVal = newVal.replace(re2, '$1$2$4.');
}
newVal = newVal.replace(/\.$/, ''); 
return newVal;
}
function moveDecimalNF(val, left, places)
{
var newVal = '';
if (places == null) {
newVal = this.moveDecimalAsString(val, left);
} else {
newVal = this.moveDecimalAsString(val, left, places);
}
return parseFloat(newVal);
}
function getRoundedNF(val)
{
val = this.moveDecimalRight(val);
if (this.truncate) {
val = val >= 0 ? Math.floor(val) : Math.ceil(val); 
} else {
val = Math.round(val);
}
val = this.moveDecimalLeft(val);
return val;
}
function preserveZerosNF(val)
{
var i;
val = this.expandExponential(val);
if (this.places <= 0) return val; 
var decimalPos = val.indexOf('.');
if (decimalPos == -1) {
val += '.';
for (i=0; i<this.places; i++) {
val += '0';
}
} else {
var actualDecimals = (val.length - 1) - decimalPos;
var difference = this.places - actualDecimals;
for (i=0; i<difference; i++) {
val += '0';
}
}
return val;
}
function justNumberNF(val)
{
newVal = val + '';
var isPercentage = false;
if (newVal.indexOf('%') != -1) {
newVal = newVal.replace(/\%/g, '');
isPercentage = true; 
}
var re = new RegExp('[^\\' + this.inputDecimalValue + '\\d\\-\\+\\(\\)eE]', 'g');	
newVal = newVal.replace(re, '');
var tempRe = new RegExp('[' + this.inputDecimalValue + ']', 'g');
var treArray = tempRe.exec(newVal); 
if (treArray != null) {
var tempRight = newVal.substring(treArray.index + treArray[0].length); 
newVal = newVal.substring(0,treArray.index) + this.PERIOD + tempRight.replace(tempRe, ''); 
}
if (newVal.charAt(newVal.length - 1) == this.DASH ) {
newVal = newVal.substring(0, newVal.length - 1);
newVal = '-' + newVal;
}
else if (newVal.charAt(0) == this.LEFT_PAREN
&& newVal.charAt(newVal.length - 1) == this.RIGHT_PAREN) {
newVal = newVal.substring(1, newVal.length - 1);
newVal = '-' + newVal;
}
newVal = parseFloat(newVal);
if (!isFinite(newVal)) {
newVal = 0;
}
if (isPercentage) {
newVal = this.moveDecimalLeft(newVal, 2);
}
return newVal;
}
