if (Calculators == undefined) {
	var Calculators = {};
}
if (Calculators.math == undefined) {
	Calculators.math = {};
}
Calculators.math.Formulas = function Formulas() {
    this.MONTHLY = 12;

	// Functions from Apache POI project: http://jcs.mobile-utopia.com/jcs/5973_FinanceLib.java
    
	// Present Value
    /**
     * Present value of an amount given the number of future payments, rate, amount
     * of individual payment, future value and boolean value indicating whether
     * payments are due at the beginning of period 
     * (false => payments are due at end of period) 
     * @param r
     * @param n
     * @param y
     * @param f
     * @param t
     * @return
     */
    this.pv = function(rate, nper, pmt, fv, type){
        var retval = 0;
        if (rate == 0) {
            retval = -1 * ((nper * pmt) + fv);
        }
        else {
            var r1 = rate + 1;
            retval = (((1 - Math.pow(r1, nper)) / rate) *
            ((type) ? r1 : 1) * pmt - fv) /
            Math.pow(r1, nper);
        }
        return -1 * (Math.round(retval*100)/100);
    };
    
    this.pvPrecision = function(rate, nper, pmt, fv, type){
        var retval = 0;
        if (rate == 0) {
            retval = -1 * ((nper * pmt) + fv);
        }
        else {
            var r1 = rate + 1;
            retval = (((1 - Math.pow(r1, nper)) / rate) *
            ((type) ? r1 : 1) * pmt - fv) /
            Math.pow(r1, nper);
        }
        return -1 * (Math.round(retval*1000000)/1000000);
    };
  // Future Value
    /**
     * Future value of an amount given the number of payments, rate, amount
     * of individual payment, present value and boolean value indicating whether
     * payments are due at the beginning of period 
     * (false => payments are due at end of period) 
     * @param r rate
     * @param n num of periods
     * @param y pmt per period
     * @param f future value
     * @param t type (true=pmt at end of period, false=pmt at begining of period)
     * @return
     */
    this.fv = function(r, n, y, p, t) {
        var retval = 0;
		if (p == undefined) {
			p = 0;
		}
		if (t == undefined) {
			t = 0;
		}
        if (r == 0) {
            retval = -1*(p+(n*y));
        }
        else {
            var r1 = r + 1;
            retval =((1 - Math.pow(r1, n)) * (t ? r1 : 1) * y ) / r - 
				p * Math.pow(r1, n);
        }
        return retval;
    }
	
	// Payment
    this.pmt = function(rate, nper, pv, fv, type){
        var retval = 0;
        if (rate == 0) {
            retval = -1 * (fv + pv) / nper;
        }
        else {
            var r1 = rate + 1;
            retval = (fv + pv * Math.pow(r1, nper)) *
            rate /
            ((type ? r1 : 1) * (1 - Math.pow(r1, nper)));
        }
        return Math.round(retval*100)/100;
    };
	
	// Required investment deposits
	this.required_deposits = function(fv, ir, np) {
		var pmt = fv * ir / (Math.pow(1 + ir, np) - 1);
		return pmt;
	}
	
	// number of periods, adapted from FinanceLib.java in apache POI project
	this.nper = function(rate, pmt, pv, fv, type) {
		var retval = 0;
		if (rate == 0) {
			retval = -1 * (fv + pv) / pmt;
		} else {
			var r1 = rate + 1;
			var ryr = (type ? r1 : 1) * pmt / rate;
			var a1 = ((ryr - fv) < 0) ? Math.log(fv - ryr) : Math.log(ryr - fv);
			var a2 = ((ryr - fv) < 0) ? Math.log(-pv - ryr) : Math.log(pv + ryr);
			var a3 = Math.log(r1);
			retval = (a1 - a2) / a3;
		}
		return retval;
	}
	
	this.rate = function(nper, pmt, pv, fv) {
		// not implemented
		return 0;
	}
	
	this.effect = function(nominalRate, npery) {
		// provides the fuction of the EFFECT function in excel
		var effect = Math.pow((1 + (nominalRate / npery)), npery) - 1;
		return effect;
	}
}

