/**
 * @author 	buenger
 * @version	1.0
 * 
 * Depends on the following external classes/libraries:
 * 	- Utilities.class.js
 *  - Settings.class.js
 * 	- PPI.class.js
 *  - Event handling from mootools library 1.2 (mootools.net)
 */

function Leasing () {
	
	var price;
	var runtime;
	var nomInterest;
	var effInterest;
	var maxDecliningBalance; 
	var minDecliningBalance; 
	var standardDecliningBalance;
	var decliningBalance = 0;
	var deposit = 0; 
	
	var isMarginTaxed = false;
	var hasPPIDeath = true;
	var hasPPIUnemployment = true;
	
	this.PPIRate;
	this.PPITotal;
	this.rate;
	this.rateInclPPI;
	this.totalCharges;
	this.interestCharges;
	this.decliningBalance;
	this.deposit;
	
	var _self = this;
	
	this.setRuntime = function (a_runtime) {
		runtime = Number(a_runtime);
	}
	
	this.setPrice = function (a_price) {
		price = Number(a_price);
	}
	
	this.setDeposit = function (a_deposit) {
		deposit = Number(a_deposit);
	}
	
	this.setDecliningBalance = function (a_decliningBalance) {
		decliningBalance = Number(a_decliningBalance);
	}
	
	this.setMinDecliningBalance = function (a_minDecliningBalance) {
		minDecliningBalance = Number(a_minDecliningBalance);
	}
	
	this.setMaxDecliningBalance = function (a_maxDecliningBalance) {
		maxDecliningBalance = Number(a_maxDecliningBalance);
	}
	
	this.setStandardDecliningBalance = function (a_standardDecliningBalance) {
		standardDecliningBalance = Number(a_standardDecliningBalance);
	}
	
	this.setNomInterest = function (a_nomInterest) {
		nomInterest = Number(a_nomInterest);
	}
	
	this.setEffInterest = function (a_effInterest) {
		effInterest = Number(a_effInterest);
	}
	
	this.setMarginTaxed = function (a_isMarginTaxed) {
		isMarginTaxed = a_isMarginTaxed;
	}
	
	this.setPPIUnemployment = function (a_hasPPIUnemployment) {
		hasPPIUnemployment = a_hasPPIUnemployment;
	}
	
	this.setPPIDeath = function (a_hasPPIDeath) {
		hasPPIDeath = a_hasPPIDeath;
	}
	
	this.calculate = function(){
		
		if (!checkValues()) {
			handleUndefinedError();
			return;
		}
		if (!checkPrice()) {
			handlePriceError();
			return;
		}
		if (!checkMinRuntime()) {
			handleRuntimeError();
			return;
		}
		if (!checkDeposit()) {
			handleDepositError();
			return;
		}
		if (!checkDecliningBalance()) {
			handleDecliningBalanceError();
			return;
		}
		
		this.rate = Utilities.round(Utilities.inclVAT(getRate()));
		this.rateInclPPI = Utilities.round(getRateInclPPI());
		this.deposit = (deposit == 0) ? Utilities.round(this.rateInclPPI) : Utilities.round(deposit);
		
		_self.fireEvent("success");
	}
	
	this.getStandardDecliningBalance = function () {
		return standardDecliningBalance;
	}
	
	function getRate() {	
		var _price, _interest, _runtime, _firstInterestCharge, _initPrice, pot, numerator, denominator, ApM;
		 
		_price = (isMarginTaxed == true) ? price: Utilities.exclVAT(price);
		_interest = nomInterest / 1200;
				
		if (Utilities.exclVAT(deposit) > 0) {
			_runtime = runtime - 1;
			_firstInterestCharge = (_price - Utilities.exclVAT(deposit)) * (_interest);
			_initPrice = _price - Utilities.exclVAT(deposit) + _firstInterestCharge;
		}
		else {
			_runtime = runtime;
			_initPrice = _price;
		}
		
		pot = Math.pow((1 + _interest), -(_runtime));
		numerator = _initPrice - (Utilities.exclVAT(decliningBalance) * pot);
		denominator = (1 + _interest) * ((1 - pot) / _interest);
		ApM = numerator / denominator;
		return ApM;
	}
	
	function getRateInclPPI() {	
		var ApM, PPIDeath, PPIUnemployment;
		
		ApM = Utilities.inclVAT(getRate());
		PPIDeath  = (hasPPIDeath) ? getPPIDeath(ApM) : 0;
		PPIUnemployment = (hasPPIUnemployment) ? getPPIUnemployment(ApM) : 0;
		ApM += PPIDeath + PPIUnemployment;
		
		return ApM;
	}
	
	function getPPIDeath (a_number) {
		return (a_number >= PPI.getLeasingPPITreshold()) ? PPI.getLeasingPPITreshold() * PPI.getLeasingPPIDeath(): a_number * PPI.getLeasingPPIDeath()
	}
	
	function getPPIUnemployment (a_number) {
		return (a_number >= PPI.getLeasingPPITreshold()) ? PPI.getLeasingPPITreshold() * PPI.getLeasingPPIUnemployment(): a_number * PPI.getLeasingPPIUnemployment ()
	}
	
	//Controlling vars
	function checkValues () {
		var ctrl = true;
		
		if (runtime == undefined || isNaN(runtime)) ctrl = false;
		if (price == undefined || isNaN(price)) ctrl = false;
		if (deposit == undefined || isNaN(deposit)) ctrl = false;
		if (decliningBalance == undefined || isNaN(decliningBalance)) ctrl = false;
		if (nomInterest == undefined || isNaN(nomInterest)) ctrl = false;
		if (hasPPIDeath == undefined) ctrl = false;
		if (hasPPIUnemployment == undefined) ctrl = false;
		if (isMarginTaxed == undefined) ctrl = false;
		
		return ctrl;
	}
	
	function checkMinRuntime () {
		return (runtime >= Settings.getLeasingMinRuntime());
	}
	
	function checkPrice () {
		return (price <= Settings.getLeasingMaxPrice() && price >= Settings.getLeasingMinPrice());
	}
	
	function checkDeposit () {
		return (deposit == 0 || deposit <= price / 2);
	}
	
	function checkDecliningBalance () {
		return (decliningBalance <= maxDecliningBalance && decliningBalance >= minDecliningBalance);
	}
	
	//Error handling, implements Event extension (mootools 1.2)
	function handleRuntimeError () {
		_self.fireEvent("error", "runtime");
	}
	
	function handleDepositError () {
		_self.fireEvent("error", "deposit");
	}
	
	function handleDecliningBalanceError () {
		_self.fireEvent("error", ["decliningBalance", minDecliningBalance, maxDecliningBalance]);
	}
	
	function handlePriceError () {
		_self.fireEvent("error", ["price", Settings.getLeasingMinPrice(), Settings.getLeasingMaxPrice()]);
	}
	
	function handleUndefinedError () {
		_self.fireEvent("error", "undefined");
	}
	
	//Event extension (mootools 1.2)
	$extend(this, new Events());
}




