/**
 * Overview: This plugin is included on any page where a mortgage calculator resides (potentially any page).
 *
 * usage: used on all website pages that have mortgage features
 * dependencies: jQuery, jquery.rpm.js
 */

(function(){
	$.fn.csMortgagePanel = $.csMortgagePanel = function(method) {
		var options = null; // contains all the options that the plugin uses
		var optionsObjectName = 'csMortgagePanelOptions'; // because this plugin stores option in the 'body' DOM element, we create a unique identifier for it to prevent conflicts with other plugins

		var methods = {
			/**
			* Initialize plugin
			*
			* @param options options used to configure the plygin
			*/
			init : function(options){
				return this.each(function() {
					var self = this;  // initialize a pointer to the context for the plugin
					var $this = $(this);  // create a quick-reference jQuery object with this DOM element
					
					// load the config.
					helpers.loadOptions.call(this, options);


					// function to initiate the tabs in the mortgage panel
					var initateTabs = function(){
						$("#csTabMortgage", "#csMortgageInfoWindow").click(function(){
							if(!helpers.isTabSelected('csTabMortgage')){
								helpers.openMortgageCalculator(initateTabs);
							}
							return false;
						});
						$("#csTabPrequalifier", "#csMortgageInfoWindow").click(function(){
							if(!helpers.isTabSelected('csTabPrequalifier')){
								helpers.openPrequalifier(initateTabs);
							}
							return false;
						});
					}

					// load the correct tab based on the selectedTabId of the options (0 = Mortgage Calculator, 1 = Prequalifier)
					if(options.activeTabId == 'csTabMortgage')
						helpers.openMortgageCalculator(initateTabs, true);
					else if(options.activeTabId == 'csTabPrequalifier')
						helpers.openPrequalifier(initateTabs, true);
						
					// store the options for subsequent calls
					$this.data(optionsObjectName, options);
					
					return false;
				});
			}
		};

		// public static methods - called without an element being specified
		var staticMethods = {

		};
		
		// these are the private helper functions, generally static.
		var helpers = {
			/** Opens the mortgage calculator
			  * 
			  * @param onComplete function to be run after the infowindow has opened
			  */
			openMortgageCalculator : function(onComplete, init) {
				var cb_his_ctl = "bust";
				if(init === true) cb_his_ctl = "log";
			
				// load the correct mortgage calculator into the panel
				$.clickSoldUtils('infoBoxCreate', {
					href: options.ajaxTarget + "?pathway=537&loadMortgageCalculator=true&listPrice=" + options.listPrice + "&propTax=" + options.tax + "&conFees=" + options.cFees + "&listingNumber=" + options.listingNumber + "&modletId=" + options.modletId,
					cb_his_control: cb_his_ctl,
					onComplete: function(){
						helpers.selectTab('#csTabMortgage');
						$('#csMortgageCalculator', '#csMortgageInfoWindow').MortgageCalc('init', options.region);
						if(onComplete != null && typeof onComplete == "function") onComplete();
						$.clickSoldUtils('infoBoxResize');
					},
					onClosed: function(){
					}
				});
				
				return false;
			},
			/** Opens the Prequalifier
			  * 
			  * @param onComplete function to be run after the infowindow has opened
			  */
			openPrequalifier : function(onComplete, init) {
				var cb_his_ctl = "bust";
				if(init === true) cb_his_ctl = "log";
			
				// load the correct mortgage calculator into the panel
				$.clickSoldUtils('infoBoxCreate', {
					href: options.ajaxTarget + "?pathway=537&loadPrequalifier=true&propTax=" + options.tax + "&conFees=" + options.cFees + "&listingNumber=" + options.listingNumber + "&modletId=" + options.modletId,
					cb_his_control: cb_his_ctl,
					onComplete: function(){
						helpers.selectTab('#csTabPrequalifier');
						if(onComplete != null && typeof onComplete == "function") onComplete();
						$("label[for='bankruptcy']").parents("div.cs-input-small").removeClass("cs-input-small");
						$.clickSoldUtils('infoBoxResize');
					},
					onClosed: function(){
					}
				});
				
				return false;
			},
			/**
			  * Highlights the tab with the specified ID
			  *
			  * @param id - id of the tab we're looking to highlight
			  */
			selectTab:function(tabId){  // throws exception
				// reset all tabs
				$(".cs-tabs-tab-active", '#csMortgageInfoWindow').addClass("cs-tabs-tab").removeClass("cs-tabs-tab-active");
				
				// highlight the correct tab
				$(tabId, '#csMortgageInfoWindow').parent().addClass("cs-tabs-tab-active").removeClass("cs-tabs-tab");
			},
			/** Checks whether the given tab is selected
			  * 
			  * @param tab to check
			  * @return boolean if the tab is selected or not
			  */
			isTabSelected : function(tabId) {
				if(tabId == $(".cs-tabs-tab-active", '#csMortgageInfoWindow').children('a').attr('id'))
					return true
				else
					return false;
			},

			/**
			  * Loads the options, trying to load from memory if available
			  *
			  * @param options - options sent from running the plugin (if available)
			  */
			loadOptions:function(opts){  // throws exception
				var self = this;  // initialize a pointer to the context for the plugin
				var $this = $(this);  // create a quick-reference jQuery object with this DOM element

				if(options == null){
					options = $this.data(optionsObjectName); // attempt to extract any stored configs for this DOM element
					
					// if config is still null, continue.
					if(options == null)
						options = {};
					
					// now update the options
					if(opts != null){
						if(!opts) return false;
						$.extend(options, opts);
					}
				}
			}
		};

		// these are the private helper functions. Expose these methods in staticMethods
		var MortgageCalculatorHelpers = {
			
		};

		try{
			if(methods[method]){
				return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
			}else if(staticMethods[method]){
				return staticMethods[method].apply(this, Array.prototype.slice.call(arguments, 1));
			}else if(typeof method === "object"){
				return methods.init.apply(this, arguments);
			}else{
				alert("Error! Method does not exist: " + method);
				$.error("Method " + method + " doesn't exist on jQuery.csMortgagePanel");
			}
		}catch(ex){
			alert("$.fn.csMortgagePanel - error\n" + ex.name + " - " + ex.message);
		}
	}

	$.fn.MortgageCalc = function(method, region) {
		
		var t_Mortgage = 0;
		var t_TotalMortgagePayment = 0;
		
		var principal;
		var interest;
		var lbl1;
		var principalPaid;
		var interestPaid;
		var lbl2;
		
		var graph1 = null;
		var graph2 = null;

		var methods = {
			init : function(reg){
				return this.each(function(){
					// initialize
					var region = reg;

					//populate Down Payment input box with percentage specified in drop-down
					$("#downPay").val( (helpers.readFormattedValue($("#downPay_perc").val()) * helpers.readFormattedValue($("#listPrice").val())) / 100 );

					// run the first calculation
					helpers.calculate(region);
					
					// add change events to the numerical fields
					$("#listPrice, #utilities, #propTax, #conFees, #amort, #intRate, #payFreq").change(function(){
						helpers.calculate(region);
					});
					
					// add change event for down-payment drop-down
					$("#downPay").change(function(){
						// calculate the percent the user is putting down
						var percent = helpers.readFormattedValue($("#downPay").val()) / helpers.readFormattedValue($("#listPrice").val()) * 100;
						percent = percent.toFixed(0);
						
						// append an option with this new percentage and set it at selected
						$("#downPay_perc").append("<option value=\"" + percent + "\">" + percent + "</option>").val(percent);

						// re-run the calculation
						helpers.calculate(region);
					});
					// add a change event to the down payment percentage drop-down
					$("#downPay_perc").change(function(){
						$("#downPay").val( (helpers.readFormattedValue($("#downPay_perc").val()) * helpers.readFormattedValue($("#listPrice").val())) / 100 );

						// re-run the calculation
						helpers.calculate(region);
					});
					
					// add a change amortization to the down payment percentage drop-down
					$("#amort_years").change(function(){
						$('#amort').val($("#amort_years").val());
						helpers.calculate(region);
					});
				});	
			}
		};
		
		var helpers = {
			/**
			  * Reads a formatted currency value and returns a valid double
			  */
			readFormattedValue : function(formattedValue){
				return formattedValue.replace(/[^\d^\.]/g, "");
			},

			calculate : function(region){
				var $this = $(this);
				
				// Massage Currency Values, so commas and dollar signs don't mess up the calculations.
				$("#listPrice").val($.clickSoldUtils("formatAsCurrency", $("#listPrice").val(), false));
				$("#utilities").val($.clickSoldUtils("formatAsCurrency", $("#utilities").val(), false));
				$("#propTax").val($.clickSoldUtils("formatAsCurrency", $("#propTax").val(), false));
				$("#conFees").val($.clickSoldUtils("formatAsCurrency", $("#conFees").val(), false));
				$("#downPay").val($.clickSoldUtils("formatAsCurrency", $("#downPay").val(), false));
				
				// determine insurance stuff
				var temp = parseFloat($("#downPay").val())/parseFloat($("#listPrice").val());
				var tempAmortization = parseFloat($("#amort_years").val());
				var insuranceRate = 0;
				if(region == "1"){ //Canada
					//Standard Insurance (CMHC) up to and including 25 years amortization.
					if( temp <= 0.05 ) insuranceRate = 0.0275;	  // more than 95% loan-to-value (this is no longer allowed)
					else if( temp <= 0.10 ) insuranceRate = 0.0200;  // up to and including 90% loan-to-value
					else if( temp <= 0.15 ) insuranceRate = 0.0175;  // up to and including 85% loan-to-value
					else if( temp <= 0.20 ) insuranceRate = 0.0100;  // up to and including 80% loan-to-value
					else if( temp <= 0.25 ) insuranceRate = 0.0065;  // up to and including 75% loan-to-value
					else if( temp <= 0.35 ) insuranceRate = 0.0050;  // up to and including 65% loan-to-value
					else insuranceRate = 0;
					
					//Insurance surcharge based on mortgage over 25 years.
					if ( tempAmortization > 35 && insuranceRate != 0)  { insuranceRate += 0.0060 } 
					else if ( tempAmortization > 30 && insuranceRate != 0)  { insuranceRate += 0.0040 } 
					else if ( tempAmortization > 25 && insuranceRate != 0)  { insuranceRate += 0.0020 }
					
				}else{  //USA
					//Get Payments Per Year 			
					insuranceRate = (parseFloat($("#intRate").val()) / 100) / 12;
				}
				
				// get temporary values
				var temp_mortgageAmount = parseFloat(helpers.readFormattedValue($("#listPrice").val())) - parseFloat(helpers.readFormattedValue($("#downPay").val()));
				var temp_insurance = temp_mortgageAmount * insuranceRate;
				var temp_PropertyTax = parseFloat(helpers.readFormattedValue($("#propTax").val())) / $("#payFreq").val();
				var temp_CondoFees = parseFloat(helpers.readFormattedValue($("#conFees").val()));
				var temp_UtilityCosts = parseFloat(helpers.readFormattedValue($("#utilities").val()));

				// set global parameters
				var yearlyPayments = $("#payFreq").val();
				var annualInterestRate = parseFloat($("#intRate").val())/100;
				var amortizationYears = $('#amort').val();
				var principal = temp_insurance + temp_mortgageAmount;

				// Calculates the periodic mortgage payment for the specified conditions. 
				// Formulas taken from: http://en.wikipedia.org/wiki/Amortization_calculator, though it appears that
				// the periodic interest formula there is not correct. Below we are using a slightly modified version:
				// 	i = (1+iann/compoundingPeriods)^compoundingPeriods/yearlyPayments - 1
				// instead of
				//	i = (1+iann/yearlyPayments)^compoundingPeriods/yearlyPayments - 1
				//
				// Results varified by: http://www.1stop-mortgagecalculator.com/mortgage-calculator-code-part3.htm
				//
				// @param yearlyPayments = number of payments to be made within a year
				// @param annualInterestRate (in %)
				// @param principal
				// @param amortizationYears
				//
				// calculate periodic interest rate
				var periodicInterest;		// periodic interest
				var compoundingPeriods;		// compounding periods/yr (12 in US, 2 in Canada)
				  
				// set compounding periods
				if(region == "1")
					compoundingPeriods = 2;
				else
					compoundingPeriods = 12;
				  
				// get periodic interest
				periodicInterest = Math.pow((1 + annualInterestRate/compoundingPeriods), compoundingPeriods/yearlyPayments) - 1;
				  
				// calculate and set periodic payment
				periodicPayment = (principal * periodicInterest)/(1 - Math.pow((1+periodicInterest), ((-1) * amortizationYears*yearlyPayments)));

				// set the monthly equivalent payment
				this.t_TotalMortgagePayment = periodicPayment*yearlyPayments/12;
				var temp_TotalMonthly = temp_UtilityCosts + temp_CondoFees + temp_PropertyTax + this.t_TotalMortgagePayment;

				// prepare report
				$('#report_Price').html("$" + $.clickSoldUtils("formatAsCurrency", $("#listPrice").val(), false));
				$('#report_MortgageAmount').html("$" + $.clickSoldUtils("formatAsCurrency", temp_mortgageAmount, false));
				$('#report_Insurance').html("$" + $.clickSoldUtils("formatAsCurrency", temp_insurance, false));
				$('#report_TotalMortgage').html("$" + $.clickSoldUtils("formatAsCurrency", principal, false));
				$('#report_InsuranceRate').html((insuranceRate*100).toFixed(2));

				$('#report_TotalMortgagePayment').html("$" + $.clickSoldUtils("formatAsCurrency", this.t_TotalMortgagePayment, false));
				$('#report_PropertyTax').html("$" + $.clickSoldUtils("formatAsCurrency", temp_PropertyTax, false));
				$('#report_CondoFees').html("$" + $.clickSoldUtils("formatAsCurrency", temp_CondoFees, false));
				$('#report_UtilityCosts').html("$" + $.clickSoldUtils("formatAsCurrency", temp_UtilityCosts, false));
				$('#report_TotalMonthly').html("$" + $.clickSoldUtils("formatAsCurrency", temp_TotalMonthly, false));
				
				// create value storage objects
				var principalPortion = new Array();
				var interestPortion = new Array();
				var principalAccumulated = new Array();
				var interestAccumulated = new Array();
				var xTicks = new Array();
				
				// create temporary variables
				var tempPrincipalPortion = 0;
				var tempInterestPortion = 0;
				var tempPrincipalAccumulated = 0;
				var tempInterestAccumulated = 0;

				// create an amortization table based on the periodic payment.
				var outstandingPrincipal = principal;
				var lastInterestAccululated = 0;
				var years = 0;
				for(var i = 0; i < yearlyPayments * amortizationYears; i++){
					if(amortizationYears > 25){
						if(i % (yearlyPayments*2) == 0){
							xTicks.push([i, years]);
							years +=2;
						}
					}else{
						if(i % yearlyPayments == 0){
							xTicks.push([i, years]);
							years++;
						}
					}

					interestPortion[i] = [i, outstandingPrincipal * periodicInterest];
					principalPortion[i] = [i, periodicPayment - interestPortion[i][1]];

					interestAccumulated[i] = [i, interestPortion[i][1] + tempInterestAccumulated];
					tempInterestAccumulated = interestAccumulated[i][1];

					principalAccumulated[i] = [i, principalPortion[i][1] + tempPrincipalAccumulated];
					tempPrincipalAccumulated = principalAccumulated[i][1];

					outstandingPrincipal = outstandingPrincipal - principalPortion[i][1];
				}
				
				// add the final xTick
				xTicks.push([yearlyPayments * amortizationYears-1, years]);
				
				$("#gLeg1").empty();
				$("#gLeg2").empty();

				if(graph1 != null){
					graph1 = null;
				}

				//place arrays into flot object and plot graph - first graph
				graph1 = $.plot($("#int_pri"), [{
					data: interestPortion,
					label: "Interest",
					lines: { show: true }
				},{
					data: principalPortion,
					label: "Principal",
					lines: { show: true }
				}],
				{
					xaxis: {
						ticks: xTicks
					},
					yaxis: {
						tickFormatter: function(val, axis){
							return '$'+$.clickSoldUtils("formatAsCurrency", val, false);
						}
					},
					legend: {
						container: $("#gLeg1"),
						backgroundOpacity:0.4
					}
				});
				
				if(graph2 != null){
					graph2 = null;
				}
				
				//place arrays into flot object and plot graph - first graph
				graph = $.plot($("#int_pri_acc"), [{
					data: interestAccumulated,
					label: "Interest",
					lines: { show: true }
				},
				{
					data: principalAccumulated,
					label: "Principal",
					lines: { show: true }
				}],
				{
					xaxis: {
						ticks: xTicks
					},
					yaxis: {
						tickFormatter: function(val, axis){
							return '$'+$.clickSoldUtils("formatAsCurrency", val, false);
						}
					},
					legend: {
						container: $("#gLeg2"),
						backgroundOpacity:0.4
					}
				});
			}
		};
		
		if( methods[method] ){  //Method call
			return methods[method].apply(this, Array.prototype.slice.call( arguments, 1 ));
		}else if(typeof method === "object"){  //Initialization call - must have arguments
			return methods.init.apply(this, arguments);
		}else{  //ERROR
			$.error("Method " + method + " does not exist on jQuery.MortgageCalc");
		}
	};
})( jQuery );
