if (Calculators == undefined) {
	var Calculators = {};
}
if (Calculators.loan == undefined) {
	Calculators.loan = {};
}
Calculators.loan.Refinance = function Refinance(originalRate, originalAppraisedValue, originalAmount, originalPeriods, originalPeriodsRemaining, 
	refinancedRate, refinancedAppraisedValue, refinancedBalance, refinancedOtherClosingCosts, refinancedPeriods, loanOriginationRate, pointsPaid, incomeTaxRate) {

	this.originalRate = new Calculators.type.Rate(originalRate);
	this.originalAppraisedValue = new Calculators.type.Money(originalAppraisedValue);
	this.originalAmount = new Calculators.type.Money(originalAmount);
	this.originalPeriods = new Number(originalPeriods);
	this.originalPeriodsRemaining = new Number(originalPeriodsRemaining);
	this.refinancedRate = new Calculators.type.Rate(refinancedRate);
	this.refinancedAppraisedValue = new Calculators.type.Money(refinancedAppraisedValue);
	this.refinancedOtherClosingCosts = new Calculators.type.Money(refinancedOtherClosingCosts);
	this.refinancedPeriods = new Number(refinancedPeriods);
	this.loanOriginationRate = new Calculators.type.Rate(loanOriginationRate);
	this.pointsPaid = new Number(pointsPaid);
	this.incomeTaxRate = new Calculators.type.Rate(incomeTaxRate);

	this.originalMortgage = new Calculators.loan.Loan(originalRate, originalPeriods, originalAmount);

	if (refinancedBalance == 0) {
		var statement = this.originalMortgage.getMonthlyStatement(this.originalPeriods - this.originalPeriodsRemaining);
		this.refinancedBalance = statement.getBalance();
	}
	else {
		this.refinancedBalance = new Calculators.type.Money(refinancedBalance);
	}
	
	this.getRefinancedLoanBalance = function(){
		return this.refinancedBalance;
	}
	
	this.getRefinancedLoanOriginationRateAsAmount = function(){
		var amount = this.getRefinancedLoanBalance().getAmount();
		return new Calculators.type.Money(amount * this.loanOriginationRate.getAmount());
	}

	this.getPointsAsAmount = function() {
		var amount = this.getRefinancedLoanBalance().getAmount();
		return new Calculators.type.Money(amount * (this.pointsPaid / 100));
	}
	
	this.getAllClosingCosts = function() {
		var originationCosts = this.getRefinancedLoanOriginationRateAsAmount();
		var pointsCosts = this.getPointsAsAmount();
		return this.refinancedOtherClosingCosts.add(originationCosts.add(pointsCosts));
	}
	
	this.getRefinancedAmount = function() {
		return this.getRefinancedLoanBalance();
	}
	
	this.refinancedMortgage = new Calculators.loan.Loan(refinancedRate, refinancedPeriods, this.getRefinancedAmount().getAmount());

	this.getSavingsByMonth = function(){
		// Iterate through all the statements and return a new Array comparing
		//	each mortgage statement
	}
	
	this.getOriginalLoanBalance = function(){
		var statement = this.originalMortgage.getMonthlyStatement(this.originalPeriods - this.originalPeriodsRemaining);
		if (statement)
			return statement.getBalance();
		else
			return null;
	}
	
	this.getIncomeTaxRate = function(){
		return this.incomeTaxRate;
	}
	
	this.getOriginalLoanAmount = function(){
		return this.originalAmount;
	}
	
	this.getOriginalAppraisedValue = function(){
		return this.originalAppraisedValue;
	}
	
	this.getOriginalPeriodsRemaining = function(){
		return this.originalPeriodsRemaining;
	}
	
	this.getOriginalInterestRate = function(){
		return this.originalRate;
	}
	
	this.getOriginalLoanYears = function(){
		return this.originalPeriods / 12;
	}
	
	this.getOriginalYearsRemaining = function(){
		return this.originalPeriodsRemaining / 12;
	}
	
	this.getRefinancedTermYears = function(){
		return this.refinancedPeriods / 12;
	}
	
	this.getRefinancedOtherClosingCosts = function(){
		return this.refinancedOtherClosingCosts;
	}
	
	this.getRefinancedAppraisedValue = function(){
		return this.refinancedAppraisedValue;
	}
	
	this.getRefinancedInterestRate = function(){
		return this.refinancedRate;
	}
	
	this.getRefinancedLoanOriginationRate = function(){
		return this.loanOriginationRate;
	}
	
	this.getRefinancedPointsPaid = function(){
		return this.pointsPaid;
	}

	this.getOriginalLoanMonthlyPayment = function() {
		return this.originalMortgage.getMonthlyPayment();
	}

	this.getRefinancedLoanMonthlyPayment = function() {
		return this.refinancedMortgage.getMonthlyPayment();
	}
	
	this.getOriginalLoanMonthlyStatement = function(month) {
		var offset = ((this.getOriginalLoanYears() - this.getOriginalYearsRemaining()) * this.originalMortgage.MONTHS);
		var offsetMonth = offset + month;

		if ((offsetMonth < 0) || (offsetMonth > this.originalMortgage.nper)) {
			return null;
		}

		var statement = this.originalMortgage.getMonthlyStatement(offsetMonth);
		if (statement) {
			var pmiStatement = new Calculators.loan.StatementWithPMI(statement, this.originalAppraisedValue, this.originalAmount);
			return pmiStatement;
		}
		else {
			var statement = new Calculators.loan.Statement(0.0, 0.0, 0.0);
			var pmiStatement = new Calculators.loan.StatementWithPMI(statement, this.originalAppraisedValue, this.originalAmount);
			return pmiStatement;
		}
	}

	this.getRefinancedLoanMonthlyStatement = function(month) {
		var statement = this.refinancedMortgage.getMonthlyStatement(month);
		if (statement) {
			var pmiStatement = new Calculators.loan.StatementWithPMI(statement, this.refinancedAppraisedValue, this.refinancedBalance);
			return pmiStatement;
		}
		else {
			var statement = new Calculators.loan.Statement(0.0, 0.0, 0.0);
			var pmiStatement = new Calculators.loan.StatementWithPMI(statement, this.refinancedAppraisedValue, this.refinancedBalance);
			return pmiStatement;
		}
	}

	this.getOriginalLoanYearlyStatement = function(year) {
		var offset = ((this.getOriginalLoanYears() - this.getOriginalYearsRemaining()));
		var statement = this.getYearlyStatement(this.originalMortgage, (offset + year), this.originalAppraisedValue, this.originalAmount);
		if (statement) {
			return statement;
		}
		else {
			statement = new Calculators.loan.Statement(0.0, 0.0, 0.0);
			var pmiStatement = new Calculators.loan.StatementWithPMI(statement, this.originalAppraisedValue, this.originalAmount);
			return pmiStatement;
		}
	}

	this.getRefinancedLoanYearlyStatement = function(year) {
		var statement = this.getYearlyStatement(this.refinancedMortgage, year, this.refinancedAppraisedValue, this.refinancedBalance);
		return statement;
		//var pmiStatement = new Calculators.loan.StatementWithPMI(statement, this.refinancedAppraisedValue, this.refinancedBalance);
		//alert("pmiStatement: " + pmiStatement);
		//return pmiStatement;
	}
	
	this.getMonthOfOriginalPmiFreedom = function() {
		var offset = (this.originalPeriods - this.originalPeriodsRemaining);
		var statements = this.originalMortgage.statements;
		var noMorePmiAmount = 0.20 * this.originalAppraisedValue.getAmount();
		var noMorePmiBalance = 0.80 * this.originalAppraisedValue.getAmount();
		var principal = 0;
		for (var i=0; i<statements.length; ++i) {
			var statement = statements[i];
			if (statement) {
				 if (statement.getBalance().getAmount() < noMorePmiBalance) {
					return i - offset + 1;
				 }
			}
			
		}
	}

	this.getMonthOfRefinancedPmiFreedom = function() {
		var statements = this.refinancedMortgage.statements;
		var noMorePmiAmount = 0.20 * this.refinancedAppraisedValue.getAmount();
		var noMorePmiBalance = 0.80 * this.refinancedAppraisedValue.getAmount();
		var principal = 0;
		for (var j=0; j<statements.length; ++j) {
			var statement = statements[j];
			if (statement) {
				 if (statement.getBalance().getAmount() < noMorePmiBalance) {
					//alert("" + statement.getBalance().getAmount() + " < " + noMorePmiBalance + " at? " + j);
					return j + 1;
				 }
			}
			
		}
	}

	this.getYearOfOrginalPmiFreedom = function() {
		var offset = (this.getOriginalLoanYears() - this.getOriginalYearsRemaining());
		var years = this.originalMortgage.getMonthlyNper();
		var noMorePmiAmount = 0.20 * this.originalAppraisedValue.getAmount();
		var principal = 0;
		for (var i=0; i<years; ++i) {
			principal = principal + this.getYearlyStatement(this.originalMortgage, i, this.originalAppraisedValue, this.originalAmount).getPrincipal().getAmount();
			if (principal > noMorePmiAmount) {
				//alert(principal + " > " + noMorePmiAmount);
				return i - offset;
			}
		}
	}

	this.getYearOfRefinancedPmiFreedom = function() {
		var years = this.refinancedMortgage.getMonthlyNper();
		var noMorePmiAmount = 0.20 * this.getRefinancedAmount().getAmount();
		var principal = 0;
		for (var i=0; i<years; ++i) {
			principal = principal + this.getYearlyStatement(this.refinancedMortgage, i, this.refinancedAppraisedValue, this.refinancedBalance).getPrincipal().getAmount();
			if (principal > noMorePmiAmount) {
				//alert(principal + " > " + noMorePmiAmount);
				return i;
			}
		}
	}

	this.getYearlyStatement = function(loan, year, appraisedAmount, loanAmount) {
		if ((year < 0) || (year > loan.getMonthlyNper())) {
			return null;
		}
		
		var balance = 0.0;
		var interest = new Calculators.type.Money(0.0);
		var principal = new Calculators.type.Money(0.0);
		var pmi = new Calculators.type.Money(0.0);
		
		var end = (year == 0) ? 1 : year * loan.MONTHS + 1;
		var start = (year == 0) ? 0 : end - loan.MONTHS;

		for (var month = start; month < end; ++month) {
			var stmt = loan.getMonthlyStatement(month);
			var pmiStatement = new Calculators.loan.StatementWithPMI(stmt, appraisedAmount, loanAmount);
			balance = stmt.getBalance();
			interest = interest.add(stmt.getInterest());
			principal = principal.add(stmt.getPrincipal());
			pmi = pmi.add(pmiStatement.getPMI());
		}
		
		var totalsStmt = new Calculators.loan.Statement(
			new Calculators.type.Money(balance).rounded(), interest.rounded(), principal.rounded());
		
		var totalsWithPmi = new Calculators.loan.StatementWithPMI(totalsStmt, appraisedAmount, loanAmount, pmi.rounded());
		return totalsWithPmi;
	}
	
	this.getMonthlyPaymentSavings = function() {
		return (this.originalMortgage.getMonthlyPayment().subtract(
			this.refinancedMortgage.getMonthlyPayment()));
	}
	
	this.getInterestSavings = function(month) {
		var oStmt = this.getOriginalLoanMonthlyStatement(month);
		var rStmt = this.getRefinancedLoanMonthlyStatement(month);

		if (oStmt) {
			return (oStmt.getInterest().subtract(rStmt.getInterest()));
		}
		else {
			return new Calculators.type.Money(0.00);
		}
	}
	
	this.getPmiSavings = function(month) {
		var oStmt = this.getOriginalLoanMonthlyStatement(month);
		var rStmt = this.getRefinancedLoanMonthlyStatement(month);

		if (oStmt) {
			return (oStmt.getPMI().subtract(rStmt.getPMI()));
		}
		else {
			return new Calculators.type.Money(0.00);
		}
	}

	this.getMonthlyPaymentSavingsBreakevenPoint = function() {
		// When monthly payment savings > closing costs
		var savings = this.getMonthlyPaymentSavings().getAmount();
		var costs = this.getAllClosingCosts().getAmount();
		var point = Math.ceil(costs / savings);
		return point;
	}
		
	this.getPmiBreakevenPoint = function() {
		// When Interest and PMI > closing costs
		var costs = this.getAllClosingCosts().getAmount();
		
		var runningTotalSavings = 0.00;
		for (var i=1; i<this.refinancedPeriods; i++) {
			runningTotalSavings += this.getInterestSavings(i).getAmount();
			runningTotalSavings += this.getPmiSavings(i).getAmount();
			if (runningTotalSavings > costs) {
				return i;
			}
		}
		
		return 0;
	}
		
	this.getAfterTaxSavingsBreakevenPoint = function() {
		// When after-tax interest and PMI > closing costs
		var costs = this.getAllClosingCosts().getAmount();
		var taxFactor = (1 - this.incomeTaxRate.getAmount());

		var runningTotalSavings = 0.00;
		for (var i=1; i<this.refinancedPeriods; i++) {
			runningTotalSavings += (this.getInterestSavings(i).getAmount() * taxFactor);
			runningTotalSavings += this.getPmiSavings(i).getAmount();
			if (runningTotalSavings > costs) {
				return i;
			}
		}
		
		return 0;
	}
		
	this.getTotalSavingsVsPrepaymentBreakevenPoint = function() {
		// getAfterTaxInterestSavings() > (closing costs + prepayment)
		var costs = this.getAllClosingCosts().getAmount();
		var taxFactor = (1 - this.incomeTaxRate.getAmount());
		var offset = ((this.getOriginalLoanYears() - this.getOriginalYearsRemaining()) * this.originalMortgage.MONTHS);

		// create a temp mortgage to simulate prepayment
		//var prepaymentMortgage = this.generatePrepaymentMortgage();

		var runningTotalSavings = 0.00;
		for (var i=1; i<this.refinancedPeriods; i++) {
			var offsetMonth = offset + i;
	
			if (offsetMonth <= this.prepaymentMortgage.nper) {
				var statement = this.prepaymentMortgage.getMonthlyStatement(offsetMonth);
				if (statement) {
					var prepaymentStatement = new Calculators.loan.StatementWithPMI(statement, this.originalAppraisedValue, this.originalAmount);
					var refinancedStatement = this.getRefinancedLoanMonthlyStatement(i);
					
					var interestSavings = (prepaymentStatement.getInterest().subtract(refinancedStatement.getInterest()).getAmount() * taxFactor);
					var pmiSavings = prepaymentStatement.getPMI().subtract(refinancedStatement.getPMI()).getAmount();
					
					runningTotalSavings += interestSavings;
					runningTotalSavings += pmiSavings;
					if (runningTotalSavings > costs) {
						//alert("" + runningTotalSavings + " > " + costs);
						return i;
					}
				}
			}
		}
		
		return 0;
	}
	
	////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	// Functions used for comparing refinancing against using the closing costs to prepay on the existing mortgage
	////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	
	this.generatePrepaymentMortgage = function() {
		var costs = this.getAllClosingCosts().getAmount();
		var offset = ((this.getOriginalLoanYears() - this.getOriginalYearsRemaining()) * this.originalMortgage.MONTHS);

		// create a temp mortgage to simulate prepayment
		var frequency = new Calculators.loan.PaymentFrequency();
		var prepayment = new Calculators.loan.Prepayment(costs, frequency.getPaymentFrequency(frequency.LUMPSUM), offset);
		var prepaymentMortgage = new Calculators.loan.Loan(originalRate, originalPeriods, originalAmount, prepayment);
		
		return prepaymentMortgage;
	}
	
	this.prepaymentMortgage = this.generatePrepaymentMortgage();

	this.getPrepaymentLoanYearlyStatement = function(year) {
		var offset = ((this.getOriginalLoanYears() - this.getOriginalYearsRemaining()));
		var statement = this.getYearlyStatement(this.prepaymentMortgage, (offset + year), this.originalAppraisedValue, this.originalAmount);
		if (statement) {
			return statement;
		}
		else {
			statement = new Calculators.loan.Statement(0.0, 0.0, 0.0);
			var pmiStatement = new Calculators.loan.StatementWithPMI(statement, this.originalAppraisedValue, this.originalAmount);
			return pmiStatement;
		}
	}

}
