	var MAX_DOLLAR_AMOUNT = 10000000000;
	$(document).ready(function(){
		init();
		pagepeel();
		unmaskBody();
		extra_init();
		
	});
	function pagepeel(){
		$("#pageflip").hover(function() { //On hover...
	$("#pageflip img , .msg_block").stop()
		.animate({ //Animate and expand the image and the msg_block (Width + height)
			width: '307px',
			height: '319px'
		}, 500);
	} , function() {
	$("#pageflip img").stop() //On hover out, go back to original size 50x52
		.animate({
			width: '50px',
			height: '52px'
		}, 220);
	$(".msg_block").stop() //On hover out, go back to original size 50x50
		.animate({
			width: '50px',
			height: '50px'
		}, 200, false,
		function(){
			$(".msg_block").hide();
		}
		); //Note this one retracts a bit faster (to prevent glitching in IE)
		
		
});
	}
	function unmaskBody(){
		$('#body_mask').fadeOut('show');
	}
	function extra_init(){
		donate_init();
		socialbm_init();
	}
	function socialbm_init(){
		$('#socialbm_sc').attr('src','http://s7.addthis.com/js/250/addthis_widget.js?pub=xa-4a40797b009355d0');
		$('#socialbm_im').attr('src','images/sm-bookmark-en.gif');
		$('#socialbm_div').show();
	}
	function donate_init(){
		$('#donate_now').attr('src',"images/btn_donate_SM.gif");
		$('#paypal_px').attr('src',"images/pixel.gif");
		$('#donate').show();
	}
	function toJSTimeStamp(date){
		var d=new Date();
		d.setYear(date.year);
		d.setMonth(date.month-1);
		d.setDate(date.date||1);
		d.setHours(0);
		d.setMinutes(0);
		d.setSeconds(0);
		d.setMilliseconds(0);
		return d.getTime();
		
	}
	function getMonthlyData(dataMonthly,field){
		var res=[];
		for(var i =0;i<dataMonthly.length;i++){
				res.push([toJSTimeStamp({
						year: dataMonthly[i].year,
						month:dataMonthly[i].month
					}
					),dataMonthly[i][field]]);
		}
		return res;
	}
	function getMonthlyInterestData(data){
		return getMonthlyData(data,'mInterest');
	}
	function getMonthlyTotalPaymentData(dataMonthly){
		var res=[];		
		for(var i =0;i<dataMonthly.length;i++){
				res.push([toJSTimeStamp({
						year: dataMonthly[i].year,
						month:dataMonthly[i].month
					}
					),dataMonthly[i].mInterest+dataMonthly[i].mPrincipal]);
		}
		return res;
	}
	function refiplot(param){
		$('#refi_chart_container').show();
			var res=param||reficalc_light();
			 var curLoan =res.curLoanInfo, refi =res.refiInfo, refi2 = res.refi2Info, curExtraLoan=res.curExtraLoan;
			 var maxD =maxDate(curLoan.payoffDate, refi.payoffDate, refi2?refi2.newPayoffDate:false, curExtraLoan?curExtraLoan.newPayoffDate:false);
			 var curLoanMPayment=[], curLoanMInterest=[], refiMPayment=[], refiMInterest=[];
			 
				curLoanMPayment.push([toJSTimeStamp(curLoan.startDate),curLoan.monthlyPayment]);	
				curLoanMPayment.push([toJSTimeStamp({
					year:curLoan.data.dataMonthly[curLoan.data.dataMonthly.length-1].year,
					month: curLoan.data.dataMonthly[curLoan.data.dataMonthly.length-1].month
				}),
					curLoan.monthlyPayment]);
		
			 	refiMPayment=getMonthlyTotalPaymentData(refi.data.dataMonthly);
			 
			 	curLoanMInterest = getMonthlyInterestData(curLoan.data.dataMonthly);
				refiMInterest= getMonthlyInterestData(refi.data.dataMonthly);

				var add=[];
				if(refi2){
					add.push({
						data:getMonthlyTotalPaymentData(refi2.data2.dataMonthly),
						label:'Refinanced Principal Payment(plus extra monthly payment)',
						group:"Refinanced Loan Data(plus extra monthly payment)"
					});
					add.push({
						data:getMonthlyInterestData(refi2.data2.dataMonthly),
						label:'Refinanced Interest Payment(plus extra monthly payment)',
						group:"Refinanced Loan Data(plus extra monthly payment)"
					});					
				}
				else if(curExtraLoan){
					add.push({
						data:getMonthlyTotalPaymentData(curExtraLoan.data2.dataMonthly),
						label:'Original Principal Payment(plus extra monthly payment)',
						group:"Original Loan Data(plus extra monthly payment)"
					});
					add.push({
						data:getMonthlyInterestData(curExtraLoan.data2.dataMonthly),
						label:'Orignal Principal Payment(plus extra monthly payment)',
						group:"Original Loan Data(plus extra monthly payment)"
					});						
				}
				var plotData=[{
					data:curLoanMPayment,
					label:'Original Principal Payment'	,
					group:'Original Loan Data'
				},{
					data: curLoanMInterest,
					label:'Original Interest Payment',
					group:'Original Loan Data'
				},
				{
					data:refiMPayment,
					label:'Refinanced Principal Payment',
					group:'Refinanced Loan Data'
				},
				{
					data:refiMInterest,
					label:'Refinanced Interest Payment',
					group:'Refinanced Loan Data'	
				}
				];
			
				var colors={
					'Original Principal Payment':"#edc240", 
					'Original Interest Payment':"#afd8f8",
					'Refinanced Principal Payment':"#cb4b4b", 
					'Refinanced Interest Payment':"#4da74d"
					
				};
				if(add.length>0){
					plotData = plotData.concat(add);
					colors[add[0].label]="#9440ed";
					colors[add[1].label]="#Bd9b33";
				}
				
				plotPaymentChart(plotData,
				{
					startDate:curLoan.startDate,
					maxDate:maxD,
					container:'refi_chart',
					containerWindow:refiChartWin,
					height:'300px',
					chartControl:'refi_chart_control',
					show_groups:{
						'Original Loan Data':true,
						'Refinanced Loan Data':true
					},
					colors:colors
				}	
				);
				
	}
	function mxplot(param){
		$('#test_plot_container').show();
			var res=param||mxcalc_light();
			// console.log(res);
			 var mPaymentData=[], dataMonthly = res.data.dataMonthly,  newMPaymentData=[], extraDataMonthly=res.data2.dataMonthly;
			 
				mPaymentData.push([toJSTimeStamp(res.startDate),res.monthlyPayment]);	
				mPaymentData.push([toJSTimeStamp({
					year:dataMonthly[dataMonthly.length-1].year,
					month: dataMonthly[dataMonthly.length-1].month
				}),
					res.monthlyPayment]);
		
			 newMPaymentData=getMonthlyTotalPaymentData(extraDataMonthly);
			 
			 var mInterestData1 = getMonthlyInterestData(dataMonthly);
			 var mInterestData2 = getMonthlyInterestData(extraDataMonthly);
	
			var plot_data=[{
					data:mPaymentData,
					label:'Principal Payment',
					group:'Original'
				},{
					data: mInterestData1,
					label:'Interest Payment',
					group:'Original'
				},
				{
					data:newMPaymentData,
					label:'Principal Payment(after extra payment)',
					group:'With Extra Payment'
				},
				{
					data:mInterestData2,
					label:'Interest Payment(after extra payment)'	,
					group:'With Extra Payment'
				}
				];
				plotPaymentChart(plot_data,
				{
					startDate:res.startDate,
					container:'test_plot',
					containerWindow: mcalcPlotWin,
					show_groups:{
						'Original':true,
						'With Extra Payment':true
					}
				}	
				);	
				
	}
	function mplot(param){
		$('#test_plot_container').show();
				var res=param||mcalc_light();
				res=cp_amortize(res);
				var dataMonthly = res.data.dataMonthly;
				var mInterestData = getMonthlyInterestData(dataMonthly), mPaymentData=[];
				
				
		
				mPaymentData.push([toJSTimeStamp(res.startDate),res.monthlyPayment]);
				mPaymentData.push([toJSTimeStamp({
					year:dataMonthly[dataMonthly.length-1].year,
					month: dataMonthly[dataMonthly.length-1].month
				}),
				res.monthlyPayment]);
				
				//console.log(res);
				//console.log(data);
				plotPaymentChart([{
					data:mPaymentData,
					label:'Principal Payment'
				},{
					data: mInterestData,
					label:"Interest Payment"
				}],
				{
					startDate:res.startDate,
					container:'test_plot',
					containerWindow:mcalcPlotWin
				}	
				);		
	}	

	var mcalcPlotWin;
	var extraPayWin;
	var refiChartWin;
	function plot_init(){
		
		mcalcPlotWin=$.swindow('test_plot_container',{
			expandCtrl:'mplot_head',
			closeCtrl:'mplot_close'
		}).hide();
	
		extraPayWin=$.swindow('mxform',{
			expandCtrl:'extrapay_head'
		});
		refiChartWin=$.swindow('refi_chart_container',{
			expandCtrl:'refichart_expand',
			closeCtrl:'refichart_close'
		}).hide();
	}
	function plotPaymentChart(data, options){
	
			var container = getEl(options.container), height = options.height||'300px';
			var chart_control = (options.chartControl? getEl(options.chartControl) : false);
			var show_groups=options.show_groups||{};
				container.css('height',height);
				container.show();
				
				var plot_data=[], colors=[];
				for(var i =0;i<data.length;i++){
					
					if(isString(data[i].group) && !show_groups[data[i].group])continue;
					plot_data.push(
						$.extend({lines:{
							show:false,
							fill:true
						}},data[i])
					);
					if(options.colors && options.colors[data[i].label])colors.push(options.colors[data[i].label]);
				}
				if (options.containerWindow) {
					options.containerWindow.expand();
				}
				if(colors.length<=0)colors=false;
				$.plot(container, plot_data,
					
					{
						colors: colors||["#edc240", "#afd8f8", "#cb4b4b", "#4da74d", "#9440ed"],
						xaxis: $.extend((options.maxDate?{max:toJSTimeStamp(options.maxDate)}:{}),
						{
							mode: "time",
							minTickSize: [1, "month"],
							min: toJSTimeStamp(options.startDate)
							
						}),
						yaxis:{
							tickFormatter:function(x){
								return '$'+x;
							}
						},
						legend:{
							show:true
						}
					}
				);
			
			//setup chart control
	
			if(chart_control){
				chart_control.empty();
				chart_control.css('border','1px solid green');

				var visited={};
				for(var i =0;i<data.length;i++){
					if(visited[data[i].group])continue;
					visited[data[i].group]=true;
					var ck=$('<input type="checkbox" value="'+data[i].group+'" ' + (show_groups[data[i].group]?'checked':'' )+ '/>');
					ck.click(function(){
						var chks=chart_control.find('input:checked');
	
						var show_groups={};
						for(var j=0;j<chks.length;j++){
							show_groups[chks[j].value] = true;
						}
						plotPaymentChart(data,$.extend(options, {show_groups:show_groups}));
					});
					chart_control.append(ck).append(data[i].group);
				}
				chart_control.show();
				
			}
				
	}
	function enable_all_forms(){
		$('form').each(function(index, el){
			enable_form(el, true);
		});
	}
	
	function check_elements_val(els, val, skips){
		skips = skips||[];
		for(var i =0;i<els.length;i++){
			var el = $(els[i]), type =el.attr('type');

			if(skips[el.attr('id')])continue;
			if (type == 'checkbox' || type=='radio') {
				if (el.attr('checked')) {
					return false;
				}
			}
			else if(el.val()!=val)return false;
		}	
		return true;
	}
	function fill_elements(elements, values){
		elements.each(function(index, el){
			el = $(el);
			var id = isString(el)?el:(el.attr('id')?el.attr('id'):el.attr('name'));
			
			if (typeof values[id] !== 'undefined') {
				if (el.attr('type') == 'checkbox' || el.attr('type') == 'radio') {
					el.attr('checked', values[id]);
				}
				else {
					el.val(values[id]);
					
				}
			}
		});
	}
	function set_form_default_vals(options){
		if(!options)return;
		
		$(options.forms).each(function(index, el){
			var form = el.name, values=el.values, skips = el.skips || {};;
			
			var inputs=$('#'+form).find('input[type!=submit],select');
			if(check_elements_val(inputs,'',skips)){
			
				fill_elements(inputs, values);
			}
			
			
		});
		
		
		/*
		var stdate = $('#stdate'), cur_loan_month = $('#cur_loan_month'), cur_loan_year = $('#cur_loan_year');
		$('#stdate').datepicker();
		var curDate = new Date();
		if (stdate.val() == '') {
		
			stdate.datepicker('setDate', curDate);
		}
		
		$('#cur_loan_now').click(function(){
		
			if ($(this).is(":checked")) {
				var curDate = new Date();
				$('#cur_loan_month').val(curDate.getMonth() + 1);
				$('#cur_loan_year').val(curDate.getFullYear());
			}
		});		
		if(cur_loan_month.val() == '' && cur_loan_year.val()==''){
			$('#cur_loan_now').attr('checked',true);
			$('#cur_loan_month').val(curDate.getMonth() + 1);
			$('#cur_loan_year').val(curDate.getFullYear());
			
		}
		*/
	}
	
	function init(){
		
		$('#tb').tabs();
		$('#amortize_tb').tabs().hide();
		$('#original_am').tabs();
		$('#mod_am').tabs();
		$('#refi_amortize_tb').tabs().hide();
		$('#refi_original_am').tabs();
		$('#refi_am').tabs();
		$('#refi2_am').tabs();
		
		plot_init();
		enable_all_forms();
		var cur_date = new Date(), cur_month = cur_date.getMonth()+1, cur_year = cur_date.getFullYear(); 
		set_form_default_vals({
			forms:[{
					name:'mform',
					values:{
						loanamt:300000,
						rate: 4.5,
						years: 30,
						stdate:dateFormat(cur_date),
						/*showam:false,*/
						showam:true,
						mcalc_showplot:true
					}
				
				},
				{
					name:'mxform',
					values:{
						/*mxcal_showam:false,*/
						mxcal_showam:true,
						mxcalc_showplot:true
					},
					skips:{
						extra_monthly_start_month:true,
						extra_monthly_start_year:true,
						extra_yearly_repeat_month:true,
						extra_yearly_start_year:true,
						extra_onetime_month:true,
						extra_onetime_year:true
					}
				},
				{
					name:'refiform',
					values : {
						cur_loan_amt:250000,
						cur_monthly_payment: 1700,
						cur_rate:5.5,
						refi_rate:4.5,
						refi_years: 30,
						cur_loan_month:cur_month,
						cur_loan_year: cur_year,
						cur_loan_now:true,
						refi_closing:true,
						/*refi_showam:false,*/
						refi_showam:true,
						refi_showplot:true
					},
					skips:{
						total_closing_cost_unit:true
					}
				}	
				]
		});
		
		
		
		$('#mform').validate({
			rules:{
				loanamt: {
					required:true,
					number:true,
					min:0
				},
				rate: {
					required: true,
					number: true,
					min: 0
				},
				stdate:{
					required: true,
					date:true
					
				},
				years:{
					digits:true
					
				},
				months:{
					digits:true
				}/*,
				errorPlacement: function(error, element) {
     				if (element.attr("name") == "fname" 
                 	|| element.attr("name") == "lname" )
       				error.insertAfter("#lastname");
     				else
       				error.insertAfter(element);
   				}
				*/
			},
			groups:{
				loan_term_group:'years months'
			}

		});
		
		$('#mxform').validate({
			rules: {
				extra_monthly: {
					number: true,
					min: 0
				},
				extra_yearly: {
					number: true,
					min: 0
				},
				extra_onetime: {
					number: true,
					min: 0
				}								
			},
			groups:{
				extra_pay_group:'extra_monthly extra_yearly extra_onetime'
			}			
		});
				
		$('#mform').submit(function(){
			try {
				if ($(this).valid()) {
					c_mcalc();
				}
			}catch(e){
				
				alert(e);
			}
			enable_forms(['m_form', 'mx_form'], true);
			return false;
		});
		$('#mxform').submit(function(){
			//try {
				if ($('#mform').valid() && $(this).valid()) {
					c_mxcalc();
				}
			
			/*}catch(e){
				
				alert(e);
			}*/
			enable_forms(['m_form', 'mx_form'], true);;
			return false;
		});		
		
	
		refi_init();
		
		
		
	}
	function refi_init(){
		$('#refiform').validate({
			rules: {
				cur_loan_amt: {
					required:true,
					number: true,
					min: 0
				},
				cur_monthly_payment: {
					required:true,
					number: true,
					min: 0
				},
				cur_rate: {
					required:true,
					number: true,
					min: 0,
					max:100
				},	
				refi_rate: {
					required:true,
					number: true,
					min: 0,
					max:100
				},	
				cur_loan_month:{
					required:true
				},
				cur_loan_year:{
					required:true
				},
				refi_years:{
					digits:true,
					min:0
				},
				refi_months:{
					digits:true,
					min:0
				},
				total_closing_cost:{
					number:true,
					/*
					max:{
						depends:function(el){
							var unit = $('#total_closing_cost_unit').val(); //perf
							console.log(unit);
							if(unit=='percentage'){
								return 100;
							}
							return MAX_DOLLAR_AMOUNT;
						},
						
					},*/
					min:0
				}	
						
			},
			groups:{
					cur_loan_date:'cur_loan_month cur_loan_year',
					refi_loan_term:'refi_years refi_months'
			}		
		});
		$('#refiform').submit(function(){
			try {
				
				if ($(this).valid()) {
				
					c_reficalc();
				}
			}catch(e){
				enable_forms(['refiform'], true);
				alert(e);
				
			}
			return false;
		});		
	}

	
	
	jQuery.validator.addMethod('loan_term_group', function(val, el) {
		return validate_required_group(val,el, 'loan_term_group');
	}, 'Please enter a positive integer for the year and/or month of the loan term.');
	jQuery.validator.addMethod('extra_pay_group', function(val, el) {
		return validate_required_group(val,el, 'extra_pay_group');
	}, 'Please enter an extra payment amount.');
	jQuery.validator.addMethod('refi_loan_term', function(val, el) {
		return validate_required_group(val,el, 'refi_loan_term');
	}, 'Please enter a positive integer for the year and/or month of the new loan term.');
			
	function validate_required_group(val, el, group_class){
		var $module = $(el).parents('.required_group_container');
		var gp=$module.find('.'+group_class+':filled');
		if(!gp)return gp;
		var ok = false;
		for(var i =0;i<gp.length;i++){
			
			if($(gp[i]).val()>0)return true;
		}
		return ok;
	}

	/*************************input handlers/parsers***************************/
	
	function parseRefiCalcCoreInput(){
		var p = Number($('#cur_loan_amt').val()), r = Number($('#cur_rate').val()), toRefiCost = $('#refi_closing').attr('checked'), refiCost = Number($('#total_closing_cost').val()), refiCostUnit = $('#total_closing_cost_unit').val(); 		
		cur_monthly = Number($('#cur_monthly_payment').val()),
		refi_r=Number($('#refi_rate').val()),
		refi_years = $('#refi_years').val(), refi_months=$('#refi_months').val(), cur_loan_year=$('#cur_loan_year').val(), cur_loan_month=$('#cur_loan_month').val();
		
		r/=1200;
		refi_r/=1200;
		
		refiCost = (refiCostUnit=='percentage' ? p*(refiCost/100): refiCost); 

		var refi_months = Number(isInteger(refi_years)?refi_years:0) * 12 + Number(isInteger(refi_months)?refi_months:0);
		var curLoanDate={
			year: Number(cur_loan_year),
			month: Number(cur_loan_month)
		}	
		var res = {
			curLoanAmount:p,
			curInterestRate:r,
			curMonthlyPayment: cur_monthly,
			refiInterestRate:refi_r,
			refiMonths:refi_months,
			curLoanDate:curLoanDate,
			refiCost : refiCost,
			toRefiCost: toRefiCost
		};
		
	
		return res;
	}	
	function parseMCalcCoreInput(){
		var p = Number($('#loanamt').val()), r = Number($('#rate').val()), yrs = $('#years').val(), mths=$('#months').val(), stdate=$('#stdate').val();
		
		r= r/1200;
		stdate = parseDate(stdate);
		var months = Number(isInteger(yrs)?yrs:0) * 12 + Number(isInteger(mths)?mths:0);
		
		var res = {
			principal:p,
			interestRate:r,
			months:months,
			startDate:stdate
		};
		return res;
	}
	function parseMCalcExtraInput(){
		var extraMonthlyStartDate={
			month: Number($('#extra_monthly_start_month').val()),
			year: Number($('#extra_monthly_start_year').val())
		};
		var extraYearlyDate={
			month: Number($('#extra_yearly_repeat_month').val()),
			year: Number($('#extra_yearly_start_year').val())
		};
		var extraOnetimeDate={
			month: Number($('#extra_onetime_month').val()),
			year: Number($('#extra_onetime_year').val())
		};					
		var res= {
			extraMonthly: $('#extra_monthly').val(),
			extraYearly: $('#extra_yearly').val(),
			extraOnetime: $('#extra_onetime').val(),
			extraMonthlyStartDate:extraMonthlyStartDate	,
			extraYearlyDate: extraYearlyDate,
			extraOnetimeDate:extraOnetimeDate
			
		};
		for(var i in res){
			if(isStringNumber(res[i])) res[i] = Number(res[i]);
				
		}
		

		return res;
	}	
	/************************End of input handlers/parsers*********************/
	
	/*****************Form/action handlers***************/
	function c_reficalc(){
		enable_forms(['refiform'], false);
		var reficalc_light_res=reficalc_light();;
		
	
		mask('refi_amortize_tb');		
		$('#refiform').schedule(100,function(){
			if($('#refi_showplot').attr('checked'))refiplot(reficalc_light_res);
			if ($('#refi_showam').attr('checked')) {
				try {
					mask('refi_amortize_tb');
					var t = new Date().getTime();
			
				
					reficalc_intensive(reficalc_light_res);
					t = new Date().getTime() - t;
				//console.log("took "+t/1000+" secs");
				}catch(ex){
					alert("Error during showing refinance amortization: "+ex);
				}
			}
			$(this).dequeue();
			unmask('refi_amortize_tb');
			enable_forms($('#refiform'), true);
			
		});
		
		
		
	}
	function reficalc_light(){
		var coreinput=parseRefiCalcCoreInput();
	
		var reficalc_res=cp_reficalc(coreinput);
		
		reficalc_set_results(reficalc_res);
		
		return $.extend({}, reficalc_res);			
	}
	function reficalc_intensive(params){
		setRefiCalcAmortize(params);
	}
	function toggle_innerHTML(parent, key, html){
		parent.html(html);
	}
	function setRefiCalcAmortize(parameters,render_options){	
		var render_options=$.extend({
			container:'refi_amortize_tb',
			cols: 8,
			orientation:'vertical'
		},render_options || {});
		var res = parameters;
		
		var curLoanInfo = res.curLoanInfo, refiInfo = res.refiInfo, refi2Info = res.refi2Info, curExtraLoanInfo = res.curExtraLoanInfo;
		var tb_header = '$'+curLoanInfo.principal +' borrowed on '+dateFormat(curLoanInfo.startDate)+' with a monthly payment of '+fm(curLoanInfo.monthlyPayment);
	
		renderAmortizeTable(curLoanInfo, curLoanInfo.data.dataMonthly, $.extend({
			table_to_show:'refi_original_am',
			sub_table_to_show:'refi_original_am_monthly',
			table_header: tb_header,
			type:'monthly'
		},render_options));
		renderAmortizeTable(curLoanInfo, curLoanInfo.data.dataYearly, $.extend({
			table_to_show:'refi_original_am',
			sub_table_to_show:'refi_original_am_yearly',
			table_header: tb_header,
			type:'yearly'
		},render_options));
		
		if(isObject(refiInfo)){			
			var tb2_header = '$'+refiInfo.principal +' refinanced on '+dateFormat(refiInfo.startDate)+' with a monthly payment of '+fm(refiInfo.monthlyPayment);
			renderAmortizeTable(refiInfo, refiInfo.data.dataMonthly, $.extend({
				table_to_show:'refi_am',
				sub_table_to_show:'refi_am_monthly',
				table_header: tb2_header,
				type:'monthly'
			},render_options));
			renderAmortizeTable(refiInfo, refiInfo.data.dataYearly, $.extend({
				table_to_show:'refi_am',
				sub_table_to_show:'refi_am_yearly',
				table_header: tb2_header,
				type:'yearly'
			},render_options));			
		}
		if(isObject(refi2Info)){	
		$('#refi2_tab_title').text('Refinanced with same monthly payment');
			var tb3_header = '$'+refi2Info.principal +' refinanced on '+dateFormat(refi2Info.startDate)+' with a monthly payment of '+fm(refi2Info.monthlyPayment);
			var plus = ' plus ' + (isPositiveNumber(refi2Info.extraMonthly) ? 'an extra monthly ' + fm(refi2Info.extraMonthly) : '');
			renderAmortizeTable(refi2Info, refi2Info.data2.dataMonthly, $.extend({
				table_to_show:'refi2_am',
				sub_table_to_show:'refi2_am_monthly',
				table_header: tb3_header,
				table_notes:plus,
				type:'monthly'
			},render_options));
			renderAmortizeTable(refi2Info, refi2Info.data2.dataYearly, $.extend({
				table_to_show:'refi2_am',
				sub_table_to_show:'refi2_am_yearly',
				table_header: tb3_header,
				table_notes:plus,
				type:'yearly'
			},render_options));			
		}	
		else if (isObject(curExtraLoanInfo)){
			$('#refi2_tab_title').text('Original with extra monthly payment');
			var tb3_header = '$'+curExtraLoanInfo.principal +' borrowed on '+dateFormat(curExtraLoanInfo.startDate)+' with a monthly payment of '+fm(curExtraLoanInfo.monthlyPayment);
			var plus = ' plus ' + (isPositiveNumber(curExtraLoanInfo.extraMonthly) ? 'an extra monthly ' + fm(curExtraLoanInfo.extraMonthly) : '');
			renderAmortizeTable(curExtraLoanInfo, curExtraLoanInfo.data2.dataMonthly, $.extend({
				table_to_show:'refi2_am',
				sub_table_to_show:'refi2_am_monthly',
				table_header: tb3_header,
				table_notes:plus,
				type:'monthly'
			},render_options));
			renderAmortizeTable(curExtraLoanInfo, curExtraLoanInfo.data2.dataYearly, $.extend({
				table_to_show:'refi2_am',
				sub_table_to_show:'refi2_am_yearly',
				table_header: tb3_header,
				table_notes:plus,
				type:'yearly'
			},render_options));			
		}
	}	
	function refi_clear_results(){
		$('#refi_out_table td.output').val('');
	}
	function reficalc_set_results(res){
		refi_clear_results();
		
		if(isObject(res.curLoanInfo)){
			setStdMoney($('#res_cur_monthly_payment'), res.curLoanInfo.monthlyPayment);
			setText($('#cur_payment_red'), "N/A");
			setStdMoney($('#cur_total_payment'), res.curLoanInfo.principal);
			setStdMoney($('#cur_total_interest'), res.curLoanInfo.totalInterest);
			setText($('#cur_interest_red'), "N/A");
			setText($('#cur_time_red'), "N/A");
			setStdDate($('#cur_payoff_date'),res.curLoanInfo.payoffDate);
			
		}
		if(isObject(res.refiInfo)){
			setStdMoney($('#refi_monthly_payment'), res.refiInfo.monthlyPayment);
			setStdMoney($('#refi_payment_red'), -res.refiInfo.monthlyPaymentRed, {show_sign:true});
			setStdMoney($('#refi_total_payment'), res.refiInfo.principal);
			setStdMoney($('#refi_total_interest'), res.refiInfo.totalInterest);
			setStdMoney($('#refi_interest_saving'), -res.refiInfo.totalInterestSaving,{show_sign:true});
			setStdDate($('#refi_payoff_date'),res.refiInfo.payoffDate);
			setDateFormat1($('#refi_time_saving'),-res.refiInfo.timeReduction,{show_sign:true});
		}	
		if(isObject(res.refi2Info)){
			$('.refi2_out').show();
			 var totalInterestSaving = res.curLoanInfo.totalInterest - res.refi2Info.newTotalInterest;
			 var timeReduction = res.curLoanInfo.data.dataMonthly.length - res.refi2Info.data2.dataMonthly.length;
			
				setStdMoney($('#refi2_monthly_payment'), res.curLoanInfo.monthlyPayment);
				setStdMoney($('#refi2_payment_red'), 0);
				setStdMoney($('#refi2_total_payment'), res.refi2Info.principal);
				setStdMoney($('#refi2_total_interest'), res.refi2Info.newTotalInterest);
				setStdDate($('#refi2_payoff_date'),res.refi2Info.newPayoffDate);
			
				setStdMoney($('#refi2_interest_saving'), -totalInterestSaving, {show_sign:true});
				setDateFormat1($('#refi2_time_saving'),-timeReduction,{
					show_sign: true
				});
		}
		else{
			$('.refi2_out').hide();
		}	
			
		if(isObject(res.curExtraLoanInfo)){
			$('.refi_cur_extra_out').show();
				var totalInterestSaving = res.curLoanInfo.totalInterest - res.curExtraLoanInfo.newTotalInterest;
				var timeReduction = res.curLoanInfo.data.dataMonthly.length - res.curExtraLoanInfo.data2.dataMonthly.length;
			
				setStdMoney($('#res_cur_extra_monthly_payment'), res.curExtraLoanInfo.monthlyPayment + res.curExtraLoanInfo.extraMonthly);
				setStdMoney($('#cur_extra_payment_red'), res.curExtraLoanInfo.extraMonthly,{show_sign:true});
				setStdMoney($('#cur_extra_total_payment'), res.curExtraLoanInfo.principal);
				setStdMoney($('#cur_extra_total_interest'), res.curExtraLoanInfo.newTotalInterest);
				setStdDate($('#cur_extra_payoff_date'),res.curExtraLoanInfo.newPayoffDate);
			
				setStdMoney($('#cur_extra_interest_red'), -totalInterestSaving, {show_sign:true});	
				setDateFormat1($('#cur_extra_time_red'),-timeReduction,{
					show_sign: true
				});
		}
		else{
			$('.refi_cur_extra_out').hide();
		}				
		//console.log(res);
		reficalc_set_summary(res);	
	}
	function reficalc_set_summary(res){
		var ans="N/A";
		if(isObject(res.refi2Info)){
			if(res.refi2Info.newTotalInterest < res.curLoanInfo.totalInterest){
				ans ="Yes";
			}
			else{
				ans = "No";
			}
		}
		else if(isObject(res.curExtraLoanInfo)){
			if(res.refiInfo.totalInterest < res.curExtraLoanInfo.newTotalInterest){
				ans = "Yes";
			}
			else ans = "No";
		}
		/*
		else if(isObject(res.refiInfo)){
			if(res.refiInfo.totalInterestSaving > 0){
				ans ="Yes";
			}
			else{
				ans = "No";
			}
		}*/
		
		$('#refi_ans').text(ans);
	}
	function cp_reficalc(params){
		var res={};	
		var curLoanParams = {
			principal:params.curLoanAmount,
			interestRate:params.curInterestRate,
			monthlyPayment:params.curMonthlyPayment,
			startDate:params.curLoanDate
		};

		var curLoanInfo = cp_amortize(curLoanParams);		
		res.curLoanInfo = curLoanInfo;
		
		//refi
		var refiPrincipal = params.curLoanAmount;
		if(params.toRefiCost)refiPrincipal+=params.refiCost;
		var refiParams={
			principal:refiPrincipal,
			interestRate:params.refiInterestRate,
			months:params.refiMonths,
			startDate:params.curLoanDate
		}
		refiParams.monthlyPayment = cp_monthly(refiParams);
		
		var refiInfo = cp_amortize(refiParams);
		refiInfo.totalInterestSaving = curLoanInfo.totalInterest - refiInfo.totalInterest;		
		refiInfo.monthlyPaymentRed = curLoanInfo.monthlyPayment - refiInfo.monthlyPayment;
		refiInfo.timeReduction = 	res.curLoanInfo.data.dataMonthly.length - refiInfo.data.dataMonthly.length ;	
		
		res.refiInfo=refiInfo;
		
		//refi2 	//refi with extra monthly payment to match the current monthly payment
		if (res.curLoanInfo.monthlyPayment > res.refiInfo.monthlyPayment) {
	
			var refi2Params = {
				principal: refiPrincipal,
				interestRate: params.refiInterestRate,
				//months: params.refiMonths,
				startDate: params.curLoanDate,
				monthlyPayment: res.refiInfo.monthlyPayment,
				extraMonthly: res.curLoanInfo.monthlyPayment - res.refiInfo.monthlyPayment
			};
			
			var refi2Info = cp_amortize(refi2Params);
			//refi2Info.totalInterestSaving = curLoanInfo.totalInterest - refi2Info.newTotalInterest;
			//refi2Info.timeReduction = res.curLoanInfo.data.dataMonthly.length - refi2Info.data2.dataMonthly.length;
			res.refi2Info = refi2Info;
		}
		else{ //recompute original with extra payment to match refi monthly payment
			var curExtraLoanParams=$.extend(curLoanParams,{
				extraMonthly: res.refiInfo.monthlyPayment - res.curLoanInfo.monthlyPayment,
				extraMonthlyStartDate:params.curLoanDate
			});
			var curExtraLoanInfo = cp_amortize(curExtraLoanParams);
			
			//curExtraLoanInfo.totalInterestSaving = curLoanInfo.totalInterest - curExtraLoanInfo.newTotalInterest;
			//curExtraLoanInfo.timeReduction = curLoanInfo.data.dataMonthly.length - curExtraLoanInfo.data.dataMonthly.length;
			res.curExtraLoanInfo = curExtraLoanInfo;
			
		}		
		//console.log(res);
		
		return res;
		
		
	}	
	/*
	function mxcalc_schedule(form, param_holder){
		console.log('schedule '+form+","+param_holder[0]);

			if (!isObject(param_holder[0])) 
				form.schedule(1, mxcalc_schedule, form, param_holder);
			else {
				console.log('isObject so stop ');
				if ($('#mxcal_showam').attr('checked')) {
					mxcalc_intensive(param_holder[0]);
				}
				$(this).dequeue();
				unmask('amortize_tb');
				enable_forms(['mform', 'mxform'], true);
			}
	}	*/
		
	function c_mxcalc(){
		enable_forms(['mform', 'mxform'], false);
		var mxcalc_light_res=[''];
		mxcalc_light_res[0] = mxcalc_light();
		
		
		if ($('#mxcal_showam').attr('checked')) mask('amortize_tb');	
		$('#mform').schedule(100, function(){
		//	try {
				if($('#mxcalc_showplot').attr('checked'))mxplot(mxcalc_light_res[0]);
				
				if ($('#mxcal_showam').attr('checked')) {
					var t = new Date().getTime();
					mxcalc_intensive(mxcalc_light_res[0]);
				//console.log("mxcalc took "+(new Date().getTime()-t)/1000+"secs");
				}
				$(this).dequeue();
			/*
			}catch(exp){
				alert("Error during showing amortization table with extra payments "+exp);
			}	*/
			unmask('amortize_tb');
			enable_forms(['mform', 'mxform'], true);
		});
		
		
		
		
	}	
	function enable_form(form, enable){
		enable = (enable?true:false);
		if(isString(form)){
			form = $('#'+form);
		}
		$(form).find('input').attr('disabled',!enable);		
	}
	function enable_forms(forms, enable){
		for(var i =0;i<forms.length;i++)enable_form(forms[i],enable);
	}
	
	function c_mcalc(){
		//var time=new Date();
		enable_forms(['mform','mxform'], false);
		var mcalc_light_res = mcalc_light();
		//console.log("took "+(new Date().getTime()-time.getTime())/1000+" s");
		
		if ($('#showam').attr('checked')) mask('amortize_tb');	
			$('#mform').schedule(100, function(){
				try {
					if($('#mcalc_showplot').attr('checked'))mplot(mcalc_light_res);
					if ($('#showam').attr('checked')) {
						mask('amortize_tb');
						mcalc_intensive(mcalc_light_res);
					}
					
					
				}catch(exp){
					alert("error during mcalc_intensive "+exp);
				}
				$(this).dequeue();
				unmask('amortize_tb');
				enable_forms(['mform', 'mxform'], true);
			});
	
		
		
		
		
		
	}
	function mcalc_light(){
		var coreinput=parseMCalcCoreInput();
	
		var mcalc_res=cp_mcalc(coreinput);
		
		setStdMoney($('#monthlypmt'), mcalc_res.monthlyPayment);
		setText($('#payoff_date'), dateFormat(mcalc_res.payoffDate));
		setStdMoney($('#total_interest') , mcalc_res.totalInterest);
		setStdMoney($('#total_payment') , mcalc_res.totalPayment);
		
		return $.extend({monthlyPayment:mcalc_res.monthlyPayment}, coreinput);
			
				
	}
	function mcalc_intensive(params){
		
		setMCalcAmortize(params);
	}
	function cp_mcalc(params){
		var monthlyPayment = cp_monthly(params);
		var totalPayment = monthlyPayment * params.months;
		var totalInterest = totalPayment - params.principal;
		
		return {
			monthlyPayment:monthlyPayment,	
			payoffDate:cp_payoff_date(params),
			totalInterest:totalInterest,
			totalPayment:totalPayment
		};
	}
	
	function mxcalc_light(){
		var params = parseMCalcCoreInput();
		var monthly=cp_monthly(params);	
		params = $.extend({},params, parseMCalcExtraInput());
		params.monthlyPayment = monthly;

		var mxcalc_res = cp_mxcalc(params);

		setStdMoney($('#interest_saving'), mxcalc_res.interestSaving);
		setDateFormat1($('#time_saving'), -mxcalc_res.timeReduction,{show_sign:true});
		setStdDate($('#new_payoff_date'), mxcalc_res.newPayoffDate);
		setStdMoney($('#new_total_interest'), mxcalc_res.newTotalInterest);
		return mxcalc_res;
	}
	function mxcalc_intensive(params){
		//console.log("input to mxcalc_intensive");
		//console.log(params);
		setMCalcAmortize(params);
	}
	
	
	function cp_mxcalc(params){
		//monthly, extra_monthly, extra_yearly, extra_onetime
		var data = cp_amortize(params);
		return data;
		
	}

	
	/*****************End of Form/action handlers***************/
	

	


	
	/********************* GUI renderers & setters************************************/
	function setStdDate(el, d){
		setText(el, dateFormat(d));
	}
	function setStdMoney(el, val, options){
		var show_sign = false;
		if(options && options.show_sign) show_sign=options.show_sign;
		
		el.text((typeof val !='undefined')? ((show_sign && val>0)?'+':'') +fm(val) : '');
	}
	function setText(el, val){
		el.text((val&& (typeof val !='undefined'))? val : '');
	}
	
	function setDateFormat1(field, months, options){ //years months
	
		var show_sign = false;
		if (options && options.show_sign) 
			show_sign = options.show_sign;
		var pos = true;
		if (months < 0) {
			pos = false;
			months = -months;
		}
		
		var y = Math.floor(months / 12);
		var out = value_format(y, {
			unit: 'year'
		});
		months = months % 12;
		if (months > 0) 
			out += ' and ' +
			value_format(months, {
				unit: 'month'
			});
	
		if (show_sign &&  (y!=0 || months!=0)) {
			if (pos) 
				out = '+' + out;
			else 
				out = '-' + out;
			
		}
	
		setText(field, out);
	}

	function setMCalcAmortize(parameters,render_options){	
		var render_options=$.extend({
			container:'amortize_tb',
			cols: 9,
			orientation:'vertical'
		},render_options || {});
		var res = parameters;
		if (!isObject(res.data) || !isObject(res.data2)) {
			res = cp_amortize(parameters);
		}
		var data = res.data, data2=res.data2, tb_header1='$' + res.principal + ' borrowed on ' + dateFormat(res.startDate) + ' with a monthly payment of ' + fm(res.monthlyPayment);
	
		if (isObject(data.dataMonthly)) {
			renderAmortizeTable(res, data.dataMonthly, $.extend({
				table_to_show: 'original_am',
				sub_table_to_show: 'original_am_monthly',
				table_header: tb_header1,
				type:'monthly'
			}, render_options));
		}
		
		if (isObject(data.dataYearly)) {
			renderAmortizeTable(res, data.dataYearly, $.extend({
				table_to_show: 'original_am',
				sub_table_to_show: 'original_am_yearly',
				table_header: tb_header1,
				type:'yearly'
			}, render_options));
		}
		if (isObject(data2)) {
			var tb2_header = '$' + res.principal + ' borrowed on ' + dateFormat(res.startDate) + ' with a monthly payment of ' + fm(res.monthlyPayment);
			var plus = ' plus ' + (isPositiveNumber(res.extraMonthly) ? 'an extra monthly ' + fm(res.extraMonthly) : '');
			plus += isPositiveNumber(res.extraYearly) ? ' and an extra yearly ' + fm(res.extraYearly) : '';
			plus += isPositiveNumber(res.extraOnetime) ? ' and an extra onetime ' + fm(res.extraOnetime) : '';
			if (isObject(data2.dataMonthly)) {
				renderAmortizeTable(res, data2.dataMonthly, $.extend({
					table_to_show: 'mod_am',
					table_header: tb2_header,
					table_notes: plus,
					sub_table_to_show: 'mod_am_monthly',
					type:'monthly'
				}, render_options));
			}
			if (isObject(data2.dataYearly)) {
				renderAmortizeTable(res, data2.dataYearly, $.extend({
					table_to_show: 'mod_am',
					table_header: tb2_header,
					table_notes: plus,
					sub_table_to_show: 'mod_am_yearly',
					type:'yearly'
				}, render_options));
			}
		}				
	}	
	function renderAmortizeTable(res, data, options){
		
		var container = getEl(options.container);

		var tb=toAmortizeTable(res, data, options), table_to_show = getEl(options.table_to_show), sub_table_to_show=(options.sub_table_to_show?getEl(options.sub_table_to_show):false);
	
		if (sub_table_to_show) {
			table_to_show.tabs('select', getID(sub_table_to_show));
			
			sub_table_to_show.html(tb);
		}	
		else{
			table_to_show.html(tb);
		}
		table_to_show.show();
		container.tabs('select',getID(table_to_show));	
		container.show();	
				
	}
	function toAmortizeTable(res, data, options){
		var time = new Date().getTime();
		var cols=options.cols;
		var html = ['<table class="tb1" width="100%">'];
		if(isString(options.table_header)) html.push('<tr><th class="tbheader" colspan=' +(options.cols+1)+ '>'+options.table_header+ '</th></tr>');
		if(isString(options.table_notes)) html.push('<tr><th class="tbnotes" colspan=' +(options.cols+1)+ '>'+options.table_notes+ '</th></tr>');
		
		var content = (options.orientation == 'horizontal'? toAmortizeTableContentHorizontal(res,data,options) : toAmortizeTableContentVertical(res,data,options));
		
		html = html.concat(content);

		html.push('</table>');
		time=new Date().getTime()-time;
		//console.log("construct table in html took! "+time/1000+" seconds");
		return html.join('');
		
	}
	function toAmortizeTableContentHorizontal(res, data, options){
		var html=[];
		var heading = ['Month', 'Year', 'Payment', 'Principal paid', 'Interest paid', 'Total interest', 'Balance'];
		if(options.type=='yearly')heading = ['Year', 'Payment', 'Principal paid', 'Interest paid', 'Total interest', 'Balance'];
		var n = Math.ceil(data.length/cols);
		var cls='';
		for(var i =0 ;i<n;i++){
			for (var k = 0; k < heading.length; k++) {
				cls='';
				if(k<2)cls='tbhd1';
				else  if (k%2==1)cls ='tbrow1';
				html.push('<tr' + (cls!=''?' class="'+cls+'"':'')  + '>');
				html.push('<td>', heading[k] , '</td>');			
				for(var j = 0;j<cols;j++){
					var index = i*cols + j;
					if(!isObject(data[index]))break;
					var row_data= [];
					if(options.type=='yearly')
						row_data = [
							data[index].month, data[index].year, fm(res.monthlyPayment), fm(data[index].mPrincipal), fm(data[index].mInterest), fm(data[index].totalInterest), fm(data[index].principal)
						];
					else 	
						row_data = [
							data[index].year, fm(res.monthlyPayment), fm(data[index].mPrincipal), fm(data[index].mInterest), fm(data[index].totalInterest), fm(data[index].principal)
						];
					
					html.push('<td>',row_data[k], '</td>');
				}
				html.push('</tr>');
			}
			
		}
		return html;		
	}
	function toAmortizeTableContentVertical(res, data, options){
	
		var html=[];
		var heading = ['Year', 'Month', 'Payment', 'Principal paid', 'Interest paid', 'Total interest', 'Balance'];
		if(options.type=='yearly')heading = ['Year', 'Payment', 'Principal paid', 'Interest paid', 'Total interest', 'Balance'];
		html.push('<tr class="tbhd1">');
		for(var i=0;i<heading.length;i++){
			html.push('<td>', heading[i] , '</td>');	
		}
		html.push('</tr>');
		
		for(var i =0 ;i<data.length;i++){
			
			html.push('<tr' + (i%2==1 ?' class="tbrow1"':'')  + '>');
			var row_data= [];
			if(options.type=='yearly')
				row_data = [
					data[i].year, fm(res.monthlyPayment), fm(data[i].mPrincipal), fm(data[i].mInterest), fm(data[i].totalInterest), fm(data[i].principal)
				];
			else row_data = [
					data[i].year, data[i].month,  fm(res.monthlyPayment), fm(data[i].mPrincipal), fm(data[i].mInterest), fm(data[i].totalInterest), fm(data[i].principal)
				];	
			for (var j = 0; j < row_data.length; j++) {
				html.push('<td>', row_data[j], '</td>');
			}
			html.push('</tr>');
			
		}
		return html;		
	}	
