/*
 * Copyright (C) 2016-2020 Kano Computing Ltd.
 * License: http://www.gnu.org/licenses/gpl-2.0.txt GNU General Public License v2
 */
import ChallengeEngine from 'challenge-engine/definition.js';
import { subscribeDOM, EventEmitter, dispose } from '@kano/common/index.js';
// Trick to make the custom emitter from the challenge engine have a normal eventemitter api
ChallengeEngine.prototype.on = ChallengeEngine.prototype.addEventListener;
export class Engine extends ChallengeEngine {
    constructor(editor) {
        super();
        this.widgets = new Map();
        this.subscriptions = [];
        this.helpers = [];
        this.stepHelpers = [];
        this.stepsMappings = new Map();
        this.aliases = [];
        this._onDidRequestNextChallenge = new EventEmitter();
        this._onDidUpdateStepIndex = new EventEmitter();
        this.editor = editor;
        this.editor.playUISound('start-challenge');
        subscribeDOM(this, 'done', () => this.onEnd(), this, this.subscriptions);
    }
    get onDidRequestNextChallenge() { return this._onDidRequestNextChallenge.event; }
    get onDidUpdateStepIndex() { return this._onDidUpdateStepIndex.event; }
    _updateStep() {
        super._updateStep();
        const step = this.steps[this.stepIndex];
        if (!step) {
            return;
        }
        const firstOrLastStep = this.stepIndex === 0
            || this.stepIndex === this._steps.length - 1;
        if (!firstOrLastStep && step.type) {
            this.editor.playUISound('banner-change');
        }
        this.stepHelpers.forEach(helper => helper.leave(this, step));
        this.stepHelpers = this.helpers.filter(helper => helper.test(this, step));
        this.stepHelpers.forEach(helper => helper.enter(this, step));
        this._onDidUpdateStepIndex.fire(this.stepIndex);
    }
    onEnd() {
        this.editor.playUISound('win');
    }
    registerAlias(alias, target) {
        this.aliases.push(this.editor.registerAlias(alias, target));
    }
    registerHelper(helper) {
        this.helpers.push(helper);
    }
    getExpandedStepIndex(sourceIndex) {
        let step;
        let counter = 0;
        // Go through all steps until the source index
        for (let i = 0; i < this._steps.length && i < sourceIndex; i += 1) {
            step = this._steps[i];
            // Shorthand exists
            if (step.type && this._shorthands[step.type]) {
                // Expand this step
                const expanded = this._shorthands[step.type](step);
                // Add the number of expanded steps
                counter += (Array.isArray(expanded) ? expanded.length : 1);
            }
            else {
                // Add one only when no shorthand exist
                counter += 1;
            }
        }
        // Counter contains the number of steps 
        return counter;
    }
    _expandStepsWithMappings() {
        // Store the mappings between generated steps and original steps
        const mappings = new Map();
        // Create a new Array of steps with the expanded shorthands
        const steps = this._steps.reduce((acc, step, index) => {
            if (step.type && this._shorthands[step.type]) {
                // A shorthand exist, use the processor to get all the steps
                const result = this._shorthands[step.type](step);
                if (Array.isArray(result)) {
                    // We got some expanded steps, map all their new indexes to their original step
                    result.forEach((r, i) => {
                        mappings.set(acc.length + i, index);
                    });
                }
                else {
                    mappings.set(acc.length, index);
                }
                return acc.concat(result);
            }
            // No expansion, map the step index to the current index
            mappings.set(acc.length, index);
            // No, shorthands, return the original step
            return acc.concat(step);
        }, []);
        return { steps, mappings };
    }
    dispose() {
        dispose(this.subscriptions);
        this.subscriptions.length = 0;
        dispose(this.aliases);
        this.aliases.length = 0;
        this.widgets.forEach((widget) => {
            this.editor.removeContentWidget(widget);
        });
        this._onDidUpdateStepIndex.dispose();
    }
}
//# sourceMappingURL=engine.js.map