`;
// Set dashboard content (Spec II.A)
dashboardContent.innerHTML = tableHtml + calculatorHtml;
// Set PDF content (Spec II.C.2 - excludes interactive elements)
pdfOutputContent.innerHTML = `
`;
paramsContainer.appendChild(paramDiv);
paramIndex++;
}
lobDiv.appendChild(paramsContainer);
const addParamBtnDiv = document.createElement("div");
addParamBtnDiv.className = "actuarial-config-add-param-btn";
addParamBtnDiv.innerHTML = ``;
lobDiv.appendChild(addParamBtnDiv);
configContainer.appendChild(lobDiv);
lobIndex++;
}
}
/**
* Saves the data from the config tab back to the actuarialData object
* and reloads the dashboard
*/
window.saveActuarialConfig = function () {
if (!configContainer || !saveMessage) return;
const newActuarialData = {};
const lobDivs = configContainer.querySelectorAll(".actuarial-config-lob");
lobDivs.forEach((lobDiv) => {
const lobNameInput = lobDiv.querySelector(
".actuarial-config-lob-name"
);
if (!lobNameInput) return;
const lobName = lobNameInput.value.trim();
if (!lobName) return;
newActuarialData[lobName] = {};
const paramDivs = lobDiv.querySelectorAll(".actuarial-config-param");
paramDivs.forEach((paramDiv) => {
const keyInput = paramDiv.querySelector(
".actuarial-config-param-key"
);
const valueInput = paramDiv.querySelector(
".actuarial-config-param-value"
);
if (!keyInput || !valueInput) return;
const key = keyInput.value.trim();
const value = parseFloat(valueInput.value);
if (key && !isNaN(value)) {
newActuarialData[lobName][key] = value;
}
});
});
actuarialData = newActuarialData; // Update the global data object
buildDashboard(); // Re-build dashboard (Tab 1)
// Show save message (Spec compliant: No alert())
saveMessage.style.display = "inline";
setTimeout(() => {
saveMessage.style.display = "none";
}, 2000);
showActuarialTab("actuarial-tab-dashboard"); // Switch back to dashboard
};
/**
* Adds a new empty LOB to the config tab
*/
window.addActuarialConfigLOB = function () {
if (!configContainer) return;
const newLobId = `lob-new-${Date.now()}`;
const lobDiv = document.createElement("div");
lobDiv.className = "actuarial-config-lob";
lobDiv.id = newLobId;
lobDiv.innerHTML = `
`;
configContainer.appendChild(lobDiv);
};
/**
* Adds a new empty parameter to a LOB in the config tab
*/
window.addActuarialConfigParam = function (paramsContainerId) {
const paramsContainer = document.getElementById(paramsContainerId);
if (!paramsContainer) return;
const newParamId = `${paramsContainerId}-param-new-${Date.now()}`;
const paramDiv = document.createElement("div");
paramDiv.className = "actuarial-config-param";
paramDiv.id = newParamId;
paramDiv.innerHTML = `
`;
paramsContainer.appendChild(paramDiv);
};
/**
* Removes a DOM element (LOB or param) from the config tab
*/
window.removeActuarialElement = function (elementId) {
const element = document.getElementById(elementId);
if (element && element.parentNode) {
element.parentNode.removeChild(element);
}
};
/**
* Switches the active tab
* (Spec II.B.4)
*/
window.showActuarialTab = function (tabId) {
if (!tabButtons.length || !tabContents.length) return;
tabContents.forEach((content) => {
content.classList.remove("active");
});
tabButtons.forEach((button) => {
button.classList.remove("active");
});
const contentToShow = document.getElementById(tabId);
const buttonToActivate = document.querySelector(
`[onclick="showActuarialTab('${tabId}')"]`
);
if (contentToShow) {
contentToShow.classList.add("active");
}
if (buttonToActivate) {
buttonToActivate.classList.add("active");
}
// Re-build config tab each time it's opened to reflect data
if (tabId === "actuarial-tab-config") {
buildConfig();
}
};
/**
* Navigates between tabs using Next/Previous buttons
* (Spec II.B.4.o)
*/
window.navigateActuarialTabs = function (direction) {
if (!tabButtons.length) return;
let currentIndex = -1;
tabButtons.forEach((button, index) => {
if (button.classList.contains("active")) {
currentIndex = index;
}
});
if (currentIndex === -1) return;
let nextIndex;
if (direction === "next") {
nextIndex = (currentIndex + 1) % tabButtons.length;
} else {
nextIndex =
(currentIndex - 1 + tabButtons.length) % tabButtons.length;
}
// Get the target tabId from the button's onclick attribute
const nextButton = tabButtons[nextIndex];
const onclickAttr = nextButton.getAttribute("onclick");
const tabId = onclickAttr.match(/'([^']*)'/)[1];
if (tabId) {
showActuarialTab(tabId);
}
};
/**
* Downloads the output as a PDF
* (Spec II.C)
*/
function downloadActuarialPDF() {
// Check for required libraries
if (
typeof jspdf === "undefined" ||
typeof html2canvas === "undefined"
) {
console.error(
"Error: PDF generation libraries (jsPDF, html2canvas) not loaded."
);
return;
}
if (!pdfOutputContent || !pdfOutputContent.innerHTML) {
console.error("Error: PDF output element not found or empty.");
return;
}
const { jsPDF } = jspdf;
const pdfOutputElement = document.getElementById(
"actuarial-pdf-output-content"
);
// Temporarily make the element visible for html2canvas
pdfOutputElement.style.display = "block";
pdfOutputElement.style.position = "absolute";
pdfOutputElement.style.left = "-9999px"; // Move off-screen
html2canvas(pdfOutputElement, {
scale: 2, // Improve resolution
useCORS: true,
backgroundColor: "#ffffff",
}).then((canvas) => {
// Hide the element again
pdfOutputElement.style.display = "none";
pdfOutputElement.style.position = "static";
pdfOutputElement.style.left = "0";
const imgData = canvas.toDataURL("image/png");
const pdf = new jsPDF({
orientation: "p",
unit: "px",
format: "a4",
});
const pdfWidth = pdf.internal.pageSize.getWidth();
const pdfHeight = pdf.internal.pageSize.getHeight();
const canvasWidth = canvas.width;
const canvasHeight = canvas.height;
const ratio = canvasWidth / canvasHeight;
const imgWidth = pdfWidth - 40; // Add 20px margin on each side
let imgHeight = imgWidth / ratio;
const pageMargin = 20;
if (imgHeight <= pdfHeight - 2 * pageMargin) {
// Fits on one page
pdf.addImage(
imgData,
"PNG",
pageMargin,
pageMargin,
imgWidth,
imgHeight
);
} else {
// Handle multiple pages
let heightLeft = canvasHeight;
let canvasPosition = 0;
const pageHeightInPixels =
(pdfHeight - 2 * pageMargin) * (canvasWidth / imgWidth);
while (heightLeft > 0.1) {
const pageHeight = Math.min(heightLeft, pageHeightInPixels);
const pageImgHeight = (pageHeight * imgWidth) / canvasWidth;
const tempCanvas = document.createElement("canvas");
tempCanvas.width = canvasWidth;
tempCanvas.height = pageHeight;
const ctx = tempCanvas.getContext("2d");
ctx.drawImage(
canvas,
0, // sx
canvasPosition, // sy
canvasWidth, // sWidth
pageHeight, // sHeight
0, // dx
0, // dy
canvasWidth, // dWidth
pageHeight // dHeight
);
const pageImgData = tempCanvas.toDataURL("image/png");
pdf.addImage(
pageImgData,
"PNG",
pageMargin,
pageMargin,
imgWidth,
pageImgHeight
);
heightLeft -= pageHeight;
canvasPosition += pageHeight;
if (heightLeft > 0.1) {
pdf.addPage();
}
}
}
pdf.save("actuarial-parameters.pdf");
});
}
// --- Initialization ---
if (pdfDownloadBtn) {
pdfDownloadBtn.addEventListener("click", downloadActuarialPDF);
}
buildDashboard();
buildConfig();
// Show the first tab by default
showActuarialTab("actuarial-tab-dashboard");
});
