`;
if (loanPreview.active && estimatedLoanNeeded > 0) {
summaryHTML += `
Loan Repayment Preview (for Estimated Loan Amount)
Assumed Loan Interest Rate: ${sablt_formatPercent(loanPreview.interestRate,2)}
Assumed Loan Term: ${loanPreview.termYears} years
Estimated Monthly Payment: ${sablt_formatCurrency(loanPreview.monthlyPayment)}
Estimated Total Interest Paid: ${sablt_formatCurrency(loanPreview.totalInterest)}
Estimated Total Repayment: ${sablt_formatCurrency(loanPreview.totalRepaid)}
`;
}
summaryHTML += `
Remember: This is an estimated budget. Actual costs can vary. Research specific costs for your chosen program and destination thoroughly. Look for additional scholarships or funding opportunities to minimize borrowing.
`;
sablt_domElements.resultsContainer.innerHTML = summaryHTML;
if (sablt_domElements.pdfDownloadBtn) {
sablt_domElements.pdfDownloadBtn.classList.remove('sablt-hidden');
}
}
function sablt_hexToRgb(hex) {
if (!hex || typeof hex !== 'string') return null;
const shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i;
hex = hex.replace(shorthandRegex, function(m, r, g, b) { return r + r + g + g + b + b; });
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
return result ? { r: parseInt(result[1], 16), g: parseInt(result[2], 16), b: parseInt(result[3], 16) } : null;
}
function sablt_generatePdf() {
if (typeof window.jspdf === 'undefined' || typeof window.jspdf.jsPDF === 'undefined' || typeof window.jspdf.jsPDF.API === 'undefined' || typeof window.jspdf.jsPDF.API.autoTable === 'undefined') {
alert("PDF generation library is not loaded. Please try again later."); return;
}
if (!sablt_validateTab1() || !sablt_validateTab2() || !sablt_validateTab3()) {
alert("Please ensure all inputs are correctly filled before generating PDF.");
// Try to navigate to the first invalid tab
if (!sablt_validateTab1()) sablt_navigateToTab('sablt-tab1');
else if (!sablt_validateTab2()) sablt_navigateToTab('sablt-tab2');
else if (!sablt_validateTab3()) sablt_navigateToTab('sablt-tab3');
return;
}
sablt_calculateAndDisplaySummary();
if (sablt_domElements.resultsContainer && sablt_domElements.resultsContainer.innerHTML.includes("sablt-error-message")) {
alert("Cannot generate PDF due to errors in input or calculation. Please correct them."); return;
}
const ActualJsPDF = window.jspdf.jsPDF;
const doc = new ActualJsPDF();
const { coreCosts, livingTravelCosts, totalExpenses, availableFunds, estimatedLoanNeeded, loanPreview, programDurationMonths, destinationCountry } = sablt_budget;
doc.setFontSize(18);
const primaryColorRGB = sablt_hexToRgb(getComputedStyle(document.documentElement).getPropertyValue('--sablt-primary-color').trim()) || {r:0,g:121,b:107};
const secondaryColorRGB = sablt_hexToRgb(getComputedStyle(document.documentElement).getPropertyValue('--sablt-secondary-color').trim()) || {r:0,g:77,b:64};
const accentColorRGB = sablt_hexToRgb(getComputedStyle(document.documentElement).getPropertyValue('--sablt-accent-color').trim()) || {r:255,g:143,b:0};
doc.setTextColor(primaryColorRGB.r, primaryColorRGB.g, primaryColorRGB.b);
doc.text("Study Abroad Budget Summary", 105, 20, null, null, "center");
doc.setFontSize(10);
doc.setTextColor(38,50,56);
let startY = 30;
doc.text(`Destination: ${destinationCountry || 'Not Specified'} | Program Duration: ${programDurationMonths > 0 ? programDurationMonths + ' months' : 'N/A'}`, 14, startY);
startY += 10;
const tableHeadFillColor = [secondaryColorRGB.r, secondaryColorRGB.g, secondaryColorRGB.b];
const bodyStyles = { fontSize: 9, cellPadding: 2 };
const headStyles = { fillColor: tableHeadFillColor, textColor: 255, fontSize: 9.5, fontStyle: 'bold', cellPadding: 2.5 };
const boldStyle = { fontStyle: 'bold' };
doc.setFontSize(12);
doc.setTextColor(secondaryColorRGB.r, secondaryColorRGB.g, secondaryColorRGB.b);
doc.text("Estimated Expenses (Total for Program)", 14, startY); startY += 6;
const expenseBody = [
["Tuition Fees:", sablt_formatCurrency(coreCosts.tuition)],
["Other Program Fees:", sablt_formatCurrency(coreCosts.program)],
["Books & Supplies:", sablt_formatCurrency(coreCosts.books)],
[{content: "Subtotal Core Costs:", styles: boldStyle}, {content: sablt_formatCurrency(coreCosts.total), styles: boldStyle}],
["Accommodation:", sablt_formatCurrency(livingTravelCosts.accommodation)],
["Food & Groceries:", sablt_formatCurrency(livingTravelCosts.food)],
["Local Transportation:", sablt_formatCurrency(livingTravelCosts.localTransport)],
["Utilities:", sablt_formatCurrency(livingTravelCosts.utilities)],
["Health Insurance:", sablt_formatCurrency(livingTravelCosts.healthInsurance)],
["Round-trip Airfare:", sablt_formatCurrency(livingTravelCosts.airfare)],
["Visa & Related Costs:", sablt_formatCurrency(livingTravelCosts.visa)],
["Initial Setup & Personal Spending:", sablt_formatCurrency(livingTravelCosts.personalSetupSpending)],
[{content: "Subtotal Living & Travel:", styles: boldStyle}, {content: sablt_formatCurrency(livingTravelCosts.total), styles: boldStyle}],
[{content: "TOTAL ESTIMATED EXPENSES:", styles: {fontStyle:'bold', fillColor: [236,239,241]}}, {content: sablt_formatCurrency(totalExpenses), styles: {fontStyle:'bold', fillColor: [236,239,241]}}],
];
doc.autoTable({ startY: startY, body: expenseBody, theme: 'grid', styles: bodyStyles, headStyles: headStyles, columnStyles: {0:{fontStyle:'bold', cellWidth: 80}, 1:{halign:'right', cellWidth: 'auto'}} });
startY = doc.autoTable.previous.finalY + 10;
doc.setFontSize(12); doc.setTextColor(secondaryColorRGB.r, secondaryColorRGB.g, secondaryColorRGB.b);
doc.text("Available Funds & Loan Estimation", 14, startY); startY += 6;
const fundingBody = [
["Personal Savings:", sablt_formatCurrency(availableFunds.savings)],
["Scholarships/Grants:", sablt_formatCurrency(availableFunds.scholarships)],
["Family Contributions:", sablt_formatCurrency(availableFunds.family)],
[{content: "Total Available Funds:", styles: boldStyle}, {content: sablt_formatCurrency(availableFunds.total), styles: {fontStyle:'bold', textColor: [primaryColorRGB.r, primaryColorRGB.g, primaryColorRGB.b]}}],
[{content: "ESTIMATED LOAN AMOUNT NEEDED:", styles: {fontStyle:'bold', fillColor: [236,239,241]}}, {content: sablt_formatCurrency(estimatedLoanNeeded), styles: {fontStyle:'bold', textColor: [accentColorRGB.r, accentColorRGB.g, accentColorRGB.b], fillColor: [236,239,241]}}],
];
if (estimatedLoanNeeded <= 0) {
fundingBody.push([{content: "Your available funds appear to cover your estimated expenses.", colSpan:2, styles: {halign:'center', textColor: [primaryColorRGB.r, primaryColorRGB.g, primaryColorRGB.b]}}]);
}
doc.autoTable({ startY: startY, body: fundingBody, theme: 'grid', styles: bodyStyles, headStyles: headStyles, columnStyles: {0:{fontStyle:'bold', cellWidth: 80}, 1:{halign:'right'}} });
startY = doc.autoTable.previous.finalY + 10;
if (loanPreview.active && estimatedLoanNeeded > 0) {
doc.setFontSize(12); doc.setTextColor(secondaryColorRGB.r, secondaryColorRGB.g, secondaryColorRGB.b);
doc.text("Loan Repayment Preview (for Estimated Loan Amount)", 14, startY); startY += 6;
doc.autoTable({
startY: startY, theme: 'grid', styles: bodyStyles, headStyles: headStyles,
body: [
["Assumed Loan Interest Rate:", sablt_formatPercent(loanPreview.interestRate,2)],
["Assumed Loan Term:", `${loanPreview.termYears} years`],
["Estimated Monthly Payment:", sablt_formatCurrency(loanPreview.monthlyPayment)],
["Estimated Total Interest Paid:", sablt_formatCurrency(loanPreview.totalInterest)],
["Estimated Total Repayment:", sablt_formatCurrency(loanPreview.totalRepaid)],
], margin: { left: 14, right: 14 }, columnStyles: {0:{fontStyle:'bold', cellWidth: 80}, 1:{halign:'right'}}
});
startY = doc.autoTable.previous.finalY + 10;
}
doc.setFontSize(9);
doc.setTextColor(100);
const note = "This is an estimated budget. Actual costs can vary. Research specific costs for your chosen program and destination thoroughly. Look for additional scholarships or funding opportunities to minimize borrowing.";
const splitNote = doc.splitTextToSize(note, doc.internal.pageSize.width - 28);
doc.text(splitNote, 14, startY);
startY += (splitNote.length * (doc.getLineHeight() / doc.internal.scaleFactor * 0.8)) + 5;
doc.setFontSize(9);
doc.setTextColor(150);
doc.text(`Report generated on: ${new Date().toLocaleDateString()} ${new Date().toLocaleTimeString()}`, 14, doc.internal.pageSize.height - 10);
doc.save("Study_Abroad_Budget_Estimate.pdf");
}
window.sablt_switchTab = sablt_switchTab;
window.sablt_navigateToTab = sablt_navigateToTab;
window.sablt_generatePdf = sablt_generatePdf;
// Expose update functions if needed, though listeners handle most dynamic updates internally
window.sablt_updateTotalLivingTravelDisplay = sablt_updateTotalLivingTravelDisplay;
window.sablt_updateFundingSummaryAndLoanPreview = sablt_updateFundingSummaryAndLoanPreview;