// Imports
import { generateUUID, htmlOlCommandsOperations } from "./../../main";
import {
getOperationTypeByValue,
getOperatorByHash,
getOperatorTypeByValue,
htmlAssignVariableScheme,
htmlOperationKindScheme,
htmlOperationTypeSelect,
htmlOperatorValueInputScheme,
htmlOperatorVariablesSelectScheme,
operationScheme,
Operators,
operatorScheme,
printOperationScheme,
} from "./operations-schemes";
import { getVariableByHash, variables } from "../variables/variables";
// Imports
export const operations = [];
// Creating operation
export function createOperation() {
let operation = Object.assign({}, operationScheme);
operation.hash = generateUUID().replaceAll("-", "");
// TODO: Fix
operation.assignedVariable = variables[0];
operation.operators = [];
operations.push(operation);
let htmlOperation = htmlAssignVariableScheme();
htmlOperation = htmlOperation.replaceAll("", operation.hash);
htmlOlCommandsOperations.insertAdjacentHTML("beforeend", htmlOperation);
document
.getElementById(`operation${operation.hash}AssignVariableSelect`)
.addEventListener("change", (ev) => {
updateOperationAssignValue(
ev.target.getAttribute("operation-id"),
ev.target.value
);
});
document
.getElementById(`operation${operation.hash}Delete`)
.addEventListener("click", (ev) => {
deleteOperation(ev.target.getAttribute("operation-id"));
});
document
.getElementById(`operation${operation.hash}Resume`)
.addEventListener("focus", (ev) => {
const operationHash = ev.target.getAttribute("operation-id");
manageOperationEditing(operationHash);
});
document
.getElementById(`operation${operation.hash}Display`)
.addEventListener("keyup", (ev) => {
const operationHash = ev.target.getAttribute("operation-id");
if (ev.key === "Enter") manageOperationEditing(operationHash, true);
});
addOperatorKind(operation.hash);
updateResume(operation.hash);
// Changing focus to the variable type after creation for screen readers
document
.getElementById(`operation${operation.hash}AssignVariableSelect`)
.focus();
}
// Add operator kind to the operation
export function addOperatorKind(hash) {
let operation = getOperationByHash(hash);
console.log(operation);
let htmlOperationKind = htmlOperationKindScheme(operation);
document
.getElementById(`operation${operation.hash}OperatorsDiv`)
.insertAdjacentHTML("beforeend", htmlOperationKind);
document
.getElementById(`operation${operation.hash}KindSelect`)
.addEventListener("focusout", (ev) => {
selectedOperationKind(ev.target.getAttribute("operation-id"));
ev.target.parentElement.remove();
});
}
// Function to be trigger when the operator kind is selected
export function selectedOperationKind(operationHash) {
let operation = getOperationByHash(operationHash);
console.log(operation);
let kindSelect = document.getElementById(
`operation${operation.hash}KindSelect`
);
// TODO: think into an way to make this dynamic
if (kindSelect.value === "VARIABLE") {
insertVariableAfterOperationKind(kindSelect, operation);
} else if (kindSelect.value === "VALUE") {
insertValueAfterOperationKind(kindSelect, operation);
}
}
// Insert variable after operator kind select
export function insertVariableAfterOperationKind(kindSelect, operation) {
let operator = Object.assign({}, operatorScheme);
operator.hash = generateUUID().replaceAll("-", "");
// TODO: Fix ?
operator.variable = variables[0];
operator.type = getOperatorTypeByValue("VARIABLE");
let operatorVariableSelect = htmlOperatorVariablesSelectScheme(
operation,
operator
);
operation.operators.push(operator);
kindSelect.parentElement.parentElement.insertAdjacentHTML(
"beforeend",
operatorVariableSelect
);
insertOperationTypeAtEndOfOperation(operation, operator);
document
.getElementById(
`operation${operation.hash}Operator${operator.hash}VariableSelect`
)
.addEventListener("change", (ev) => {
updateOperationOperator(
ev.target.getAttribute("operation-id"),
ev.target.getAttribute("operator-id"),
ev.target.value
);
});
updateResume(operation.hash);
// Changing focus to the variable select after select for screen readers
document
.getElementById(
`operation${operation.hash}Operator${operator.hash}VariableSelect`
)
.focus();
}
// Insert value after operator kind select
export function insertValueAfterOperationKind(kindSelect, operation) {
let operator = Object.assign({}, operatorScheme);
operator.hash = generateUUID().replaceAll("-", "");
operator.type = getOperatorTypeByValue("VALUE");
let operatorValueInput = htmlOperatorValueInputScheme(operation, operator);
operation.operators.push(operator);
kindSelect.parentElement.parentElement.insertAdjacentHTML(
"beforeend",
operatorValueInput
);
kindSelect.parentElement.remove();
insertOperationTypeAtEndOfOperation(operation, operator);
document
.getElementById(
`operation${operation.hash}Operator${operator.hash}ValueInput`
)
.addEventListener("change", (ev) => {
updateOperationOperator(
ev.target.getAttribute("operation-id"),
ev.target.getAttribute("operator-id"),
ev.target.value
);
});
updateResume(operation.hash);
// Changing focus to the input value after select for screen readers
document
.getElementById(
`operation${operation.hash}Operator${operator.hash}ValueInput`
)
.focus();
}
// Add final operation type end of the operation
export function insertOperationTypeAtEndOfOperation(operation, afterOperator) {
let operator = Object.assign({}, operatorScheme);
operator.hash = generateUUID().replaceAll("-", "");
operator.type = getOperatorTypeByValue("OPERATOR");
operator.operator = getOperationTypeByValue("SEMICOLON");
let operationTypeInput = htmlOperationTypeSelect(operation, operator);
operationTypeInput.replaceAll("", operator.hash);
operation.operators.push(operator);
if (afterOperator.type.value === "VARIABLE") {
document
.querySelector(`select[operator-id='${afterOperator.hash}']`)
.parentElement.insertAdjacentHTML("afterend", operationTypeInput);
} else if (afterOperator.type.value === "VALUE") {
document
.querySelector(`input[operator-id='${afterOperator.hash}']`)
.parentElement.insertAdjacentHTML("afterend", operationTypeInput);
}
document
.getElementById(
`operation${operation.hash}Operator${operator.hash}OperationTypeSelect`
)
.addEventListener("change", (ev) => {
updateOperationOperator(
ev.target.getAttribute("operation-id"),
ev.target.getAttribute("operator-id"),
ev.target.value
);
});
}
// ***********************************************************************
// Listeners
// ***********************************************************************
export function updateOperationAssignValue(operationHash, newVariable) {
let operation = getOperationByHash(operationHash);
let variable = getVariableByHash(newVariable);
operation.assignedVariable = variable;
updateResume(operation.hash);
}
export function updateOperationOperator(operationHash, operatorHash, newValue) {
let operation = getOperationByHash(operationHash);
let operator = getOperatorByHash(operation, operatorHash);
switch (operator.type.value) {
case "VARIABLE":
let variable = getVariableByHash(newValue);
operator.variable = variable;
break;
case "VALUE":
operator.value = newValue;
break;
case "OPERATOR":
operator.operator = getOperationTypeByValue(newValue);
const operationTypeSelect = document.getElementById(
`operation${operation.hash}Operator${operator.hash}OperationTypeSelect`
);
// If the operator isn't a semicolumn, it is the last item on the operator list and teh next elemtn is equal to null,
// we need to add a new operator select
if (
operator.operator.name !== ";" &&
operation.operators.indexOf(operator) ===
operation.operators.length - 1 &&
operationTypeSelect.parentElement.nextElementSibling == null
)
addOperatorKind(operation.hash);
else if (
operator.operator.name === ";" &&
operation.operators.indexOf(operator) ===
operation.operators.length - 1 &&
operationTypeSelect.parentElement.nextElementSibling != null
)
operationTypeSelect.parentElement.nextElementSibling.remove();
else if (
operator.operator.name === ";" &&
operation.operators.indexOf(operator) !==
operation.operators.length - 1 &&
operationTypeSelect.parentElement.nextElementSibling != null
) {
let indexOfOperator = operation.operators.indexOf(operator) + 1;
operation.operators.splice(indexOfOperator);
let elementSibling =
operationTypeSelect.parentElement.nextElementSibling;
let nextElementSibling =
operationTypeSelect.parentElement.nextElementSibling;
while (nextElementSibling != null) {
nextElementSibling = elementSibling.nextElementSibling;
elementSibling.remove();
elementSibling = nextElementSibling;
}
}
break;
}
updateResume(operation.hash);
}
// Here we remove all operation that include the variable received as parameter
export function deleteOperationByVariable(variable) {
const operationsToRemove = [];
for (const i in operations) {
console.log(operations[i]);
if (operations[i].assignedVariable.hash === variable.hash) {
document.getElementById(`operation${operations[i].hash}Li`).remove();
operationsToRemove.push(operations[i]);
continue;
}
for (const j in operations[i].operators) {
console.log(j);
console.log(operations[i].operators[j]);
if (operations[i].operators[j].type.value === Operators.VARIABLE) {
if (operations[i].operators[j].variable.hash === variable.hash) {
document.getElementById(`operation${operations[i].hash}Li`).remove();
operationsToRemove.push(operations[i]);
// if (operation.operators.length > 2) {
//
// } else {
//
// }
}
}
}
}
for (const i in operationsToRemove) {
operations.splice(operations.indexOf(operationsToRemove[i]), 1);
}
}
// Here we remove all operation that include the variable received as parameter
export function deleteOperation(hash) {
const operation = getOperationByHash(hash);
document.getElementById(`operation${hash}Li`).remove();
operations.splice(operations.indexOf(operation), 1);
}
// Here we remove all operation
export function deleteAllOperation() {
for (let i = 0; i < operations.length; i++) {
document.getElementById(`operation${operations[i].hash}Li`).remove();
}
operations.length = 0;
}
// ***********************************************************************
// Managing operation editing
// ***********************************************************************
const manageOperationEditing = (hash, enableForEditing = false) => {
const operation = getOperationByHash(hash);
const operationForm = document.getElementById(
`operation${operation.hash}Form`
);
switch (operation.type) {
case "ASSIGN":
if (operation.editing && !enableForEditing) {
// Editing fields
operationForm.childNodes[1].childNodes[1].style.display = "none";
operationForm.childNodes[1].childNodes[3].style.display = "none";
operationForm.childNodes[1].childNodes[5].style.display = "none";
// Resume field
operationForm.childNodes[1].childNodes[7].style.display = "inline";
operation.editing = false;
} else if (enableForEditing) {
// Editing fields
operationForm.childNodes[1].childNodes[1].style.display = "inline";
operationForm.childNodes[1].childNodes[3].style.display = "inline";
operationForm.childNodes[1].childNodes[5].style.display = "inline";
// Resume field
operationForm.childNodes[1].childNodes[7].style.display = "none";
// Changing focus to firt child
document
.getElementById(`operation${operation.hash}AssignVariableSelect`)
.focus();
operation.editing = true;
}
break;
case "PRINT":
if (operation.editing && !enableForEditing) {
// Editing fields
operationForm.childNodes[1].childNodes[1].style.display = "none";
operationForm.childNodes[1].childNodes[3].style.display = "none";
// Resume field
operationForm.childNodes[1].childNodes[5].style.display = "inline";
operation.editing = false;
} else if (enableForEditing) {
// Editing fields
operationForm.childNodes[1].childNodes[1].style.display = "inline";
operationForm.childNodes[1].childNodes[3].style.display = "inline";
// Resume field
operationForm.childNodes[1].childNodes[5].style.display = "none";
// Changing focus to firt child
document
.getElementById(`operation${operation.hash}VariableSelectLabel`)
.focus();
operation.editing = true;
}
break;
}
};
// ***********************************************************************
// Updating variable resume
// ***********************************************************************
function updateResume(hash) {
const resume = generateResume(hash);
document.getElementById(`operation${hash}DisplayCode`).innerText =
resume.display;
document
.getElementById(`operation${hash}Resume`)
.setAttribute("title", resume.resume);
}
function generateResume(hash) {
const operation = getOperationByHash(hash);
let resume;
let display;
switch (operation.type) {
case "ASSIGN":
resume = `${operation.assignedVariable.name}, recebe: `;
display = `${operation.assignedVariable.name} <- `;
for (const i in operation.operators) {
console.log(operation.operators[i]);
switch (operation.operators[i].type.value) {
case Operators.OPERATOR:
resume += `${operation.operators[i].operator.friendlyName} `;
display += `${operation.operators[i].operator.name} `;
break;
case Operators.VALUE:
resume += `${operation.operators[i].value} `;
display += `${operation.operators[i].value} `;
break;
case Operators.VARIABLE:
resume += `${operation.operators[i].variable.name} `;
display += `${operation.operators[i].variable.name} `;
break;
}
}
break;
case "PRINT":
resume = `Escreva a variável: ${operation.assignedVariable.name}`;
display = `escreva (${operation.assignedVariable.name});`;
break;
}
return { resume: resume, display: display };
}
// ***********************************************************************
// Print
// ***********************************************************************
export function createPrintOperation() {
const operation = Object.assign({}, operationScheme);
operation.hash = generateUUID().replaceAll("-", "");
operation.assignedVariable = variables.length > 0 ? variables[0] : null;
operation.type = "PRINT";
operations.push(operation);
const printOperation = printOperationScheme(operation);
htmlOlCommandsOperations.insertAdjacentHTML("beforeend", printOperation);
updateResume(operation.hash);
// Changing focus to the variable type after creation for screen readers
document
.getElementById(`operation${operation.hash}VariableSelectLabel`)
.focus();
document
.getElementById(`operation${operation.hash}VariableSelect`)
.addEventListener("change", (ev) => {
updatePrintOperation(
ev.target.getAttribute("operation-id"),
ev.target.value
);
});
document
.getElementById(`operation${operation.hash}Delete`)
.addEventListener("click", (ev) => {
deleteOperation(ev.target.getAttribute("operation-id"));
});
document
.getElementById(`operation${operation.hash}Resume`)
.addEventListener("focus", (ev) => {
const operationHash = ev.target.getAttribute("operation-id");
manageOperationEditing(operationHash);
});
document
.getElementById(`operation${operation.hash}Display`)
.addEventListener("keyup", (ev) => {
const operationHash = ev.target.getAttribute("operation-id");
if (ev.key === "Enter") manageOperationEditing(operationHash, true);
});
}
// TODO:
// terminal => basico
function updatePrintOperation(hash, newValue) {
const operation = getOperationByHash(hash);
const variable = getVariableByHash(newValue);
operation.assignedVariable = variable;
updateResume(operation.hash);
}
// ***********************************************************************
// Util
// ***********************************************************************
export function getOperationByHash(hash) {
for (let i = 0; i < operations.length; i++) {
if (operations[i].hash === hash) return operations[i];
}
return null;
}
// ***********************************************************************