(function( $ ) {
	if (Number.prototype.jSliderNice) {
		var stdNice = Number.prototype.jSliderNice;
		Number.prototype.jSliderNice = function () {
			var value = stdNice.apply(this, arguments);
			value = value.toString().replace(/,/gi, ".");
			value = value.toString().replace(/ /gi, ",");
			return value;
		}
	}
	$.fn.loanSlider = function( action, opt_value ) {
		var result = $.fn.slider.apply(this, arguments);
		$.each(result, function(){
			var slider = $(this).data("jslider");
			slider.redrawLimits = function() {};
			for( var i=0; i < 2; i++ )
				slider.o.limits[i].fadeIn("fast");
			var pointer = slider.o.pointers[0];
			var originalSet = pointer._set;
			pointer._set = function ( prc, opt_origin ) {
				var oldValue = pointer.value.origin;
				originalSet.apply(pointer, arguments);
				if (slider.onChange)
					slider.onChange(oldValue, pointer.value.origin);
			}
			slider.domNode.click(function(evt) { 
				pointer._parent = {
					offset: slider.domNode.offset(),
					width: slider.domNode.width()
				};
				var coords = pointer._getPageCoords( evt );
				pointer._set( pointer.calc( coords.x ) );
			});
		});
		return result;
	};
})( jQuery );