/********************* End of GUI renderers & setters************************************/	
	
	//******************** Math functions ************************/
	function cp_monthly(params){
		var p = params.principal, r = params.interestRate, n = params.months;
		return p * r / (1-Math.pow(1+r, -n));
		
	}
	function cp_payoff_date(params){
		var n = params.months, day = params.startDate.day, month = params.startDate.month, year = params.startDate.year;
		year += Math.floor(n/12);
		month += (n%12);
		if(month>12){
			month = month%12;
			year++;
		}
		
		return {
			day:day,
			month:month,
			year: year
		}
	}

	function cp_amortize(params){
		
		var res = $.extend({},params);
	
		var coreParams = removeKeys($.extend({},params), ['extraMonthly', 'extraYearly', 'extraOnetime','extraMonthlyStartDate']);
	
		res.data = amortize(coreParams);
		res.totalInterest = cp_total_interest(res.data.dataMonthly);
		
		if(isObject(coreParams.startDate)){
			var months =coreParams.months;
			if(!isNumber(months)) months = res.data.dataMonthly.length;
			if(isNumber(months)){
				res.payoffDate = cp_payoff_date({startDate:coreParams.startDate, months:months});		
			}
		}	
		
		if (isNumber(params.extraMonthly) || isNumber(params.extraYearly || isNumber(params.extraOnetime))) {
			
			res.data2 = amortize($.extend({}, params));
			res.newPayoffDate = inc_month(params.startDate,res.data2.dataMonthly.length);
			res.newTotalInterest = cp_total_interest(res.data2.dataMonthly);
			
			res.interestSaving =  res.totalInterest - res.newTotalInterest;
			res.timeReduction = cp_time_saving(res.data.dataMonthly, res.data2.dataMonthly);
			
		
		}
		
		return res;	
	}
	function cp_time_saving(series, new_series){
		if(!isObject(series) || !isObject(new_series)) return 0;
		return series.length - new_series.length;
	}
	function cp_total_interest(series){
		
		return (isObject(series) && series.length>0) ? series[series.length-1].totalInterest : 0;
	}


	function amortize(params){
		var res={};
		var dataMonthly=new Array(), dataYearly = new Array();
		var p = params.principal, r = params.interestRate , n =params.months, m = params.monthlyPayment, stdate	=params.startDate;
		var year = stdate.year, month = stdate.month;
		if (!isNumber(m)) {
			m = cp_monthly(params);
		}
		//extras //interesting_saving, time_saving, new_payoff_date, new_total_interest
		var extraMonthly = params.extraMonthly, extraMonthlyStart = params.extraMonthlyStartDate;
		var extraYearly = params.extraYearly, extraYearlyDate = params.extraYearlyDate;
		var extraOnetime = params.extraOnetime, extraOnetimeDate = params.extraOnetimeDate;
		
		var totalInterest = 0,  counter=0, counter2=0;
		var yInterest = 0, yPrincipal = 0;
		while (Math.round(p) > 0) {
			var mInterest = p * r;
			var new_m = m;
			
			//if(isNumber(extraYearly))console.log('year is '+year+', month is '+month+', extra year is '+extraYearlyDate.month+', extraMonthlyStart.year is '+extraYearlyDate.year);
			if(isNumber(extraMonthly) && dateCompare(stdate, {year:year,month:month}, ['year','month'])<=0  ){
				new_m += extraMonthly ;
			}
			if(isNumber(extraYearly) && year>=extraYearlyDate.year && extraYearlyDate.month == month){
				
				new_m += extraYearly;
			}
			if(isNumber(extraOnetime) && extraOnetimeDate.year == year && extraOnetimeDate.month == month){
				 new_m +=extraOnetime;
			}
			
			var mPrincipal = new_m - mInterest;
			if(p<=mPrincipal){
				mPrincipal = p;
				p=0;
			}
			else p-=mPrincipal;
			totalInterest+=mInterest;
			yInterest+=mInterest;
			yPrincipal+=mPrincipal;
			month++;
			if(month>12){
				month = 1;
				year++;
				dataYearly[counter2++] = {
					mInterest:yInterest,
					mPrincipal:yPrincipal,
					principal:p,
					totalInterest:totalInterest,
					year:year
				}
				yInterest = 0;
				yPrincipal = 0;
			}
			
			dataMonthly[counter++]={
				mInterest:mInterest,
				mPrincipal:mPrincipal,
				principal:p,
				month:month,
				year:year,
				totalInterest:totalInterest
			}	
		}
		res.dataMonthly=dataMonthly;
		res.dataYearly=dataYearly;
		return res;
	}
	/****************** End of Math functions*********************/
	/****************** parsers, formatters and utils*********************/	
	function dateFormat(date){
		
		if(!isObject(date)) return '';
		var month = (method_exists(date,'getMonth')?date.getMonth()+1:date.month), day = (method_exists(date,'getDate')? date.getDate():date.day), year = (method_exists(date, 'getFullYear')?date.getFullYear():date.year);
		return dfm(month,2) +"/" + (isNumber(day)? dfm(day,2) +"/" :'')+dfm(year,dfm);
	}
	function inc_month(date, inc){
		var res = $.extend({},date);
		res.year += Math.floor(inc/12);
		res.month += inc%12;
		if(res.month>12){
			res.month=1;
			res.year++;
		}	
		return res;
	}
	function parseDate(date){
		date = date.split("/");
		var d = {
			month: Number(date[0]),
			day: Number(date[1]),
			year: Number(date[2])
		};
		return d;
	}
	
	function dfm(x, digits){
		if(typeof x !='number')x = Number(x);
		var fm = '';
		for(var i =0;i<digits;i++)fm+='0';
		return x.numberFormat(fm);
	}

	function fm(x){
		//if(typeof x !='number')x = Number(x);
		//return '$'+x.numberFormat('0.00'); //horrible performance
		
			return x.toFixed(2);
		
	}
	function isDefined(x){
		return typeof(x)!=='undefined';
	}	
	
	function removeKeys(obj, keys){
		
		for(var i =0;i<keys.length;i++)delete obj[keys[i]];
		return obj;
	}
	function value_format(val, options){
		options = options||{};
		var res = val;
		if(isString(options.unit)){
			res +=' '+options.unit+(Math.abs(val)<=1?'':'s');
		}
		return res;
	}		
	/****************** End of parsers, formatters and utils*********************/		
