
//var color_alert = "#FB4040"
var color_alert = "#B33538"

// FUNCIONES AJAX

var http_request = false;

function envioAJAX(params) {
	http_request = false;
	var post_data = "";
	
	// No vienen parámetros de la tabla
	if(!params || params == null){
		params = 0;
	}
	//document.getElementById("financiacion_box").innerHTML = ""; // elimina el cuadro de financiacion_box (si se activa esta linea se ha de enviar siempre el financiacion_box desde el servidor

	// inicialización
	if (window.XMLHttpRequest) { // Mozilla, Safari,...
		http_request = new XMLHttpRequest();
		if (http_request.overrideMimeType) {
			http_request.overrideMimeType('text/xml');
			// Ver nota sobre esta linea al final
		}
	} else if (window.ActiveXObject) { // IE
		try {
			http_request = new ActiveXObject("Msxml2.XMLHTTP");
		} catch (e) {
			try {
				http_request = new ActiveXObject("Microsoft.XMLHTTP");
			} catch (e) {}
		}
	}
	
	// Comprobación AJAX
	if (!http_request) {
		//alert('Fallo :( No es posible crear una instancia XMLHTTP');
		alert('Por favor actualice su navegador a una versión más reciente');
		return false;
	}

	// Parseo y generación url
	//var url="procesa_calculadora.php"
	var server_script = "procesa_calculadora.php"
	
	promo = document.getElementById("selectPromo").value
	if(promo==0){
		// no hay selección
		document.getElementById("alert_box").innerHTML=""
		document.getElementById("resumen_box").innerHTML=""
		//document.getElementById("grafica_box").innerHTML=""
		document.getElementById("lista_pisos_box").innerHTML=""
		document.getElementById("financiacion_box").innerHTML=""
		// document.getElementById("calculo_interactivo").innerHTML=""
		document.getElementById("hipoteca_box").innerHTML=""
		// document.getElementById("rentas_box").innerHTML=""
		//document.getElementById("respuestaAJAX_box").innerHTML=""
		return
	}
	//url=url+"?p="+promo  // para metodo get
	post_data="p="+promo // para metodo post
	
	str_orig = document.getElementById("inversion").value
	str = eliminaLetras(str_orig);
	document.getElementById("inversion").value = str
	
	if(str.length==0){
		str = "0"
	}

	if(str==0){
		document.getElementById("inversion").value = "";
		document.getElementById("inversion").style.background = color_alert;
		document.getElementById("selectPromo").value = 0;
		document.getElementById("resumen_box").innerHTML = "";
		document.getElementById("hipoteca_box").innerHTML = "";
		// document.getElementById("rentas_box").innerHTML = "";
		//document.getElementById("respuestaAJAX_box").innerHTML = "";
		alert("No se ha indicado la cantidad estimada que se desea invertir");
		return;
	}
	else{
		document.getElementById("inversion").style.background = "#FFFFFF";
	}
	//url=url+"&q="+str // para método get
	if(params!=0){
		post_data = post_data + "&q="+str + params + "&tiempo="+new Date().getTime() // para metodo post
	}
	else{
		post_data = post_data + "&q="+str
		try{
			document.getElementById("table_number").value = 0;
		}catch(e){
			// nothing
		}
	}
	
	// Envío
	http_request.onreadystatechange = alertContents;
	//http_request.open('GET', url, true);  // para metodo get
	http_request.open('POST',server_script, true); // para metodo post
	//http_request.send(null);  // para metodo get
	http_request.setRequestHeader('Content-Type','application/x-www-form-urlencoded'); // para metodo post
	http_request.send(post_data); // para metodo post

	document.getElementById("inversion").focus();
}

/*
function replaceSpecialTokens_js(xml_string){

	html_string = xml_string;

	html_string = html_string.replace(/__--comillas--__/gi, '"');
	html_string = html_string.replace(/__--ampersand--__/gi, '&');
	html_string = html_string.replace(/__--menor--__/gi, '<');
	html_string = html_string.replace(/__--mayor--__/gi, '>');
	html_string = html_string.replace(/__--euro--__/gi, '€');

	return html_string;
}
*/

