"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.MotionComposerRunner = void 0;
const tslib_1 = require("tslib");
const rxjs_1 = require("rxjs");
const util_1 = require("./util");
/**
 * The MotionComposerRunner executes a Motion Composer data structure (file).
 *
 * Execution can be stopped, but this will only happen after the current command completes.
 *
 * The class maintains the `running` state.
 *
 * While executing, the observable returned by the `run` method emits the entire Motion Composer data structure,
 * including updated status for each command as it starts, succeeds, or fails.
 */
class MotionComposerRunner {
    constructor(client) {
        this.client = client;
        /**
         * Indicates the running status of the Motion Composer as it executes and completes.
         */
        this.running = false;
        /**
         * Emits on the `stop$` subject to halt the execution of the entire Motion Composer after ongoing commands complete.
         */
        this.stop$ = new rxjs_1.Subject();
    }
    /**
     * Executes the provided Motion Composer.
     * Flows run in parallel, while commands within each flow are executed sequentially.
     */
    run(motionComposer) {
        this.running = true;
        // Clone the provided composer data to allow updates to command statuses during execution.
        const mc = structuredClone(motionComposer);
        // Reset the status, status message, and the result of all commands.
        mc.flows.forEach((flow) => {
            flow.commands.forEach((command) => {
                command.status = undefined;
                command.statusMessage = undefined;
                command.result = undefined;
            });
        });
        return (0, rxjs_1.from)(mc.flows).pipe(
        // Process each flow concurrently.
        (0, rxjs_1.mergeMap)((flow) => {
            var _a;
            return (0, rxjs_1.from)(flow.commands).pipe(
            // Execute each command sequentially.
            (0, rxjs_1.concatMap)((command) => {
                command.status = 'running';
                const startEmission = (0, rxjs_1.of)(mc);
                const executeCommand = (() => tslib_1.__awaiter(this, void 0, void 0, function* () {
                    switch (command.type) {
                        case 'delay': {
                            yield (0, util_1.resolveAfter)(command.config.duration);
                            command.status = 'succeeded';
                            break;
                        }
                        case 'download': {
                            try {
                                yield this.client.request.download(command.deviceRef, command.config.index, command.config.subindex, command.config.value);
                                command.status = 'succeeded';
                            }
                            catch (err) {
                                command.status = 'failed';
                                if (err instanceof Error) {
                                    command.statusMessage = err.message;
                                }
                            }
                            break;
                        }
                        case 'quickStop': {
                            try {
                                yield this.client.request.quickStop(command.deviceRef);
                                command.status = 'succeeded';
                            }
                            catch (err) {
                                command.status = 'failed';
                                if (err instanceof Error) {
                                    command.statusMessage = err.message;
                                }
                            }
                            break;
                        }
                        case 'resetFault': {
                            try {
                                yield this.client.request.resetFault(command.deviceRef);
                                command.status = 'succeeded';
                            }
                            catch (err) {
                                command.status = 'failed';
                                if (err instanceof Error) {
                                    command.statusMessage = err.message;
                                }
                            }
                            break;
                        }
                        case 'runPositionProfile': {
                            try {
                                yield this.client.runPositionProfile(command.deviceRef, command.config);
                                command.status = 'succeeded';
                            }
                            catch (err) {
                                command.status = 'failed';
                                if (err instanceof Error) {
                                    command.statusMessage = err.message;
                                }
                            }
                            break;
                        }
                        case 'runTorqueProfile': {
                            try {
                                yield this.client.runTorqueProfile(command.deviceRef, command.config);
                                command.status = 'succeeded';
                            }
                            catch (err) {
                                command.status = 'failed';
                                if (err instanceof Error) {
                                    command.statusMessage = err.message;
                                }
                            }
                            break;
                        }
                        case 'runVelocityProfile': {
                            try {
                                yield this.client.runVelocityProfile(command.deviceRef, command.config);
                                command.status = 'succeeded';
                            }
                            catch (err) {
                                command.status = 'failed';
                                if (err instanceof Error) {
                                    command.statusMessage = err.message;
                                }
                            }
                            break;
                        }
                        case 'setModesOfOperation': {
                            try {
                                yield (0, rxjs_1.lastValueFrom)(this.client.request.setModesOfOperation(command.deviceRef, command.config.modesOfOperation));
                                command.status = 'succeeded';
                            }
                            catch (err) {
                                command.status = 'failed';
                                if (err instanceof Error) {
                                    command.statusMessage = err.message;
                                }
                            }
                            break;
                        }
                        case 'transitionToCia402State': {
                            try {
                                yield this.client.request.transitionToCia402State(command.deviceRef, command.config.state);
                                command.status = 'succeeded';
                            }
                            catch (err) {
                                command.status = 'failed';
                                if (err instanceof Error) {
                                    command.statusMessage = err.message;
                                }
                            }
                            break;
                        }
                        case 'upload': {
                            try {
                                const value = yield this.client.request.upload(command.deviceRef, command.config.index, command.config.subindex);
                                command.result = value;
                                command.status = 'succeeded';
                            }
                            catch (err) {
                                command.status = 'failed';
                                if (err instanceof Error) {
                                    command.statusMessage = err.message;
                                }
                            }
                        }
                    }
                    return mc;
                }))();
                const endEmission = (0, rxjs_1.from)(executeCommand);
                // Emit twice: once when the command starts, and once when it ends.
                return (0, rxjs_1.concat)(startEmission, endEmission);
            }), (0, rxjs_1.repeat)((_a = flow.repeat) !== null && _a !== void 0 ? _a : 1), (0, rxjs_1.takeUntil)(this.stop$));
        }), (0, rxjs_1.finalize)(() => (this.running = false)) // note: this runs after complete on subscribe
        );
    }
    /**
     * Stops the currently executing Motion Composer.
     * All ongoing commands must complete before execution is halted.
     */
    stop() {
        this.stop$.next();
    }
}
exports.MotionComposerRunner = MotionComposerRunner;
//# sourceMappingURL=motion-composer.js.map