@plotinus/matrix-package-calculator
Version:
Calculator components for the Matrix framework - basic arithmetic operations with UI
176 lines (175 loc) • 7.38 kB
JavaScript
import { BaseCommunicationComponent } from '@matrix/framework';
import { logInfo, logDebug } from '@matrix/logger';
export class CalculatorComponent extends BaseCommunicationComponent {
constructor() {
super(...arguments);
this.calculatorState = {
display: '0',
currentValue: 0,
previousValue: null,
pendingOperation: null,
waitingForNewValue: false,
history: []
};
}
onInit() {
logInfo(`Calculator:${this.id}: Initialized with clean state.`);
this.setState(this.calculatorState);
}
startExecution() {
logInfo(`Calculator:${this.id}: Starting execution. Calculator is ready.`);
this.emitEvent('CalculatorReady', { calculatorId: this.id });
}
// DSL binding: onCalculate="calculateHandler"
calculateHandler(calculation) {
logInfo(`Calculator:${this.id}: Received calculate command.`);
logDebug(`Calculator:${this.id}: Calculation details`, calculation);
const result = this.performCalculation(calculation);
this.setState(this.calculatorState);
logInfo(`Calculator:${this.id}: Calculation completed. Result: ${this.calculatorState.display}`);
this.emitEvent('CalculationComplete', {
calculatorId: this.id,
calculation,
result: this.calculatorState.display,
state: { ...this.calculatorState }
});
return result;
}
// DSL binding: onNumberInput="numberInputHandler"
numberInputHandler(data) {
logInfo(`Calculator:${this.id}: Number input received: ${data.digit}`);
if (this.calculatorState.waitingForNewValue) {
this.calculatorState.display = data.digit.toString();
this.calculatorState.currentValue = data.digit;
this.calculatorState.waitingForNewValue = false;
}
else {
if (this.calculatorState.display === '0') {
this.calculatorState.display = data.digit.toString();
}
else {
this.calculatorState.display += data.digit.toString();
}
this.calculatorState.currentValue = parseFloat(this.calculatorState.display);
}
this.setState(this.calculatorState);
this.emitEvent('DisplayUpdated', {
calculatorId: this.id,
display: this.calculatorState.display,
value: this.calculatorState.currentValue
});
}
// DSL binding: onOperation="operationHandler"
operationHandler(data) {
logInfo(`Calculator:${this.id}: Operation received: ${data.operation}`);
if (this.calculatorState.pendingOperation && !this.calculatorState.waitingForNewValue) {
// Complete pending operation first
const calculation = {
id: `calc-${Date.now()}`,
operation: this.calculatorState.pendingOperation,
operand: this.calculatorState.currentValue,
timestamp: Date.now()
};
this.performCalculation(calculation);
}
else {
this.calculatorState.previousValue = this.calculatorState.currentValue;
}
this.calculatorState.pendingOperation = data.operation;
this.calculatorState.waitingForNewValue = true;
this.setState(this.calculatorState);
this.emitEvent('OperationSet', {
calculatorId: this.id,
operation: data.operation,
display: this.calculatorState.display
});
}
// DSL binding: onEquals="equalsHandler"
equalsHandler() {
logInfo(`Calculator:${this.id}: Equals operation received`);
if (this.calculatorState.pendingOperation && this.calculatorState.previousValue !== null) {
const calculation = {
id: `calc-${Date.now()}`,
operation: this.calculatorState.pendingOperation,
operand: this.calculatorState.currentValue,
timestamp: Date.now()
};
this.performCalculation(calculation);
this.calculatorState.pendingOperation = null;
this.calculatorState.previousValue = null;
this.calculatorState.waitingForNewValue = true;
this.setState(this.calculatorState);
this.emitEvent('EqualsComplete', {
calculatorId: this.id,
result: this.calculatorState.display
});
}
}
// DSL binding: onClear="clearHandler"
clearHandler() {
logInfo(`Calculator:${this.id}: Clear operation received`);
this.calculatorState = {
display: '0',
currentValue: 0,
previousValue: null,
pendingOperation: null,
waitingForNewValue: false,
history: [...this.calculatorState.history] // Keep history but reset everything else
};
const clearCalculation = {
id: `clear-${Date.now()}`,
operation: 'clear',
timestamp: Date.now()
};
this.calculatorState.history.push(clearCalculation);
this.setState(this.calculatorState);
this.emitEvent('CalculatorCleared', {
calculatorId: this.id,
display: this.calculatorState.display
});
}
performCalculation(calculation) {
let result = this.calculatorState.currentValue;
if (this.calculatorState.previousValue !== null && calculation.operand !== undefined) {
switch (calculation.operation) {
case 'add':
result = this.calculatorState.previousValue + calculation.operand;
break;
case 'subtract':
result = this.calculatorState.previousValue - calculation.operand;
break;
case 'multiply':
result = this.calculatorState.previousValue * calculation.operand;
break;
case 'divide':
if (calculation.operand === 0) {
logInfo(`Calculator:${this.id}: Division by zero attempted`);
this.calculatorState.display = 'Error';
this.emitEvent('CalculationError', {
calculatorId: this.id,
error: 'Division by zero',
calculation
});
return this.calculatorState.currentValue;
}
result = this.calculatorState.previousValue / calculation.operand;
break;
}
}
// Update state
this.calculatorState.currentValue = result;
this.calculatorState.display = result.toString();
this.calculatorState.history.push(calculation);
logDebug(`Calculator:${this.id}: Calculation result`, { calculation, result });
return result;
}
// Method to get calculation history - useful for external queries
getHistory() {
return [...this.calculatorState.history];
}
// Method to get current state - useful for external queries
getCurrentState() {
return { ...this.calculatorState };
}
}
CalculatorComponent.dslTag = 'calculator-definition';