function alertContents() {

	if (http_request.readyState == 4) {
		if (http_request.status == 200) {
		
			//Se programan los saltos para visualizar la pagina correctamente
			// Se mueve a la parte superior de la página
			var salto_inicial="calculadora.php#1";
			try{
				var table_number = document.getElementById("table_number").value;
				if(table_number!=0){
					salto_inicial="calculadora.php#2";
				}else{
					//
				}
			}catch(e){
				//salto_inicial=150;
			}
			
			
			// window.scrollTo(0,1500);
			// try{
				// var table_number = document.getElementById("table_number").value;
				// window.scrollTo(0,salto_inicial+(table_number*50))
				// alert("try")
			// }catch (e) {
				// window.scrollTo(0,salto_inicial);//es la primera vuelta y se tiene que situar en la tabla de finaciacion
				// alert("catch")
			// }
			
			//alert(http_request.responseText); // Si fuera modo texto
			var xmldoc = http_request.responseXML;
			
			// Procesa inversion_box
			var inversion_box_node = xmldoc.getElementsByTagName('inversion_box').item(0);
			if(inversion_box_node.firstChild.data!="-1"){
				//document.getElementById("inversion_box").innerHTML = replaceSpecialTokens_js(inversion_box_node.firstChild.data);
				document.getElementById("inversion_box").innerHTML = inversion_box_node.firstChild.data;
			}
			//alert(inversion_box_node.firstChild.data);
			
			// Procesa select_box
			var select_box_node = xmldoc.getElementsByTagName('select_box').item(0);
			if(select_box_node.firstChild.data!="-1"){
				//document.getElementById("select_box").innerHTML = replaceSpecialTokens_js(select_box_node.firstChild.data);
				document.getElementById("select_box").innerHTML = select_box_node.firstChild.data;
			}
			//alert(select_box_node.firstChild.data);
			
			// Procesa alert_box
			var alert_box_node = xmldoc.getElementsByTagName('alert_box').item(0);
			if(alert_box_node.firstChild.data!="-1"){
				//document.getElementById("alert_box").innerHTML = replaceSpecialTokens_js(alert_box_node.firstChild.data);
				document.getElementById("alert_box").innerHTML = alert_box_node.firstChild.data;
				if(alert_box_node.firstChild.data!=""){
					salto_inicial="calculadora.php#0";
				}
			}
			//alert(alert_box_node.firstChild.data);
			
			/* // --> AL RESUMEN_BOX COMBINADO
			// Procesa resumen_box
			var resumen_box_node = xmldoc.getElementsByTagName('resumen_box').item(0);
			if(resumen_box_node.firstChild.data!="-1"){
				//document.getElementById("resumen_box").innerHTML = replaceSpecialTokens_js(resumen_box_node.firstChild.data);
				document.getElementById("resumen_box").innerHTML = resumen_box_node.firstChild.data;
				muestra_box("resumen_box");
			}
			//alert(resumen_box_node.firstChild.data);
			*/
			
			/* // --> AL RESUMEN_BOX COMBINADO
			// Procesa grafica_box
			var grafica_box_node = xmldoc.getElementsByTagName('grafica_box').item(0);
			if(grafica_box_node.firstChild.data!="-1"){
				//document.getElementById("grafica_box").innerHTML = replaceSpecialTokens_js(grafica_box_node.firstChild.data);
				document.getElementById("grafica_box").innerHTML = grafica_box_node.firstChild.data;
				muestra_box("grafica_box");
				
			}
			//alert(grafica_box_node.firstChild.data);
			*/
			
			// RESUMEN BOX COMBINADO
			// Procesa resumen_box
			var resumen_box_node = xmldoc.getElementsByTagName('resumen_box').item(0);
			var grafica_box_node = xmldoc.getElementsByTagName('grafica_box').item(0);
			if(resumen_box_node.firstChild.data!="-1" && grafica_box_node.firstChild.data!="-1"){
				document.getElementById("resumen_box").innerHTML = resumen_box_node.firstChild.data+grafica_box_node.firstChild.data;
				muestra_box("resumen_box");
			}
			
			////Procesa lista_pisos_box
			// var lista_pisos_box_node = xmldoc.getElementsByTagName('lista_pisos_box').item(0);
			// if(lista_pisos_box_node.firstChild.data!="-1"){
				////document.getElementById("lista_pisos_box").innerHTML = replaceSpecialTokens_js(lista_pisos_box_node.firstChild.data);
				// document.getElementById("lista_pisos_box").innerHTML = lista_pisos_box_node.firstChild.data;
				// muestra_box("lista_pisos_box");
			// }
			//alert(lista_pisos_box_node.firstChild.data);
			
			// Procesa financiacion_box
			var financiacion_box_node = xmldoc.getElementsByTagName('financiacion_box').item(0);
			if(financiacion_box_node.firstChild.data!="-1"){
				//document.getElementById("financiacion_box").innerHTML = replaceSpecialTokens_js(financiacion_box_node.firstChild.data);
				document.getElementById("financiacion_box").innerHTML = financiacion_box_node.firstChild.data;
				muestra_box("financiacion_box");
			}
			//alert(financiacion_box_node.firstChild.data);
			
			
			// Procesa hipoteca_box
			var hipoteca_box_node = xmldoc.getElementsByTagName('hipoteca_box').item(0);
			if(hipoteca_box_node.firstChild.data!="-1"){
				//document.getElementById("hipoteca_box").innerHTML = replaceSpecialTokens_js(hipoteca_box_node.firstChild.data);
				document.getElementById("hipoteca_box").innerHTML = hipoteca_box_node.firstChild.data;
				muestra_box("hipoteca_box");
			}
			//alert(hipoteca_box_node.firstChild.data);
			
			// Procesa rentas_box
			// var rentas_box_node = xmldoc.getElementsByTagName('rentas_box').item(0);
			// if(rentas_box_node.firstChild.data!="-1"){
				////document.getElementById("rentas_box").innerHTML = replaceSpecialTokens_js(rentas_box_node.firstChild.data);
				// document.getElementById("rentas_box").innerHTML = rentas_box_node.firstChild.data;
				// muestra_box("rentas_box");
			// }
			//alert(rentas_box_node.firstChild.data);
			
			// Se mueve a la parte superior de la página
			
			window.location.href = salto_inicial;
			
		} else {
			alert('Hubo problemas con la petición.');
		}
	}

}

