import { PropositionalFormula } from '../../../types.js';
import { TruthTableFormatter } from './TruthTableFormatter.js';
/**
* HTML renderer for truth tables
* Handles HTML-specific formatting and styling
*/
export class TruthTableHTMLRenderer {
private formatter: TruthTableFormatter;
constructor() {
this.formatter = new TruthTableFormatter();
}
/**
* Render a truth table as HTML
* @param variables Variable names
* @param formulas Propositional formulas
* @param assignments Variable assignments
* @param results Evaluation results
* @param isArgument Whether this is an argument
* @param isArgumentValid Whether the argument is valid (if applicable)
* @returns HTML string
*/
render(
variables: string[],
formulas: PropositionalFormula[],
assignments: Map<string, boolean>[],
results: boolean[][],
isArgument: boolean,
isArgumentValid?: boolean
): string {
let html = '<div class="truth-table-container">\n';
html += '<table class="truth-table">\n';
// Add header
html += this.renderHeader(variables, formulas, isArgument);
// Add body
html += this.renderBody(variables, assignments, results, isArgument);
// Add footer for arguments
if (isArgument && isArgumentValid !== undefined) {
html += this.renderFooter(variables.length + formulas.length, isArgumentValid);
}
html += '</table>\n';
html += this.renderStyles();
html += '</div>';
return html;
}
private renderHeader(
variables: string[],
formulas: PropositionalFormula[],
isArgument: boolean
): string {
let html = '<thead>\n<tr>\n';
// Variable columns
variables.forEach(variable => {
html += `<th class="variable">${variable}</th>\n`;
});
// Formula columns
formulas.forEach((formula, index) => {
const isConclusion = isArgument && index === formulas.length - 1;
const formulaClass = isConclusion ? 'conclusion' : 'premise';
html += `<th class="formula ${formulaClass}">${this.formatter.formatFormula(formula)}</th>\n`;
});
// Validity column for arguments
if (isArgument) {
html += '<th class="validity">Valid?</th>\n';
}
html += '</tr>\n</thead>\n';
return html;
}
private renderBody(
variables: string[],
assignments: Map<string, boolean>[],
results: boolean[][],
isArgument: boolean
): string {
let html = '<tbody>\n';
assignments.forEach((assignment, rowIndex) => {
html += '<tr>\n';
// Variable values
variables.forEach(variable => {
const value = assignment.get(variable);
html += `<td class="value">${this.formatter.formatBoolean(value!)}</td>\n`;
});
// Formula results
const rowResults = results[rowIndex];
rowResults.forEach((result, colIndex) => {
const isConclusion = isArgument && colIndex === rowResults.length - 1;
const resultClass = isConclusion ? 'conclusion' : 'premise';
html += `<td class="result ${resultClass}">${this.formatter.formatBoolean(result)}</td>\n`;
});
// Validity cell for arguments
if (isArgument) {
const allPremisesTrue = rowResults.slice(0, -1).every(result => result);
const conclusionFalse = !rowResults[rowResults.length - 1];
const isCounterexample = allPremisesTrue && conclusionFalse;
const validityClass = isCounterexample ? 'invalid' : 'valid';
const validityText = this.formatter.formatValidity(!isCounterexample, 'html');
html += `<td class="validity ${validityClass}">${validityText}</td>\n`;
}
html += '</tr>\n';
});
html += '</tbody>\n';
return html;
}
private renderFooter(colspan: number, isValid: boolean): string {
return `
<tfoot>
<tr>
<td colspan="${colspan}" class="analysis">
<span class="${isValid ? 'valid' : 'invalid'}">
This argument is ${isValid ? 'VALID' : 'INVALID'}
</span>
</td>
<td class="validity ${isValid ? 'valid' : 'invalid'}">
${this.formatter.formatValidity(isValid, 'html')}
</td>
</tr>
</tfoot>
`;
}
private renderStyles(): string {
return `
<style>
.truth-table-container {
font-family: Arial, sans-serif;
margin: 20px 0;
}
.truth-table {
border-collapse: collapse;
width: 100%;
text-align: center;
}
.truth-table th, .truth-table td {
border: 1px solid #ddd;
padding: 8px;
}
.truth-table th {
background-color: #f2f2f2;
font-weight: bold;
}
.truth-table th.formula {
background-color: #e6f3ff;
}
.truth-table th.conclusion {
background-color: #ffe6e6;
}
.truth-table td.result {
font-weight: bold;
}
.truth-table td.result.premise {
background-color: #f0f8ff;
}
.truth-table td.result.conclusion {
background-color: #fff0f0;
}
.truth-table td.validity.valid {
background-color: #e6ffe6;
color: green;
font-weight: bold;
}
.truth-table td.validity.invalid {
background-color: #ffe6e6;
color: red;
font-weight: bold;
}
.truth-table tfoot td {
text-align: right;
font-weight: bold;
}
.truth-table .analysis .valid {
color: green;
}
.truth-table .analysis .invalid {
color: red;
}
</style>
`;
}
}