(function($) {
    var series = [];
    var derivativeSeries = [];
    var dateDifference = function(a, b) {
        return (a.getTime() - a.getTimezoneOffset() * 60000 - b.getTime() + b.getTimezoneOffset() * 60000) / 1000 / 3600 / 24;
    };

    $.loanCalculator = function(settings) {
        return new LoanCalculator(settings);
    }

    this.LoanCalculator = function() {
        return this.init.apply(this, arguments);
    };

    LoanCalculator.prototype = {
        loanTermWeeks: 78,
        interestTable: [
			{ amount: 550, rate: 0.1285 },
			{ amount: 600, rate: 0.1251 },
			{ amount: 650, rate: 0.1216 },
			{ amount: 700, rate: 0.1188 },
			{ amount: 750, rate: 0.1163 },
			{ amount: 800, rate: 0.1141 },
			{ amount: 850, rate: 0.1123 },
			{ amount: 900, rate: 0.1107 },
			{ amount: 950, rate: 0.1092 },
			{ amount: 1000, rate: 0.1079 },
			{ amount: 1100, rate: 0.1068 },
			{ amount: 1200, rate: 0.1047 },
			{ amount: 1300, rate: 0.1031 },
			{ amount: 1400, rate: 0.1016 },
			{ amount: 1500, rate: 0.1004 },
			{ amount: Number.MAX_VALUE, rate: 0.0993 }
		],
        init: function(settings) {
            var $this = this;
            var amountSlider = $(settings.amount);
            var periodSlider = $(settings.period);
            if (amountSlider) {
                this.amountSlider = amountSlider.data("jslider");
                this.amountSlider.o.limits[0].html('<ins>' + settings.amountLowerDimension + '</ins><span>' + this.amountSlider.settings.from + '</span>' + settings.amountLowerDimension);
                this.amountSlider.onChange = function() { $this.updateIndicators() };
            }
            if (periodSlider) {
                var pSlider = this.periodSlider = periodSlider.data("jslider");
                this.periodSlider.o.limits[0].html('<ins>' + settings.periodLowerDimension + '</ins><span>' + this.periodSlider.settings.from + '</span>' + settings.periodLowerDimension);
                this.periodSlider.onChange = function() {
                    var period = pSlider.o.pointers[0].value.origin;
                    var dimension = pSlider.o.labels[0].o.find("b");
                    if (period == pSlider.settings.from) {
                        dimension.replaceWith(settings.periodLowerDimension);
                        pSlider.lowerDimension = true;
                    }
                    else if (pSlider.lowerDimension) {
                        dimension.replaceWith(pSlider.settings.dimension);
                        pSlider.lowerDimension = false;
                    }
                    $this.updateIndicators();
                };
            }
            this.sumIndicator = $(settings.sum);
            this.interestIndicator = $(settings.interest);
            this.repayableIndicator = $(settings.totalRepayable);
            this.periodSlider.onChange();
        },
        updateIndicators: function() {
            var amount = this.amountSlider.o.pointers[0].value.origin;
            var period = this.periodSlider.o.pointers[0].value.origin;
            var interestRate = 0;
            for (var index = 0; index < this.interestTable.length; index++) {
                interestRate = this.interestTable[index].rate;
                if (amount < this.interestTable[index].amount)
                    break;
            }
            var weeklyAmount = Math.round(100 * (amount / this.loanTermWeeks + amount * interestRate * 12 / 52)) / 100;
            var totalPayable = this.getTotalPayable(period, amount, weeklyAmount);

            this.sumIndicator.html(this.amountSlider.nice(amount));
            this.interestIndicator.html(this.amountSlider.nice(totalPayable - amount));
            this.repayableIndicator.html(this.amountSlider.nice(totalPayable));
        },
        getTotalPayable: function(period, amount, weeklyAmount) {
            var date = new Date();  //(2010, 08, 07, 0, 0, 0);
            date = new Date(date.getFullYear(), date.getMonth(), date.getDate());
            var lastDate = new Date(date.getTime() + period * 7 * 24 * 3600 * 1000);
            lastDate.setHours(lastDate.getHours() + lastDate.getTimezoneOffset() / 60 - date.getTimezoneOffset() / 60);
            var deferredDate = new Date(lastDate.getFullYear(), lastDate.getMonth() + 1, lastDate.getDate());
            var daysSinceLoanStartedExclDeferral = dateDifference(lastDate, date);
            var daysSinceLoanStarted = dateDifference(deferredDate, date);

            var numberPaymentsUpToDateExclDeferral = Math.floor(daysSinceLoanStartedExclDeferral / 7.0);
            var numberPaymentsUpToDate = Math.floor(daysSinceLoanStarted / 7.0);

            var annualRate = this.getAPR(amount, weeklyAmount) + 1;

            var discountedCashFlowOfPaymentsMade = 0;
            var principalAmountAndInterest = 0;

            var paymentDate = new Date(date);

            if (numberPaymentsUpToDate > this.loanTermWeeks)
                numberPaymentsUpToDate = this.loanTermWeeks;

            for (var i = 0; i < numberPaymentsUpToDate; i++) {
                paymentDate.setDate(paymentDate.getDate() + 7);
                var pmt = this.applyInterest(weeklyAmount, paymentDate, deferredDate, annualRate);
                discountedCashFlowOfPaymentsMade += pmt;
            }
            principalAmountAndInterest = this.applyInterest(amount, date, deferredDate, annualRate);

            var balanceAtTimeOfNoticeExclDeferral = weeklyAmount * (this.loanTermWeeks - numberPaymentsUpToDateExclDeferral);
            var balanceAtTimeOfNotice = weeklyAmount * (this.loanTermWeeks - numberPaymentsUpToDate);

            var rebate = balanceAtTimeOfNotice - principalAmountAndInterest + discountedCashFlowOfPaymentsMade;
            if (rebate < 0)
                rebate = 0;
            var esFigure = balanceAtTimeOfNoticeExclDeferral - rebate;
            return esFigure + numberPaymentsUpToDateExclDeferral * weeklyAmount;
        },
        applyInterest: function(amount, date, lastDate, annualRate) {
            var getPeriod = function(date, lastDate) {
                // check full months
                if (date.getDate() == lastDate.getDate()) {
                    var months = lastDate.getMonth() + lastDate.getFullYear() * 12 - date.getMonth() - date.getFullYear() * 12;
                    return months / 12.00;
                }

                // check full weeks
                var days = dateDifference(lastDate, date);
                if (days % 7 == 0)
                    return days / 7 / 52;

                // if not, find combination years + days
                var years = 0;
                var tmpDate = new Date(date);
                while (true) {
                    tmpDate.setFullYear(tmpDate.getFullYear() + 1);
                    if (tmpDate > lastDate) {
                        tmpDate.setFullYear(tmpDate.getFullYear() - 1);
                        break;
                    }
                    years++;
                }
                return years + dateDifference(lastDate, tmpDate) / 365.25;
            };

            return Math.round(100 * amount * Math.pow(annualRate, getPeriod(date, lastDate))) / 100;
        },
        getAPR: function(amount, weeklyAmount) {
            var a = weeklyAmount / (amount + weeklyAmount);
            var b = amount / (amount + weeklyAmount);
            var discountFactor = a;
            var prevDiscountFactor = 0;
            var precision = 0.0000001;
            for (var i = 0; i < 20 && Math.abs(prevDiscountFactor - discountFactor) > precision; i++) {
                prevDiscountFactor = discountFactor;
                discountFactor -= (a * Math.pow(discountFactor, this.loanTermWeeks + 1) - discountFactor + b) /
													(a * (this.loanTermWeeks + 1) * Math.pow(discountFactor, this.loanTermWeeks) - 1);
            }
            return Math.round(1000 * (Math.pow(discountFactor, -52) - 1)) / 1000;
        }
    }

})(jQuery);