// FUNCIONES COMUNES (PARSEO, CÁLCULO, ETC...)

function IsNumeric(sText){
	var ValidChars = "0123456789";
	var IsNumber=true;
	var Char;

	for (i = 0; i < sText.length && IsNumber == true; i++){ 
		Char = sText.charAt(i); 
		if (ValidChars.indexOf(Char) == -1){
			IsNumber = false;
		}
	}
	return IsNumber;
}

function revisaCantidadTabla(index){
// XXX Suprimido -> No va en explorer
/*
	var table_str = "";
	table_str = document.getElementById("table["+index+"]").value;
	var table_str2 = "";
	table_str2 = eliminaLetras(table_str);
	document.getElementById("table["+index+"]").value = table_str2;
	*/
}

function revisaTablaFinanciacion(){
	var table_number = document.getElementById("table_number").value;
	var parametros_tabla = "";
	var elemento_tabla = 0;
	var ind_i = 0;
	
	parametros_tabla = parametros_tabla + "&tn="+table_number;
	for(ind_i=0;ind_i<table_number;ind_i++){
		elemento_tabla = document.getElementById("table_data_["+ind_i+"]").value;
		parametros_tabla = parametros_tabla + "&t"+ind_i+"=" + elemento_tabla;
	}
	//document.getElementById("financiacion_box").innerHTML = "";
	envioAJAX(parametros_tabla);
}


function revisaCantidadInversion(){
	str = document.getElementById("inversion").value;
	str2 = eliminaLetras(str);
	document.getElementById("inversion").value = str2;
	document.getElementById("selectPromo").value = 0;
	document.getElementById("alert_box").innerHTML = "";
	document.getElementById("resumen_box").innerHTML = "";
	//document.getElementById("grafica_box").innerHTML = "";
	document.getElementById("lista_pisos_box").innerHTML = "";
	document.getElementById("financiacion_box").innerHTML = "";
	document.getElementById("hipoteca_box").innerHTML=""
	// document.getElementById("rentas_box").innerHTML=""
	//document.getElementById("respuestaAJAX_box").innerHTML = "";
	document.getElementById("inversion").style.background = "#FFFFFF";
}

