/*
 * ====================================================================
 *
 * Copyright (c) 1999-2005 Matias Giovannini.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer. 
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution, if
 *    any, must include the following acknowledgement:  
 *       "This product includes software developed by 
 *        Matias Giovannini (http://paginar.net/matias/)."
 *    Alternately, this acknowledgement may appear in the software itself,
 *    if and wherever such third-party acknowledgements normally appear.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 */
//

function killChildren(parent) {
	while (parent.hasChildNodes())
		parent.removeChild(parent.firstChild);
}

function childOf(kind, parent) {
	return function (text) {
		var child = document.createElement(kind);
		child.appendChild(document.createTextNode(text));
		parent.appendChild(child);
		child.withStyle = function(map) {
			for (var k in map)
				this.style[k] = map[k];
			return this;
		}
		return child;
	}
}

function Row() {
	var row = document.createElement("tr");
	this.td = childOf("td", row);
	this.th = childOf("th", row);
	this.tr = function() { return row; }
	this.addTo = function(parent) { parent.appendChild(row); }
	return this;
}

function fixq(c, t, n) {
	if (t + 1.0 == 1.0)
		return c / n;
	else
		return -c * t / Math.expm1(-n * Math.logp1(t));
}

function Frances(monto, tna, cuotas, iva, cuota) {
	this.monto  = monto || 0;
	this.tna    = tna || 0;
	this.cuotas = Math.round(cuotas || 0);
	this.iva    = iva || 0;
	this.cuota  = cuota || 0;
	this.tem    = this.tna / 12;
	this.errors = new Array();

	this.hasErrors   = function() { return this.errors.length != 0; };
	this.getErrors   = function() { return this.errors; };

	this.recalcCuota = function() {
		this.cuota = fixq(this.monto, this.tem, this.cuotas)
	};
	this.recalcMonto = function() {
		this.monto = this.cuota / fixq(1., this.tem, this.cuotas);
	};
	this.recalcCuotas = function() {
		var num = -Math.logp1(-this.monto * this.tem / this.cuota);
		this.cuotas = Math.round(num / Math.logp1(this.tem));
		this.recalcCuota();
	};
	this.recalcTasa  = function() {
		var t0 = 0, f0 = this.monto / this.cuotas - this.cuota;
		if (f0 > 0) {
			this.cuota = this.monto / this.cuotas;
			this.errors.push("La cuota es insuficiente");
			return;
		}
		var t1 = 1e-3, f1;
		while ( (f1 = fixq(this.monto, t1, this.cuotas) - this.cuota) < 0 )
			t1 *= 2;
		var t, f;
		for (var i = 0; i != 30; i++) {
			t = (t0 * f1 - t1 * f0) / (f1 - f0);
			f = fixq(this.monto, t, this.cuotas) - this.cuota;
			if (Math.abs(f) < 1e-5) {
				this.tna   = Math.ceil(t * 120000) / 10000;
				this.tem   = this.tna / 12;
				this.recalcCuota();
				return;
			} else if (f < 0) {
				t0 = t;
				f0 = f;
			} else {
				t1 = t;
				f1 = f;
			}
		}
		this.errors.push("No es posible determinar la tasa");
	};

	this.recalcular  = this.recalcCuota;

	this.desarrollar = function() {
		var theTable = document.getElementById("result");
		var theRow;
		// Las tablas HTML llevan los pies en la cabeza
		var scuo = this.cuotas * this.cuota;
		var sint = scuo - this.monto;
		var siva = sint * this.iva;
		var smto = scuo + siva;
		theRow = new Row()
		theRow.th("Total");
		theRow.td("");
		theRow.td(this.monto.num2dec(0));
		theRow.td(sint.num2dec(0));
		theRow.td(siva.num2dec(0));
		theRow.td(smto.num2dec(0));
		// Tasa de Interes Compuesto p/cuota i
		var qt = Math.exp(-this.cuotas*Math.logp1(this.tem));
		for (var i = 1; i <= this.cuotas; i++) {
			var pcap = this.cuota * qt;
			var pint = this.cuota * (1 - qt);
			var pdeu = pint / this.tem;
			var piva = pint * this.iva;
			var mnto = this.cuota + piva;
			qt  *= 1 + this.tem;
			theRow = new Row();
			theRow.th(i);
			theRow.td(pdeu.num2dec(0));
			theRow.td(pcap.num2dec(0));
			theRow.td(pint.num2dec(0));
			theRow.td(piva.num2dec(0));
			theRow.td(mnto.num2dec(0));
			
		}
	};

	var numNul = 0;
	if (!this.monto) {
		this.recalcular = this.recalcMonto;
		numNul++;
	} else if (this.monto < 0)
		this.errors.push("El monto debe ser positivo");
	if (!this.tna) {
		this.recalcular = this.recalcTasa;
		numNul++;
	} else if (this.tna < 0)
		this.errors.push("La TNA debe ser positiva");
	if (!this.cuotas) {
		this.recalcular = this.recalcCuotas;
		numNul++;
	} else if (this.cuotas < 0)
		this.errors.push("Por lo menos debe pagar una cuota");
	if (!this.cuota) {
		this.recalcular = this.recalcCuota;
		numNul++;
	} else if (this.cuota < 0)
		this.errors.push("La cuota debe ser positiva");

	if (numNul > 1)
		this.errors.push("Faltan especificar valores");

	if (this.iva < 0.)
		this.errors.push("El IVA debe ser positivo");
	return this;
}

function simulador(form) {
	var monto  = parseFloat(form.monto.value);
	var tna    = parseFloat(form.tasa.value);
	var cuotas = parseInt(form.cuotas.value);
	var iva    = parseFloat(form.iva.value);
	var cuota  = parseInt(form.cuota.value);
	var ingreso = parseInt(form.ingresofamiliar.value);
	var fran   = new Frances(monto, tna/100, cuotas, iva/100, cuota);
	if (!fran.hasErrors())
		fran.recalcular();
	if (fran.hasErrors()) {
		alert(fran.getErrors().join(". "));
		return false;
	}
	form.monto.value  = fran.monto.num2dec(0);
	form.tasa.value   = (fran.tna * 100).num2dec(2);
	form.cuotas.value = fran.cuotas.num2dec(0);
	form.iva.value    = (fran.iva * 100).num2dec(2);
	form.cuota.value  = fran.cuota.num2dec(0);
	form.ingresofamiliar.value = fran.cuota.num2dec(0) * 4;
	fran.desarrollar();
	return true;
}