forecast = function(renewals, year) {
if (!Array.isArray(renewals)) return 0;
renewals = renewals.filter((r) => {
return typeof r.year === 'number' && typeof r.cost === 'number';
});
if (typeof forecastOptions.lookbackYears == 'number' && forecastOptions.lookbackYears > 0) {
renewals = renewals.slice((forecastOptions.lookbackYears * -1))
}
if (forecastOptions.ignoreExpectedUplift) {
renewals.forEach((r) => { delete r.expectedUplift; });
}
if (renewals.length < 1) {
return 0;
} else if (renewals.length == 1 || typeof renewals[renewals.length - 1].expectedUplift !== 'undefined') {
let index = renewals.length - 1;
let m = (1.0 + renewals[index].expectedUplift ? renewals[index].expectedUplift : 0) * renewals[index].cost;
let x = year - renewals[index].year;
let b = renewals[index].cost;
return (m * x) + b;
} else {
let totalYear = 0;
let totalCost = 0;
renewals.forEach((r) => { totalYear += r.year; });
var avgYear = totalYear / renewals.length;
renewals.forEach((r) => { totalCost += r.cost; });
var avgCost = totalCost / renewals.length;
let numerator = 0;
let denominator = 0;
renewals.forEach((r) => {
numerator += (r.year - avgYear) * (r.cost - avgCost);
denominator += (r.year - avgYear) * (r.year - avgYear);
});
var slope = numerator / denominator;
if (Number.isNaN(slope)) slope = 0;
var yIntercept = avgCost - (slope * avgYear);
var cost = slope * year + yIntercept;
if (!forecastOptions.predictDecreases) {
if (cost < (renewals[renewals.length - 1].cost - forecastOptions.decreaseLimit)) {
return renewals[renewals.length - 1].cost - forecastOptions.decreaseLimit;
}
}
return cost;
}
}