function eliminaLetras(sText){
	var ValidChars = "0123456789";
	var IsNumber=true;
	var Char;
	sText_aux = "";

	for (i = 0; i < sText.length; i++){ 
		Char = sText.charAt(i); 
		if (ValidChars.indexOf(Char) == -1){
			// Do nothing
		}
		else{
			sText_aux = sText_aux + Char;
		}
	}
	return sText_aux;
}


// function calculaHipoteca(){
	// var duracion = document.getElementById("select_hipoteca").value;
	// var tae = document.getElementById("input_tae_hipoteca").value;
	// var cantidad = document.getElementById("input_cantidad_hipoteca").value;
	// var interes_mensual = tae/12;
	// var meses=duracion*12;
	// var calculo = ((cantidad*interes_mensual)/(100*(1-(Math.pow((1+(interes_mensual/100)),((-1)*meses))))));
	// document.getElementById("input_hipoteca_cantidad").value = Math.round(calculo*100)/100;
	
	// var suma_rentas=0;
	// var num_pisos = document.getElementById("numero_pisos").value;
	// for(ind_i=0;ind_i<num_pisos;ind_i++){
		// elemento = parseInt(document.getElementById("alquiler_piso_["+ind_i+"]").value);
		// suma_rentas=suma_rentas+elemento;
	// }
	// document.getElementById("rentabilidad").value =Math.round((suma_rentas-calculo)*100)/100;
	
// }

function changeNumberFormat(num){
	var num1=str_replace(num,".",";");
	var num2=str_replace(num1,",",".");
	var num3=str_replace(num2,";",",");
	return num3;
}
function str_replace(cadena, cambia_esto, por_esto) {
      return cadena.split(cambia_esto).join(por_esto);
}
// alert(str_replace('Hola mundo!','mundo','world')); 
function calculaHipoteca(){
	var duracion = document.getElementById("select_hipoteca").value;
	var tae = document.getElementById("input_tae_hipoteca_h").value;
	var cantidad = document.getElementById("input_cantidad_hipoteca_h").value;
	var interes_mensual = tae/12;
	var meses=duracion*12;
	var calculo = ((cantidad*interes_mensual)/(100*(1-(Math.pow((1+(interes_mensual/100)),((-1)*meses))))));
	var hip =calculo.numberFormat("0,0.00");
	var hip1=changeNumberFormat(hip);
	document.getElementById("input_hipoteca_cantidad").value = hip1;
	// document.getElementById("cuota_hipoteca").value = hip1;
	
	var suma_rentas=0;
	var num_pisos = document.getElementById("numero_pisos").value;
	for(ind_i=0;ind_i<num_pisos;ind_i++){
		elemento = parseInt(document.getElementById("alquiler_piso_["+ind_i+"]").value);
		suma_rentas=suma_rentas+elemento;
	}
	var r= suma_rentas-calculo;
	if (((r<10)&&(r>0))||((r>-10)&&(r<0))){
		var rent = r.numberFormat("0.00");
	}else{
		var rent = r.numberFormat("0,0.00");
	}
	var rent1=changeNumberFormat(rent);
	
	// document.getElementById("rentabilidad").value =Math.round((suma_rentas-calculo)*100)/100;
	document.getElementById("rentabilidad").value =rent1;
	if (r<0){
		// document.getElementById("rentabilidad").style.color ="#FB4040";
		document.getElementById("rentabilidad").style.color ="#FF0000";
	}else{
		document.getElementById("rentabilidad").style.color ="#3CCA04";
	}
}

