@gebrai/gebrai
Version:
Model Context Protocol server for GeoGebra mathematical visualization
732 lines • 29.4 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.MockGeoGebraInstance = void 0;
const geogebra_1 = require("../types/geogebra");
const logger_1 = __importDefault(require("./logger"));
const uuid_1 = require("uuid");
/**
* Mock GeoGebra Instance for demonstration and testing
* This provides the same interface as the full implementation
* but uses in-memory simulation instead of a real browser instance
*/
class MockGeoGebraInstance {
isInitialized = false;
lastActivity = new Date();
objects = new Map();
animatingObjects = new Set();
animationSpeeds = new Map();
tracedObjects = new Set();
isAnimating = false;
id;
config;
constructor(config = {}) {
this.id = (0, uuid_1.v4)();
this.config = {
appName: 'graphing',
width: 800,
height: 600,
showMenuBar: false,
showToolBar: false,
showAlgebraInput: false,
showResetIcon: false,
enableRightClick: true,
language: 'en',
...config
};
logger_1.default.info(`Created Mock GeoGebra instance ${this.id}`, { config: this.config });
}
/**
* Initialize the mock instance
*/
async initialize() {
try {
logger_1.default.info(`Initializing Mock GeoGebra instance ${this.id}`);
// Simulate initialization delay
await new Promise(resolve => setTimeout(resolve, 100));
this.isInitialized = true;
this.updateActivity();
logger_1.default.info(`Mock GeoGebra instance ${this.id} initialized successfully`);
}
catch (error) {
logger_1.default.error(`Failed to initialize Mock GeoGebra instance ${this.id}`, error);
throw new geogebra_1.GeoGebraConnectionError(`Failed to initialize GeoGebra: ${error instanceof Error ? error.message : String(error)}`);
}
}
/**
* Execute a GeoGebra command (mock implementation)
*/
async evalCommand(command) {
this.ensureInitialized();
this.updateActivity();
try {
logger_1.default.debug(`Executing mock command on instance ${this.id}: ${command}`);
// Parse basic commands
const result = this.parseCommand(command);
logger_1.default.debug(`Mock command executed successfully on instance ${this.id}: ${command}`);
return {
success: true,
result: result
};
}
catch (error) {
logger_1.default.error(`Mock command execution failed on instance ${this.id}`, { command, error });
return {
success: false,
error: error instanceof Error ? error.message : String(error)
};
}
}
/**
* Parse and execute basic GeoGebra commands
*/
parseCommand(command) {
const trimmed = command.trim();
// Point creation: A = (x, y)
const pointMatch = trimmed.match(/^([A-Za-z]\w*)\s*=\s*\(\s*(-?\d+(?:\.\d+)?)\s*,\s*(-?\d+(?:\.\d+)?)\s*\)$/);
if (pointMatch && pointMatch[1] && pointMatch[2] && pointMatch[3]) {
const [, name, x, y] = pointMatch;
this.objects.set(name, {
name,
type: 'point',
visible: true,
defined: true,
x: parseFloat(x),
y: parseFloat(y),
z: 0,
color: '#0000FF'
});
return `Point ${name} created at (${x}, ${y})`;
}
// Slider creation: name = Slider(min, max, increment, speed, width, isAngle, horizontal, animating, random)
const sliderMatch = trimmed.match(/^([A-Za-z]\w*)\s*=\s*Slider\s*\(\s*(-?\d+(?:\.\d+)?)\s*,\s*(-?\d+(?:\.\d+)?)\s*(?:\s*,\s*(\d+(?:\.\d+)?))?\s*.*?\)$/);
if (sliderMatch && sliderMatch[1] && sliderMatch[2] && sliderMatch[3]) {
const [, name, min, max, _increment] = sliderMatch;
const defaultValue = parseFloat(min);
this.objects.set(name, {
name,
type: 'slider',
visible: true,
defined: true,
value: defaultValue,
color: '#0073E6'
});
return `Slider ${name} created with range [${min}, ${max}], current value: ${defaultValue}`;
}
// Line creation: l = Line(A, B)
const lineMatch = trimmed.match(/^([A-Za-z]\w*)\s*=\s*Line\s*\(\s*([A-Za-z]\w*)\s*,\s*([A-Za-z]\w*)\s*\)$/);
if (lineMatch && lineMatch[1] && lineMatch[2] && lineMatch[3]) {
const [, name, point1, point2] = lineMatch;
if (!this.objects.has(point1) || !this.objects.has(point2)) {
throw new Error(`Points ${point1} or ${point2} do not exist`);
}
this.objects.set(name, {
name,
type: 'line',
visible: true,
defined: true,
color: '#000000'
});
return `Line ${name} created through points ${point1} and ${point2}`;
}
// Function creation: f(x) = expression
const functionMatch = trimmed.match(/^([A-Za-z]\w*)\s*\(\s*x\s*\)\s*=\s*(.+)$/);
if (functionMatch && functionMatch[1] && functionMatch[2]) {
const [, name, expression] = functionMatch;
this.objects.set(name, {
name,
type: 'function',
visible: true,
defined: true,
value: expression,
color: '#FF0000'
});
return `Function ${name}(x) = ${expression} created`;
}
// Parametric curve creation: name = Curve(x_expr, y_expr, param, start, end)
const parametricMatch = trimmed.match(/^([A-Za-z]\w*)\s*=\s*Curve\s*\(\s*(.+?)\s*,\s*(.+?)\s*,\s*([A-Za-z]\w*)\s*,\s*(-?\d+(?:\.\d+)?)\s*,\s*(-?\d+(?:\.\d+)?)\s*\)$/);
if (parametricMatch && parametricMatch[1] && parametricMatch[2] && parametricMatch[3] && parametricMatch[4] && parametricMatch[5] && parametricMatch[6]) {
const [, name, xExpr, yExpr, param, tMin, tMax] = parametricMatch;
this.objects.set(name, {
name,
type: 'curve',
visible: true,
defined: true,
value: `Parametric: x(${param}) = ${xExpr}, y(${param}) = ${yExpr}, ${param} ∈ [${tMin}, ${tMax}]`,
color: '#00AA00'
});
return `Parametric curve ${name} created: x(${param}) = ${xExpr}, y(${param}) = ${yExpr}, ${param} ∈ [${tMin}, ${tMax}]`;
}
// Implicit curve creation: name = ImplicitCurve(expression)
const implicitMatch = trimmed.match(/^([A-Za-z]\w*)\s*=\s*ImplicitCurve\s*\(\s*(.+)\s*\)$/);
if (implicitMatch && implicitMatch[1] && implicitMatch[2]) {
const [, name, expression] = implicitMatch;
this.objects.set(name, {
name,
type: 'implicitcurve',
visible: true,
defined: true,
value: `Implicit: ${expression} = 0`,
color: '#AA0000'
});
return `Implicit curve ${name} created: ${expression} = 0`;
}
// Styling commands: SetColor, SetLineThickness, SetLineStyle
const setColorMatch = trimmed.match(/^SetColor\s*\(\s*([A-Za-z]\w*)\s*,\s*"([^"]+)"\s*\)$/);
if (setColorMatch && setColorMatch[1] && setColorMatch[2]) {
const [, name, color] = setColorMatch;
const obj = this.objects.get(name);
if (obj) {
obj.color = color;
return `Color of ${name} set to ${color}`;
}
return `Object ${name} not found for color setting`;
}
const setThicknessMatch = trimmed.match(/^SetLineThickness\s*\(\s*([A-Za-z]\w*)\s*,\s*(\d+)\s*\)$/);
if (setThicknessMatch && setThicknessMatch[1] && setThicknessMatch[2]) {
const [, name, thickness] = setThicknessMatch;
const obj = this.objects.get(name);
if (obj) {
// Store thickness in a custom property (mock doesn't have thickness in type)
obj.thickness = parseInt(thickness);
return `Line thickness of ${name} set to ${thickness}`;
}
return `Object ${name} not found for thickness setting`;
}
const setStyleMatch = trimmed.match(/^SetLineStyle\s*\(\s*([A-Za-z]\w*)\s*,\s*(\d+)\s*\)$/);
if (setStyleMatch && setStyleMatch[1] && setStyleMatch[2]) {
const [, name, lineType] = setStyleMatch;
const obj = this.objects.get(name);
if (obj) {
const style = lineType === '10' ? 'dashed' : lineType === '20' ? 'dotted' : 'solid';
obj.style = style;
return `Line style of ${name} set to ${style}`;
}
return `Object ${name} not found for style setting`;
}
// Circle creation: Circle((x, y), r)
const circleMatch = trimmed.match(/^Circle\s*\(\s*\(\s*(-?\d+(?:\.\d+)?)\s*,\s*(-?\d+(?:\.\d+)?)\s*\)\s*,\s*(\d+(?:\.\d+)?)\s*\)$/);
if (circleMatch && circleMatch[1] && circleMatch[2] && circleMatch[3]) {
const [, x, y, r] = circleMatch;
const name = `circle_${Date.now()}`;
this.objects.set(name, {
name,
type: 'circle',
visible: true,
defined: true,
x: parseFloat(x),
y: parseFloat(y),
value: parseFloat(r),
color: '#00FF00'
});
return `Circle created at (${x}, ${y}) with radius ${r}`;
}
// CAS Operations
// Solve equation: Solve(equation)
const solveMatch = trimmed.match(/^Solve\s*\(\s*(.+)\s*\)$/);
if (solveMatch && solveMatch[1]) {
const [, equation] = solveMatch;
return this.mockSolveEquation(equation);
}
// Solve equation for variable: Solve(equation, variable)
const solveVarMatch = trimmed.match(/^Solve\s*\(\s*(.+?)\s*,\s*([a-zA-Z]\w*)\s*\)$/);
if (solveVarMatch && solveVarMatch[1] && solveVarMatch[2]) {
const [, equation, variable] = solveVarMatch;
return this.mockSolveEquation(equation, variable);
}
// Differentiate with respect to variable: Derivative(expression, variable)
const derivativeVarMatch = trimmed.match(/^Derivative\s*\(\s*(.+?)\s*,\s*([a-zA-Z]\w*)\s*\)$/);
if (derivativeVarMatch && derivativeVarMatch[1] && derivativeVarMatch[2]) {
const [, expression, variable] = derivativeVarMatch;
return this.mockDifferentiate(expression, variable);
}
// Differentiate: Derivative(expression)
const derivativeMatch = trimmed.match(/^Derivative\s*\(\s*(.+)\s*\)$/);
if (derivativeMatch && derivativeMatch[1]) {
const [, expression] = derivativeMatch;
return this.mockDifferentiate(expression);
}
// Integrate with respect to variable: Integral(expression, variable)
const integralVarMatch = trimmed.match(/^Integral\s*\(\s*(.+?)\s*,\s*([a-zA-Z]\w*)\s*\)$/);
if (integralVarMatch && integralVarMatch[1] && integralVarMatch[2]) {
const [, expression, variable] = integralVarMatch;
return this.mockIntegrate(expression, variable);
}
// Integrate: Integral(expression)
const integralMatch = trimmed.match(/^Integral\s*\(\s*(.+)\s*\)$/);
if (integralMatch && integralMatch[1]) {
const [, expression] = integralMatch;
return this.mockIntegrate(expression);
}
// Simplify: Simplify(expression)
const simplifyMatch = trimmed.match(/^Simplify\s*\(\s*(.+)\s*\)$/);
if (simplifyMatch && simplifyMatch[1]) {
const [, expression] = simplifyMatch;
return this.mockSimplify(expression);
}
// Generic command (just acknowledge)
return `Command executed: ${command}`;
}
/**
* Execute command and get labels of created objects
*/
async evalCommandGetLabels(command) {
this.ensureInitialized();
this.updateActivity();
try {
const beforeObjects = new Set(this.objects.keys());
await this.evalCommand(command);
const afterObjects = new Set(this.objects.keys());
const newLabels = Array.from(afterObjects).filter(label => !beforeObjects.has(label));
logger_1.default.debug(`Mock command executed on instance ${this.id}, labels: ${newLabels.join(', ')}`);
return newLabels;
}
catch (error) {
logger_1.default.error(`Failed to execute mock command with labels on instance ${this.id}`, { command, error });
throw new geogebra_1.GeoGebraCommandError(`Failed to execute command: ${error instanceof Error ? error.message : String(error)}`, command);
}
}
/**
* Delete an object
*/
async deleteObject(objName) {
this.ensureInitialized();
this.updateActivity();
try {
const deleted = this.objects.delete(objName);
if (deleted) {
logger_1.default.debug(`Deleted object ${objName} from mock instance ${this.id}`);
}
return deleted;
}
catch (error) {
logger_1.default.error(`Failed to delete object ${objName} on mock instance ${this.id}`, error);
return false;
}
}
/**
* Check if object exists
*/
async exists(objName) {
this.ensureInitialized();
this.updateActivity();
return this.objects.has(objName);
}
/**
* Check if object is defined
*/
async isDefined(objName) {
this.ensureInitialized();
this.updateActivity();
const obj = this.objects.get(objName);
return obj ? obj.defined : false;
}
/**
* Get all object names
*/
async getAllObjectNames(type) {
this.ensureInitialized();
this.updateActivity();
if (type) {
return Array.from(this.objects.values())
.filter(obj => obj.type === type)
.map(obj => obj.name);
}
return Array.from(this.objects.keys());
}
/**
* Get object information
*/
async getObjectInfo(objName) {
this.ensureInitialized();
this.updateActivity();
return this.objects.get(objName) || null;
}
/**
* Get X coordinate of object
*/
async getXcoord(objName) {
this.ensureInitialized();
this.updateActivity();
const obj = this.objects.get(objName);
return obj?.x || 0;
}
/**
* Get Y coordinate of object
*/
async getYcoord(objName) {
this.ensureInitialized();
this.updateActivity();
const obj = this.objects.get(objName);
return obj?.y || 0;
}
/**
* Get Z coordinate of object
*/
async getZcoord(objName) {
this.ensureInitialized();
this.updateActivity();
const obj = this.objects.get(objName);
return obj?.z || 0;
}
/**
* Get value of object
*/
async getValue(objName) {
this.ensureInitialized();
this.updateActivity();
const obj = this.objects.get(objName);
return typeof obj?.value === 'number' ? obj.value : 0;
}
/**
* Get value as string
*/
async getValueString(objName) {
this.ensureInitialized();
this.updateActivity();
const obj = this.objects.get(objName);
return obj?.value?.toString() || '';
}
/**
* Create new construction
*/
async newConstruction() {
this.ensureInitialized();
this.updateActivity();
this.objects.clear();
logger_1.default.debug(`New construction created on mock instance ${this.id}`);
}
/**
* Reset to initial state
*/
async reset() {
this.ensureInitialized();
this.updateActivity();
this.objects.clear();
logger_1.default.debug(`Mock instance ${this.id} reset to initial state`);
}
/**
* Refresh all views
*/
async refreshViews() {
this.ensureInitialized();
this.updateActivity();
logger_1.default.debug(`Views refreshed on mock instance ${this.id}`);
}
/**
* Set coordinate system bounds (mock implementation)
*/
async setCoordSystem(xmin, xmax, ymin, ymax) {
this.ensureInitialized();
this.updateActivity();
logger_1.default.debug(`Mock coordinate system set on instance ${this.id}: x[${xmin}, ${xmax}], y[${ymin}, ${ymax}]`);
}
/**
* Set axes visibility (mock implementation)
*/
async setAxesVisible(xAxis, yAxis) {
this.ensureInitialized();
this.updateActivity();
logger_1.default.debug(`Mock axes visibility set on instance ${this.id}: x=${xAxis}, y=${yAxis}`);
}
/**
* Set grid visibility (mock implementation)
*/
async setGridVisible(visible) {
this.ensureInitialized();
this.updateActivity();
logger_1.default.debug(`Mock instance ${this.id}: Set grid visible: ${visible}`);
}
/**
* Check if instance is ready
*/
async isReady() {
return this.isInitialized;
}
/**
* Export construction as PNG (base64) - Mock implementation with enhanced parameters
*/
async exportPNG(scale = 1, transparent = false, dpi = 72, width, height) {
this.ensureInitialized();
this.updateActivity();
// Return a simple base64 encoded placeholder PNG
const placeholderPNG = 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==';
logger_1.default.debug(`Mock PNG exported from instance ${this.id} with scale ${scale}, transparent ${transparent}, dpi ${dpi}, dimensions ${width}x${height}`);
return placeholderPNG;
}
/**
* Export construction as SVG - Mock implementation
*/
async exportSVG() {
this.ensureInitialized();
this.updateActivity();
// Return a simple SVG with mock construction
const mockSVG = `<svg width="800" height="600" xmlns="http://www.w3.org/2000/svg">
<rect width="800" height="600" fill="white"/>
<text x="400" y="300" text-anchor="middle" font-family="Arial" font-size="20">Mock GeoGebra Construction</text>
${Array.from(this.objects.values()).map(obj => {
if (obj.type === 'point') {
return `<circle cx="${(obj.x || 0) * 50 + 400}" cy="${(obj.y || 0) * -50 + 300}" r="3" fill="${obj.color || '#0000FF'}"/>`;
}
return '';
}).join('\n ')}
</svg>`;
logger_1.default.debug(`Mock SVG exported from instance ${this.id}`);
return mockSVG.trim();
}
/**
* Export construction as PDF (base64) - Mock implementation
*/
async exportPDF() {
this.ensureInitialized();
this.updateActivity();
logger_1.default.debug(`Mock PDF export from instance ${this.id}`);
// Return mock PDF data (base64 encoded)
const mockPdfData = 'JVBERi0xLjQKJcOkw7zDtsOgCjIgMCBvYmoKPDwvTGVuZ3RoIDMgMCBSL0ZpbHRlci9GbGF0ZURlY29kZT4+CnN0cmVhbQp4nDPQM1Qo5ypUMFAw0DMwULBVqOZSUDBQykvMTbVSUDC2UshIzStRyMnPS7VVqAUAYQsKZAplbmRzdHJlYW0KZW5kb2JqCgozIDAgb2JqCjI4CmVuZG9iagoKMSAwIG9iago8PC9UeXBlL0NhdGFsb2cvUGFnZXMgNCAwIFI+PgplbmRvYmoKCjQgMCBvYmoKPDwvVHlwZS9QYWdlcy9LaWRzWzUgMCBSXS9Db3VudCAxPj4KZW5kb2JqCgo1IDAgb2JqCjw8L1R5cGUvUGFnZS9QYXJlbnQgNCAwIFIvTWVkaWFCb3hbMCAwIDYxMiA3OTJdL0NvbnRlbnRzIDIgMCBSPj4KZW5kb2JqCgp4cmVmCjAgNgowMDAwMDAwMDAwIDY1NTM1IGYgCjAwMDAwMDAyOTQgMDAwMDAgbiAKMDAwMDAwMDAwOSAwMDAwMCBuIAowMDAwMDAwMjc0IDAwMDAwIG4gCjAwMDAwMDAzNDMgMDAwMDAgbiAKMDAwMDAwMDQwMCAwMDAwMCBuIAp0cmFpbGVyCjw8L1NpemUgNi9Sb290IDEgMCBSPj4Kc3RhcnR4cmVmCjUwMwolJUVPRg==';
return mockPdfData;
}
/**
* Export animation as frames (GEB-17 enhancement)
*/
async exportAnimation(options = {}) {
this.ensureInitialized();
this.updateActivity();
const { duration = 5000, // 5 seconds
frameRate = 10, // 10 fps
format = 'frames', width = 800, height = 600 } = options;
logger_1.default.debug(`Mock animation export from instance ${this.id}`, { duration, frameRate, format, width, height });
// Calculate number of frames
const totalFrames = Math.ceil((duration / 1000) * frameRate);
// Generate mock frame data
const frames = [];
for (let i = 0; i < totalFrames; i++) {
// Generate a simple mock PNG frame (base64 encoded)
const mockFrameData = `iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==_frame_${i}`;
frames.push(mockFrameData);
}
logger_1.default.debug(`Mock animation export completed: ${frames.length} frames generated`);
if (format === 'frames') {
return frames;
}
else {
// For GIF format, return a mock GIF data string
return 'R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7_mock_gif';
}
}
/**
* Cleanup resources
*/
async cleanup() {
logger_1.default.info(`Cleaning up Mock GeoGebra instance ${this.id}`);
this.objects.clear();
this.isInitialized = false;
logger_1.default.info(`Mock GeoGebra instance ${this.id} cleaned up successfully`);
}
/**
* Get instance state
*/
getState() {
return {
id: this.id,
isReady: this.isInitialized,
lastActivity: this.lastActivity,
config: this.config
};
}
/**
* Update last activity timestamp
*/
updateActivity() {
this.lastActivity = new Date();
}
/**
* Ensure instance is initialized
*/
ensureInitialized() {
if (!this.isInitialized) {
throw new geogebra_1.GeoGebraConnectionError('Mock GeoGebra instance not initialized');
}
}
/**
* Mock implementation of equation solving
*/
mockSolveEquation(equation, variable) {
logger_1.default.debug(`Mock solving equation: ${equation}${variable ? ` for ${variable}` : ''}`);
// Simple mock responses for common cases
if (equation.includes('x^2')) {
return variable ?
`{${variable} = -√(solution), ${variable} = √(solution)}` :
`Solutions: x = -√(solution), x = √(solution)`;
}
if (equation.includes('x =') || equation.includes('= x')) {
const match = equation.match(/(-?\d+(?:\.\d+)?)/);
const value = match ? match[1] : '0';
return variable ?
`{${variable} = ${value}}` :
`Solution: x = ${value}`;
}
// Linear equation pattern
if (equation.match(/\d*x\s*[+-]/)) {
return variable ?
`{${variable} = solution_value}` :
`Solution: x = solution_value`;
}
return `Mock solution for equation: ${equation}`;
}
/**
* Mock implementation of differentiation
*/
mockDifferentiate(expression, variable = 'x') {
logger_1.default.debug(`Mock differentiating: ${expression} with respect to ${variable}`);
// Simple mock responses for common cases
if (expression === variable) {
return '1';
}
if (expression.includes(`${variable}^2`)) {
return `2*${variable}`;
}
if (expression.includes(`${variable}^3`)) {
return `3*${variable}^2`;
}
if (expression.includes(`sin(${variable})`)) {
return `cos(${variable})`;
}
if (expression.includes(`cos(${variable})`)) {
return `-sin(${variable})`;
}
if (expression.includes(`e^${variable}`)) {
return `e^${variable}`;
}
if (!expression.includes(variable)) {
return '0';
}
return `d/d${variable}(${expression})`;
}
/**
* Mock implementation of integration
*/
mockIntegrate(expression, variable = 'x') {
logger_1.default.debug(`Mock integrating: ${expression} with respect to ${variable}`);
// Simple mock responses for common cases
if (expression === '1') {
return variable;
}
if (expression === variable) {
return `${variable}^2/2`;
}
if (expression.includes(`${variable}^2`)) {
return `${variable}^3/3`;
}
if (expression.includes(`${variable}^3`)) {
return `${variable}^4/4`;
}
if (expression.includes(`sin(${variable})`)) {
return `-cos(${variable})`;
}
if (expression.includes(`cos(${variable})`)) {
return `sin(${variable})`;
}
if (expression.includes(`e^${variable}`)) {
return `e^${variable}`;
}
return `∫(${expression}, ${variable})dx`;
}
/**
* Mock implementation of expression simplification
*/
mockSimplify(expression) {
logger_1.default.debug(`Mock simplifying: ${expression}`);
// Simple mock simplifications
let simplified = expression;
// Remove unnecessary parentheses and spaces
simplified = simplified.replace(/\s+/g, '');
simplified = simplified.replace(/\(([^()]+)\)/g, '$1');
// Combine like terms (very basic)
simplified = simplified.replace(/(\d+)\*x\+(\d+)\*x/g, (_match, a, b) => {
return `${parseInt(a) + parseInt(b)}*x`;
});
// Basic arithmetic
simplified = simplified.replace(/(\d+)\+(\d+)/g, (_match, a, b) => {
return `${parseInt(a) + parseInt(b)}`;
});
simplified = simplified.replace(/(\d+)\*1/g, '$1');
simplified = simplified.replace(/1\*(\d+)/g, '$1');
simplified = simplified.replace(/\+0/g, '');
simplified = simplified.replace(/0\+/g, '');
return simplified === expression ? expression : simplified;
}
/**
* Animation Methods
*/
async setAnimating(objName, animate) {
this.ensureInitialized();
this.updateActivity();
if (!this.objects.has(objName)) {
throw new Error(`Object ${objName} does not exist`);
}
if (animate) {
this.animatingObjects.add(objName);
if (!this.animationSpeeds.has(objName)) {
this.animationSpeeds.set(objName, 1); // Default speed
}
}
else {
this.animatingObjects.delete(objName);
}
logger_1.default.debug(`Mock instance ${this.id}: Set animating for ${objName}: ${animate}`);
}
async setAnimationSpeed(objName, speed) {
this.ensureInitialized();
this.updateActivity();
if (!this.objects.has(objName)) {
throw new Error(`Object ${objName} does not exist`);
}
this.animationSpeeds.set(objName, speed);
logger_1.default.debug(`Mock instance ${this.id}: Set animation speed for ${objName}: ${speed}`);
}
async startAnimation() {
this.ensureInitialized();
this.updateActivity();
this.isAnimating = true;
logger_1.default.debug(`Mock instance ${this.id}: Started animation for ${this.animatingObjects.size} objects`);
}
async stopAnimation() {
this.ensureInitialized();
this.updateActivity();
this.isAnimating = false;
logger_1.default.debug(`Mock instance ${this.id}: Stopped animation`);
}
async isAnimationRunning() {
this.ensureInitialized();
this.updateActivity();
return this.isAnimating && this.animatingObjects.size > 0;
}
async setTrace(objName, flag) {
this.ensureInitialized();
this.updateActivity();
if (!this.objects.has(objName)) {
throw new Error(`Object ${objName} does not exist`);
}
if (flag) {
this.tracedObjects.add(objName);
}
else {
this.tracedObjects.delete(objName);
}
logger_1.default.debug(`Mock instance ${this.id}: Set trace for ${objName}: ${flag}`);
}
async setValue(objName, value) {
this.ensureInitialized();
this.updateActivity();
const obj = this.objects.get(objName);
if (!obj) {
throw new Error(`Object ${objName} does not exist`);
}
obj.value = value;
logger_1.default.debug(`Mock instance ${this.id}: Set value for ${objName}: ${value}`);
}
}
exports.MockGeoGebraInstance = MockGeoGebraInstance;
//# sourceMappingURL=geogebra-mock.js.map