function calculaHipoteca80(){
	var duracion = document.getElementById("select_hipoteca_80").value;
	var tae = document.getElementById("input_tae_hipoteca_h").value;
	var cantidad = document.getElementById("input_cantidad_hipoteca_80_h").value;
	var interes_mensual = tae/12;
	var meses=duracion*12;
	var calculo = ((cantidad*interes_mensual)/(100*(1-(Math.pow((1+(interes_mensual/100)),((-1)*meses))))));
	var hip =calculo.numberFormat("0,0.00");
	var hip1=changeNumberFormat(hip);
	document.getElementById("input_hipoteca_cantidad_80").value = hip1;
	// document.getElementById("cuota_hipoteca_80").value = hip1;
	
	var suma_rentas=0;
	var num_pisos = document.getElementById("numero_pisos").value;
	for(ind_i=0;ind_i<num_pisos;ind_i++){
		elemento = parseInt(document.getElementById("alquiler_piso_["+ind_i+"]").value);
		suma_rentas=suma_rentas+elemento;
	}
	var r= suma_rentas-calculo;
	if (((r<10)&&(r>0))||((r>-10)&&(r<0))){
		var rent = r.numberFormat("0.00");
	}else{
		var rent = r.numberFormat("0,0.00");
	}

	// var rent = r.numberFormat("0,0.00");
	var rent1=changeNumberFormat(rent);
	// document.getElementById("rentabilidad").value =Math.round((suma_rentas-calculo)*100)/100;
	document.getElementById("rentabilidad_80").value =rent1;
	if (r<0){
		// document.getElementById("rentabilidad").style.color ="#FB4040";
		document.getElementById("rentabilidad_80").style.color ="#FF0000";
	}else{
		document.getElementById("rentabilidad_80").style.color ="#3CCA04";
	}
}


function muestra_oculta_box(box){
	div = document.getElementById(box);
	mas_menos = document.getElementById("divisor_mas_menos"+box);
	if(div.style.display == "none"){
		div.style.display = "";
		document.getElementById("divisor_mas_menos"+box).innerHTML = "-";
	}
	else{
		div.style.display = "none";
		document.getElementById("divisor_mas_menos"+box).innerHTML = "+";
	}
}

function muestra_box(box){
	div = document.getElementById(box);
	mas_menos = document.getElementById("divisor_mas_menos"+box);
	div.style.display = "";
	document.getElementById("divisor_mas_menos"+box).innerHTML = "-";
}

function oculta_box(box){
	div = document.getElementById(box);
	mas_menos = document.getElementById("divisor_mas_menos"+box);
	div.style.display = "none";
	document.getElementById("divisor_mas_menos"+box).innerHTML = "+";
}

function acceptLegal(){
	divLegal = document.getElementById("aviso_legal_php");
	divCalculadora = document.getElementById("continue_php");
	divLegal.style.display = "none";
	divCalculadora.style.display = "";
}

function cambiaMasInfo(){
	div = document.getElementById("masinfo");
	if(div.style.display == "none"){
		div.style.display = "";
		document.getElementById("textomasinfo").innerHTML = "- info";
	}
	else{
		div.style.display = "none";
		document.getElementById("textomasinfo").innerHTML = "+ info";
	}
}

/*
 * Copyright (C) 2006 Baron Schwartz <baron at sequent dot org>
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by the
 * Free Software Foundation, version 2.1.
 *
 * 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 Lesser General Public License for more
 * details.
 *
 * $Revision: 1.3 $
 */

// Abbreviations: LODP = Left Of Decimal Point, RODP = Right Of Decimal Point
Number.formatFunctions = {count:0};

// Constants useful for controlling the format of numbers in special cases.
Number.prototype.NaN         = 'NaN';
Number.prototype.posInfinity = 'Infinity';
Number.prototype.negInfinity = '-Infinity';

Number.prototype.numberFormat = function(format, context) {
    if (isNaN(this) ) {
        return Number.prototype.NaNstring;
    }
    else if (this == +Infinity ) {
        return Number.prototype.posInfinity;
    }
    else if ( this == -Infinity) {
        return Number.prototype.negInfinity;
    }
    else if (Number.formatFunctions[format] == null) {
        Number.createNewFormat(format);
    }
    return this[Number.formatFunctions[format]](context);
}

Number.createNewFormat = function(format) {
    var funcName = "format" + Number.formatFunctions.count++;
    Number.formatFunctions[format] = funcName;
    var code = "Number.prototype." + funcName + " = function(context){\n";

    // Decide whether the function is a terminal or a pos/neg/zero function
    var formats = format.split(";");
    switch (formats.length) {
        case 1:
            code += Number.createTerminalFormat(format);
            break;
        case 2:
            code += "return (this < 0) ? this.numberFormat(\""
                + String.escape(formats[1])
                + "\", 1) : this.numberFormat(\""
                + String.escape(formats[0])
                + "\", 2);";
            break;
        case 3:
            code += "return (this < 0) ? this.numberFormat(\""
                + String.escape(formats[1])
                + "\", 1) : ((this == 0) ? this.numberFormat(\""
                + String.escape(formats[2])
                + "\", 2) : this.numberFormat(\""
                + String.escape(formats[0])
                + "\", 3));";
            break;
        default:
            code += "throw 'Too many semicolons in format string';";
            break;
    }
    eval(code + "}");
}

Number.createTerminalFormat = function(format) {
    // If there is no work to do, just return the literal value
    if (format.length > 0 && format.search(/[0#?]/) == -1) {
        return "return '" + String.escape(format) + "';\n";
    }
    // Negative values are always displayed without a minus sign when section separators are used.
    var code = "var val = (context == null) ? new Number(this) : Math.abs(this);\n";
    var thousands = false;
    var lodp = format;
    var rodp = "";
    var ldigits = 0;
    var rdigits = 0;
    var scidigits = 0;
    var scishowsign = false;
    var sciletter = "";
    // Look for (and remove) scientific notation instructions, which can be anywhere
    m = format.match(/\..*(e)([+-]?)(0+)/i);
    if (m) {
        sciletter = m[1];
        scishowsign = (m[2] == "+");
        scidigits = m[3].length;
        format = format.replace(/(e)([+-]?)(0+)/i, "");
    }
    // Split around the decimal point
    var m = format.match(/^([^.]*)\.(.*)$/);
    if (m) {
        lodp = m[1].replace(/\./g, "");
        rodp = m[2].replace(/\./g, "");
    }
    // Look for %
    if (format.indexOf('%') >= 0) {
        code += "val *= 100;\n";
    }
    // Look for comma-scaling to the left of the decimal point
    m = lodp.match(/(,+)(?:$|[^0#?,])/);
    if (m) {
        code += "val /= " + Math.pow(1000, m[1].length) + "\n;";
    }
    // Look for comma-separators
    if (lodp.search(/[0#?],[0#?]/) >= 0) {
        thousands = true;
    }
    // Nuke any extraneous commas
    if ((m) || thousands) {
        lodp = lodp.replace(/,/g, "");
    }
    // Figure out how many digits to the l/r of the decimal place
    m = lodp.match(/0[0#?]*/);
    if (m) {
        ldigits = m[0].length;
    }
    m = rodp.match(/[0#?]*/);
    if (m) {
        rdigits = m[0].length;
    }
    // Scientific notation takes precedence over rounding etc
    if (scidigits > 0) {
        code += "var sci = Number.toScientific(val,"
            + ldigits + ", " + rdigits + ", " + scidigits + ", " + scishowsign + ");\n"
            + "var arr = [sci.l, sci.r];\n";
    }
    else {
        // If there is no decimal point, round to nearest integer, AWAY from zero
        if (format.indexOf('.') < 0) {
            code += "val = (val > 0) ? Math.ceil(val) : Math.floor(val);\n";
        }
        // Numbers are rounded to the correct number of digits to the right of the decimal
        code += "var arr = val.round(" + rdigits + ").toFixed(" + rdigits + ").split('.');\n";
        // There are at least "ldigits" digits to the left of the decimal, so add zeros if needed.
        code += "arr[0] = (val < 0 ? '-' : '') + String.leftPad((val < 0 ? arr[0].substring(1) : arr[0]), "
            + ldigits + ", '0');\n";
    }
    // Add thousands separators
    if (thousands) {
        code += "arr[0] = Number.addSeparators(arr[0]);\n";
    }
    // Insert the digits into the formatting string.  On the LHS, extra digits are copied
    // into the result.  On the RHS, rounding has chopped them off.
    code += "arr[0] = Number.injectIntoFormat(arr[0].reverse(), '"
        + String.escape(lodp.reverse()) + "', true).reverse();\n";
    if (rdigits > 0) {
        code += "arr[1] = Number.injectIntoFormat(arr[1], '" + String.escape(rodp) + "', false);\n";
    }
    if (scidigits > 0) {
        code += "arr[1] = arr[1].replace(/(\\d{" + rdigits + "})/, '$1" + sciletter + "' + sci.s);\n";
    }
    return code + "return arr.join('.');\n";
}

Number.toScientific = function(val, ldigits, rdigits, scidigits, showsign) {
    var result = {l:"", r:"", s:""};
    var ex = "";
    // Make ldigits + rdigits significant figures
    var before = Math.abs(val).toFixed(ldigits + rdigits + 1).trim('0');
    // Move the decimal point to the right of all digits we want to keep,
    // and round the resulting value off
    var after = Math.round(new Number(before.replace(".", "").replace(
        new RegExp("(\\d{" + (ldigits + rdigits) + "})(.*)"), "$1.$2"))).toFixed(0);
    // Place the decimal point in the new string
    if (after.length >= ldigits) {
        after = after.substring(0, ldigits) + "." + after.substring(ldigits);
    }
    else {
        after += '.';
    }
    // Find how much the decimal point moved.  This is #places to LODP in the original
    // number, minus the #places in the new number.  There are no left-padded zeroes in
    // the new number, so the calculation for it is simpler than for the old number.
    result.s = (before.indexOf(".") - before.search(/[1-9]/)) - after.indexOf(".");
    // The exponent is off by 1 when it gets moved to the left.
    if (result.s < 0) {
        result.s++;
    }
    // Split the value around the decimal point and pad the parts appropriately.
    result.l = (val < 0 ? '-' : '') + String.leftPad(after.substring(0, after.indexOf(".")), ldigits, "0");
    result.r = after.substring(after.indexOf(".") + 1);
    if (result.s < 0) {
        ex = "-";
    }
    else if (showsign) {
        ex = "+";
    }
    result.s = ex + String.leftPad(Math.abs(result.s).toFixed(0), scidigits, "0");
    return result;
}

Number.prototype.round = function(decimals) {
    if (decimals > 0) {
        var m = this.toFixed(decimals + 1).match(
            new RegExp("(-?\\d*)\.(\\d{" + decimals + "})(\\d)\\d*$"));
        if (m && m.length) {
            return new Number(m[1] + "." + String.leftPad(Math.round(m[2] + "." + m[3]), decimals, "0"));
        }
    }
    return this;
}

Number.injectIntoFormat = function(val, format, stuffExtras) {
    var i = 0;
    var j = 0;
    var result = "";
    var revneg = val.charAt(val.length - 1) == '-';
    if ( revneg ) {
       val = val.substring(0, val.length - 1);
    }
    while (i < format.length && j < val.length && format.substring(i).search(/[0#?]/) >= 0) {
        if (format.charAt(i).match(/[0#?]/)) {
            // It's a formatting character; copy the corresponding character
            // in the value to the result
            if (val.charAt(j) != '-') {
                result += val.charAt(j);
            }
            else {
                result += "0";
            }
            j++;
        }
        else {
            result += format.charAt(i);
        }
        ++i;
    }
    if ( revneg && j == val.length ) {
        result += '-';
    }
    if (j < val.length) {
        if (stuffExtras) {
            result += val.substring(j);
        }
        if ( revneg ) {
             result += '-';
        }
    }
    if (i < format.length) {
        result += format.substring(i);
    }
    return result.replace(/#/g, "").replace(/\?/g, " ");
}

Number.addSeparators = function(val) {
    return val.reverse().replace(/(\d{3})/g, "$1,").reverse().replace(/^(-)?,/, "$1");
}

String.prototype.reverse = function() {
    var res = "";
    for (var i = this.length; i > 0; --i) {
        res += this.charAt(i - 1);
    }
    return res;
}

String.prototype.trim = function(ch) {
    if (!ch) ch = ' ';
    return this.replace(new RegExp("^" + ch + "+|" + ch + "+$", "g"), "");
}

String.leftPad = function (val, size, ch) {
    var result = new String(val);
    if (ch == null) {
        ch = " ";
    }
    while (result.length < size) {
        result = ch + result;
    }
    return result;
}

String.escape = function(string) {
    return string.replace(/('|\\)/g, "\\$1");
}
