var __spreadArrays = (this && this.__spreadArrays) || function () {
    for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;
    for (var r = Array(s), k = 0, i = 0; i < il; i++)
        for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)
            r[k] = a[j];
    return r;
};
var answer = "Answer";
var category = "Category";
var column = "Column";
var description = "Description";
var example = "Example";
var icon = "Icon";
var image = "Image";
var link = "Link";
var max = "Max";
var min = "Min";
var name = "Name";
var row = "Row";
var text = "Text";
var enLabel = {
    "add-item": "Add {item}",
    answer: answer,
    category: category,
    column: column,
    "delete-item": "Delete {item}",
    description: description,
    example: example,
    "false": "No",
    "hide-item": "Hide {item}",
    icon: icon,
    image: image,
    link: link,
    max: max,
    "me-auto-play": "Autoplay",
    "me-block-subtitle": "Use the '+' button below to add elements to the screen.",
    "me-block-title": "Screen creation",
    "me-element-audio": "Audio",
    "me-element-checkbox-max": "Max answers",
    "me-element-checkbox": "Checkbox",
    "me-element-download-placeholder": "File description",
    "me-element-download": "Download",
    "me-element-header-placeholder": "Header text",
    "me-element-header": "Header",
    "me-element-icon": "Icon",
    "me-element-image": "Image",
    "me-element-input-multiline": "Multiline",
    "me-element-input": "Input",
    "me-element-link": "Link",
    "me-element-matrix": "Matrix",
    "me-element-radio": "Radio",
    "me-element-slider": "Slider",
    "me-element-sort": "Sort",
    "me-element-table": "Table",
    "me-element-text": "Text",
    "me-element-video": "Video",
    "me-flow-action-add": "Add screen",
    "me-flow-action-delete": "Delete screen",
    "me-flow-action-end": "Complete module",
    "me-flow-action-open": "Show screen",
    "me-flow-condition-other": "In all other cases",
    "me-flow-condition-screen": "Screen",
    "me-flow-option-conditional": "One of the following screen's is shown",
    "me-flow-option-end": "Nothing, the module will end",
    "me-flow-option-next": "Another screen is shown",
    "me-flow-subtitle": "Use the module-graph, or the buttons below to define what happens after this screen.",
    "me-flow-title": "Define what happens next",
    "me-module-advanced-options": "Advanced options",
    "me-module-graph-subtitle": "Click on a screen for fast navigation.",
    "me-module-graph-title": "Screen overview",
    "me-module-subtitle": "Use the options below to create the module.",
    "me-module-title": "Module creation",
    "me-option": "Option",
    "me-orientation-h": "Horizontal",
    "me-orientation-v": "Vertical",
    "me-orientation": "Orientation",
    "me-other": "Other",
    "me-question": "Formulate your question",
    "me-required": "Required",
    min: min,
    name: name,
    row: row,
    "show-item": "Show {item}",
    "step-size": "Step size",
    "text-left": "Left Text",
    "text-right": "Right Text",
    text: text,
    "true": "Yes",
    "upload-item": "Upload {item}"
};
var answer$1 = "Antwoord";
var category$1 = "Categorie";
var column$1 = "Kolom";
var description$1 = "Beschrijving";
var example$1 = "Voorbeeld";
var icon$1 = "Icoon";
var image$1 = "Afbeelding";
var link$1 = "URL";
var max$1 = "Maximaal aantal tekens";
var min$1 = "Maximaal aantal tekens";
var name$1 = "Naam";
var row$1 = "Rij";
var text$1 = "Tekst";
var nlLabel = {
    "add-item": "{item} Toevoegen",
    answer: answer$1,
    category: category$1,
    column: column$1,
    "delete-item": "{item} Verwijderen",
    description: description$1,
    example: example$1,
    "false": "Nee",
    "hide-item": "Verberg {item}",
    icon: icon$1,
    image: image$1,
    link: link$1,
    max: max$1,
    "me-auto-play": "Automatisch afspelen",
    "me-block-subtitle": "Gebruik de onderstaande '+' knop om elementen aan het scherm toe te voegen.",
    "me-block-title": "Scherm creatie",
    "me-element-audio": "Audio",
    "me-element-checkbox-max": "Max. aantal antwoorden",
    "me-element-checkbox": "Checkbox",
    "me-element-download-placeholder": "Bestand omschrijving",
    "me-element-download": "Download",
    "me-element-header-placeholder": "Header tekst",
    "me-element-header": "Header",
    "me-element-icon": "Icoon",
    "me-element-image": "Afbeelding",
    "me-element-input-multiline": "Meerdere regels",
    "me-element-input": "Invoerveld",
    "me-element-link": "Hyperlink",
    "me-element-matrix": "Matrix",
    "me-element-radio": "Meerkeuze",
    "me-element-slider": "Slider",
    "me-element-sort": "Sorteer",
    "me-element-table": "Tabel",
    "me-element-text": "Tekst",
    "me-element-video": "Video",
    "me-flow-action-add": "Scherm toevoegen",
    "me-flow-action-delete": "Scherm verwijderen",
    "me-flow-action-end": "Module afronden",
    "me-flow-action-open": "Scherm tonen",
    "me-flow-condition-other": "In alle andere gevallen",
    "me-flow-condition-screen": "Scherm",
    "me-flow-option-conditional": "Een van de volgende schermen wordt getoond",
    "me-flow-option-end": "Niks, de module eindigt",
    "me-flow-option-next": "Een ander scherm wordt getoond",
    "me-flow-subtitle": "Gebruik de grafiek of de onderstaande knoppen om te definieren wat volgt na dit scherm.",
    "me-flow-title": "Definieer wat hierna gebeurt",
    "me-module-advanced-options": "Geadvanceerde opties",
    "me-module-graph-subtitle": "Klik op een scherm om snel te navigeren.",
    "me-module-graph-title": "Schermoverzicht",
    "me-module-subtitle": "Gebruik de onderstaande opties om de module aan te maken.",
    "me-module-title": "Module instellingen",
    "me-option": "Optie",
    "me-orientation-h": "Horizontaal",
    "me-orientation-v": "Verticaal",
    "me-orientation": "Oriëntatie",
    "me-other": "Anders, namelijk",
    "me-question": "Formuleer de vraag",
    "me-required": "Verplicht",
    min: min$1,
    name: name$1,
    row: row$1,
    "show-item": "Toon {item}",
    "step-size": "Stapgrootte",
    "text-left": "Linker tekst",
    "text-right": "Rechter tekst",
    text: text$1,
    "true": "Ja",
    "upload-item": "{item} Uploaden"
};
var label = { enUs: enLabel, nl: nlLabel };
var enUs = Object.assign({}, enLabel);
var nl = Object.assign({}, nlLabel);
var Block;
(function (Block) {
    Block.empty = function () { return ({
        id: '',
        version: '',
        name: '',
        elements: [],
        settings: {
            linked: []
        }
    }); };
})(Block || (Block = {}));
var AudioElement;
(function (AudioElement) {
    AudioElement.empty = function (id) { return ({
        id: id,
        type: 'audio',
        location: [],
        autoplay: false,
        metadata: {}
    }); };
    AudioElement.ICON = 'fas:volume-up';
})(AudioElement || (AudioElement = {}));
var CheckboxElement;
(function (CheckboxElement) {
    CheckboxElement.empty = function (id) { return ({
        id: id,
        type: 'checkbox',
        question: '',
        required: false,
        orientation: 'vertical',
        options: [],
        other: false,
        answer: [],
        metadata: {}
    }); };
    CheckboxElement.ICON = 'fas:check-square';
})(CheckboxElement || (CheckboxElement = {}));
var DownloadElement;
(function (DownloadElement) {
    DownloadElement.empty = function (id) { return ({
        id: id,
        type: 'download',
        text: '',
        location: [],
        metadata: {}
    }); };
    DownloadElement.ICON = 'fas:download';
})(DownloadElement || (DownloadElement = {}));
var HeaderElement;
(function (HeaderElement) {
    HeaderElement.empty = function (id) { return ({
        id: id,
        type: 'header',
        text: '',
        metadata: {}
    }); };
    HeaderElement.ICON = 'fas:heading';
})(HeaderElement || (HeaderElement = {}));
var IconElement;
(function (IconElement) {
    IconElement.empty = function (id) { return ({
        id: id,
        type: 'icon',
        question: '',
        required: false,
        options: [
            { text: 'fas:sad-tear', color: '#ef8b54' },
            { text: 'fas:frown-open', color: '#f3ac4c' },
            { text: 'fas:meh', color: '#f6d24c' },
            { text: 'fas:grin', color: '#d7f18e' },
            { text: 'fas:laugh', color: '#aad77e' }
        ],
        metadata: {}
    }); };
    IconElement.ICON = 'fas:smile';
})(IconElement || (IconElement = {}));
var ImageElement;
(function (ImageElement) {
    ImageElement.empty = function (id) { return ({
        id: id,
        type: 'image',
        location: [],
        metadata: {}
    }); };
    ImageElement.ICON = 'fas:image';
})(ImageElement || (ImageElement = {}));
var InputElement;
(function (InputElement) {
    InputElement.empty = function (id) { return ({
        id: id,
        type: 'input',
        question: '',
        required: false,
        multiline: false,
        min: null,
        max: null,
        answer: '',
        hasAnswer: false,
        metadata: {}
    }); };
    InputElement.ICON = 'fas:font';
})(InputElement || (InputElement = {}));
var LinkElement;
(function (LinkElement) {
    LinkElement.empty = function (id) { return ({
        id: id,
        type: 'link',
        href: '',
        text: '',
        icon: '',
        metadata: {}
    }); };
    LinkElement.ICON = 'fas:link';
})(LinkElement || (LinkElement = {}));
var MatrixElement;
(function (MatrixElement) {
    MatrixElement.empty = function (id) { return ({
        id: id,
        type: 'matrix',
        question: '',
        required: false,
        rows: [],
        columns: [],
        orientation: 'vertical',
        metadata: {}
    }); };
    MatrixElement.ICON = 'fas:th';
})(MatrixElement || (MatrixElement = {}));
var RadioElement;
(function (RadioElement) {
    RadioElement.empty = function (id) { return ({
        id: id,
        type: 'radio',
        question: '',
        required: false,
        orientation: 'vertical',
        options: [],
        other: false,
        answer: null,
        metadata: {}
    }); };
    RadioElement.ICON = 'fas:dot-circle';
})(RadioElement || (RadioElement = {}));
var SliderElement;
(function (SliderElement) {
    SliderElement.empty = function (id) { return ({
        id: id,
        type: 'slider',
        question: '',
        required: false,
        step: 1,
        min: 1,
        max: 5,
        minText: '',
        maxText: '',
        metadata: {}
    }); };
    SliderElement.ICON = 'fas:sliders-h';
})(SliderElement || (SliderElement = {}));
var SortElement;
(function (SortElement) {
    SortElement.empty = function (id) { return ({
        id: id,
        type: 'sort',
        question: '',
        required: false,
        dual: false,
        options: [],
        feedbackCorrect: '',
        feedbackIncorrect: '',
        metadata: {}
    }); };
    SortElement.ICON = 'fas:sort';
})(SortElement || (SortElement = {}));
var TableElement;
(function (TableElement) {
    TableElement.empty = function (id) { return ({
        id: id,
        type: 'table',
        question: '',
        required: false,
        columns: [],
        orientation: 'horizontal',
        maxRows: 0,
        metadata: {}
    }); };
    TableElement.ICON = 'fas:table';
})(TableElement || (TableElement = {}));
var TextElement;
(function (TextElement) {
    TextElement.empty = function (id) { return ({
        id: id,
        type: 'text',
        text: '',
        metadata: {}
    }); };
    TextElement.ICON = 'fas:paragraph';
})(TextElement || (TextElement = {}));
var VideoElement;
(function (VideoElement) {
    VideoElement.empty = function (id) { return ({
        id: id,
        type: 'video',
        location: [],
        autoplay: false,
        metadata: {}
    }); };
    VideoElement.ICON = 'fas:video';
})(VideoElement || (VideoElement = {}));
var BlockElement;
(function (BlockElement) {
    BlockElement.NamespaceMap = {
        audio: AudioElement,
        checkbox: CheckboxElement,
        download: DownloadElement,
        header: HeaderElement,
        icon: IconElement,
        image: ImageElement,
        input: InputElement,
        link: LinkElement,
        matrix: MatrixElement,
        radio: RadioElement,
        slider: SliderElement,
        sort: SortElement,
        table: TableElement,
        text: TextElement,
        video: VideoElement
    };
    BlockElement.empty = function (id, type) {
        return BlockElement.NamespaceMap[type].empty(id);
    };
    BlockElement.icon = function (type) { return BlockElement.NamespaceMap[type].ICON; };
    BlockElement.TYPES = Object.keys(BlockElement.NamespaceMap);
})(BlockElement || (BlockElement = {}));
var ModuleFlow;
(function (ModuleFlow) {
    // prettier-ignore
    ModuleFlow.DEFAULT_CONDITION = function condition(context) { return true; }.toString();
    ModuleFlow.empty = function () { return ({
        start: { id: '', version: '' },
        blocks: {},
        orphans: []
    }); };
})(ModuleFlow || (ModuleFlow = {}));
var Module;
(function (Module) {
    Module.empty = function () { return ({
        id: '',
        version: '',
        name: '',
        description: '',
        category: '',
        image: [],
        flow: ModuleFlow.empty(),
        settings: {
            active: false,
            locked: false,
            createdAt: new Date().toISOString(),
            createdBy: ''
        }
    }); };
})(Module || (Module = {}));
var FlowTree = /** @class */ (function () {
    function FlowTree(flow) {
        this.orphans = [];
        this._nodes = new Map();
        this._indexes = new Map();
        this.flow = flow;
        this.root = this.parse(flow.start, flow);
        for (var _i = 0, _a = flow.orphans || []; _i < _a.length; _i++) {
            var orphan = _a[_i];
            this.orphans.push(this.parse(orphan, flow));
        }
        // Add indexes
        var i = 1;
        for (var _b = 0, _c = this.nodes; _b < _c.length; _b++) {
            var node = _c[_b];
            if (!node.id)
                continue;
            var id = FlowTree.encode(node.id, node.version);
            if (!this._indexes.has(id))
                this._indexes.set(id, i++);
        }
    }
    Object.defineProperty(FlowTree.prototype, "depth", {
        get: function () {
            return this.root.depth;
        },
        enumerable: true,
        configurable: true
    });
    Object.defineProperty(FlowTree.prototype, "nodes", {
        get: function () {
            var nodes = [];
            var iterated = new Set();
            for (var _i = 0, _a = this.root.nodes; _i < _a.length; _i++) {
                var node = _a[_i];
                if (iterated.has(node))
                    continue;
                iterated.add(node);
                nodes.push(node);
            }
            for (var _b = 0, _c = this.orphans; _b < _c.length; _b++) {
                var orphan = _c[_b];
                for (var _d = 0, _e = orphan.nodes; _d < _e.length; _d++) {
                    var node = _e[_d];
                    if (iterated.has(node))
                        continue;
                    iterated.add(node);
                    nodes.push(node);
                }
            }
            return nodes;
        },
        enumerable: true,
        configurable: true
    });
    FlowTree.encode = function (arg1, arg2) {
        var _a = typeof arg1 === 'string' ? { id: arg1, version: arg2 } : arg1, id = _a.id, version = _a.version;
        return id + "@" + version;
    };
    FlowTree.decode = function (encoded) {
        var _a = encoded.split('@'), id = _a[0], version = _a[1];
        return { id: id, version: version };
    };
    FlowTree.prototype.canLink = function (source, target, once) {
        if (once === void 0) { once = false; }
        var encoded = FlowTree.encode(source);
        var src = this._nodes.get(encoded);
        if (!src)
            return false;
        // Can not link nodes if the target node is already a child of the source
        // node or the other way around
        for (var _i = 0, _a = src.nodes; _i < _a.length; _i++) {
            var node = _a[_i];
            if (node.id === target.id)
                return false;
        }
        return once ? true : this.canLink(target, source, true);
    };
    FlowTree.prototype.getDepth = function (arg1, arg2) {
        var _this = this;
        var node = this.getNode(arg1, arg2);
        if (!node)
            return 0;
        var parents = this.nodes.filter(function (n) { return n.children.indexOf(node) >= 0; });
        return parents.length
            ? 1 + Math.max.apply(Math, parents.map(function (n) { return _this.getDepth(n.id, n.version); }))
            : 0;
    };
    FlowTree.prototype.getNode = function (arg1, arg2) {
        var encoded = arg2 != undefined ? FlowTree.encode(arg1, arg2) : arg1;
        var index = this._indexes.get(encoded);
        return index ? this.nodes[index - 1] : undefined;
    };
    FlowTree.prototype.getIndex = function (arg1, arg2) {
        var encoded = arg2 != undefined ? FlowTree.encode(arg1, arg2) : arg1;
        var index = this._indexes.get(encoded);
        return index == undefined ? -1 : index;
    };
    FlowTree.prototype.getLabel = function (arg1, arg2) {
        var index = this.getIndex(arg1, arg2);
        return index >= 0 ? ('000' + index).slice(-3) : '';
    };
    FlowTree.prototype.add = function (target, id) {
        var _a;
        var prev = this.flow.blocks[target.id] || [];
        var blocks = Object.assign(Object.assign({}, this.flow.blocks), (_a = {}, _a[target.id] = __spreadArrays(prev, [{ id: id, version: 'v1' }]), _a));
        return Object.assign(Object.assign({}, this.flow), { blocks: blocks });
    };
    FlowTree.prototype.delete = function (target) {
        var _this = this;
        if (this.flow.start.id === target.id)
            return this.flow;
        // Remove every reference of the node from the blocks chain
        var blocks = Object.keys(this.flow.blocks).reduce(function (blocks, id) {
            if (id === target.id)
                return blocks;
            var next = _this.flow.blocks[id];
            blocks[id] =
                next && next.findIndex(function (n) { return n.id === target.id; }) >= 0
                    ? __spreadArrays(next.filter(function (n) { return n.id !== target.id; }), (_this.flow.blocks[target.id] || [])) : next;
            return blocks;
        }, {});
        // Filter block from orphans
        var filtered = this.flow.orphans.filter(function (o) { return o.id !== target.id; });
        if (this.flow.orphans.length === filtered.length)
            return Object.assign(Object.assign({}, this.flow), { blocks: blocks });
        // An orphaned block was deleted, gather the new orphans
        var newOrphans = (this.flow.blocks[target.id] || []).filter(function (n) {
            return Object.keys(blocks).every(function (id) { return blocks[id].every(function (c) { return c.id !== n.id; }); });
        });
        var orphans = __spreadArrays(filtered, newOrphans);
        return Object.assign(Object.assign({}, this.flow), { blocks: blocks, orphans: orphans });
    };
    FlowTree.prototype.unlink = function (source, target) {
        var _a;
        // Unlink blocks
        var next = this.flow.blocks[source];
        var detached = next.find(function (n) { return n.id === target; });
        var blocks = Object.assign(Object.assign({}, this.flow.blocks), (_a = {}, _a[source] = next.filter(function (n) { return n.id !== target; }), _a));
        // Add target to orphaned blocks in case there is no way to reach the block
        var orphaned = Object.keys(blocks).every(function (id) { return blocks[id].every(function (n) { return n.id !== target; }); });
        var orphans = orphaned
            ? __spreadArrays(this.flow.orphans, [detached]) : this.flow.orphans;
        return Object.assign(Object.assign({}, this.flow), { blocks: blocks, orphans: orphans });
    };
    FlowTree.prototype.parse = function (current, flow) {
        var encoded = FlowTree.encode(current);
        var existing = this._nodes.get(encoded);
        if (existing)
            return existing;
        var id = current.id, version = current.version;
        var children = this.parseChildren(current, flow);
        var node = new FlowTreeNode(id, version, children);
        this._nodes.set(encoded, node);
        return node;
    };
    FlowTree.prototype.parseChildren = function (current, flow) {
        var _this = this;
        var next = (flow.blocks || {})[current.id];
        return next ? next.map(function (n) { return _this.parse(n, flow); }).filter(function (n) { return !!n; }) : [];
    };
    return FlowTree;
}());
var FlowTreeNode = /** @class */ (function () {
    function FlowTreeNode(id, version, children) {
        this.id = id;
        this.version = version;
        this.children = children;
    }
    Object.defineProperty(FlowTreeNode.prototype, "depth", {
        get: function () {
            var depths = this.children.map(function (child) { return child.depth; });
            return 1 + Math.max.apply(Math, __spreadArrays([0], depths));
        },
        enumerable: true,
        configurable: true
    });
    Object.defineProperty(FlowTreeNode.prototype, "deepestPath", {
        get: function () {
            var paths = this.children.map(function (child) { return child.deepestPath; });
            var deepest = [];
            for (var _i = 0, paths_1 = paths; _i < paths_1.length; _i++) {
                var path = paths_1[_i];
                if (deepest.length < path.length)
                    deepest = path;
            }
            return __spreadArrays([this], deepest);
        },
        enumerable: true,
        configurable: true
    });
    Object.defineProperty(FlowTreeNode.prototype, "nodes", {
        get: function () {
            var nestedNodes = this.children.map(function (n) { return n.nodes; });
            var nodes = [].concat.apply([], nestedNodes);
            return __spreadArrays([this], nodes);
        },
        enumerable: true,
        configurable: true
    });
    return FlowTreeNode;
}());
var Polyline = /** @class */ (function () {
    function Polyline(points) {
        this.sections = [];
        this.points = points.map(function (_a) {
            var x = _a.x, y = _a.y;
            return [x, y];
        });
        for (var i = 0; i < this.points.length - 1; i++) {
            var p1 = this.points[i];
            var p2 = this.points[i + 1];
            var size = this.distance(p1, p2);
            this.sections.push({ p1: p1, p2: p2, size: size });
        }
    }
    Object.defineProperty(Polyline.prototype, "size", {
        /**
         * Returns the size of the polyline.
         */
        get: function () {
            return this.sections.reduce(function (total, _a) {
                var size = _a.size;
                return total + size;
            }, 0);
        },
        enumerable: true,
        configurable: true
    });
    Object.defineProperty(Polyline.prototype, "middle", {
        /**
         * Returns the middle of the polyline.
         */
        get: function () {
            // Middle of the line in terms of size
            var target = this.size / 2;
            // Move along sections until we find the section that exceeds our target,
            // from this section we can calculate the middle point's coordinated.
            var cur = 0;
            for (var _i = 0, _a = this.sections; _i < _a.length; _i++) {
                var section = _a[_i];
                var next = cur + section.size;
                if (next > target)
                    return this.along(section, target - cur);
                cur = next;
            }
            // Polyline has no sections
            return [0, 0];
        },
        enumerable: true,
        configurable: true
    });
    /**
     * Moves along the section by the specified distance.
     * @param section
     * @param distance
     */
    Polyline.prototype.along = function (section, distance) {
        var _a = section.p1, x1 = _a[0], y1 = _a[1];
        var _b = section.p2, x2 = _b[0], y2 = _b[1];
        var k = distance / section.size;
        return [k * x2 + (1 - k) * x1, k * y2 + (1 - k) * y1];
    };
    /**
     * Calculate the distance between two points.
     * @param p1 Start point
     * @param p2 End point
     */
    Polyline.prototype.distance = function (_a, _b) {
        var x1 = _a[0], y1 = _a[1];
        var x2 = _b[0], y2 = _b[1];
        var horDistance = Math.pow(x2 - x1, 2);
        var verDistance = Math.pow(y2 - y1, 2);
        return Math.sqrt(horDistance + verDistance);
    };
    return Polyline;
}());
var storedFiles = function (arg) {
    if ('flow' in arg)
        return storedModule(arg);
    else if ('type' in arg)
        return storedElement(arg);
    else
        return storedBlock(arg);
};
var storedModule = function (module) {
    return module.image;
};
var storedBlock = function (block) {
    return [].concat.apply([], block.elements.map(storedElement));
};
var storedElement = function (element) {
    switch (element.type) {
        case 'audio':
        case 'download':
        case 'image':
        case 'video':
            return element.location;
        case 'checkbox':
        case 'radio':
        case 'sort':
            return storedOptions(element.options);
        case 'matrix':
            var rows = storedOptions(element.rows);
            var columns = storedOptions(element.columns);
            return __spreadArrays(rows, columns);
        case 'table':
            return storedOptions(element.columns);
        default:
            return [];
    }
};
var storedOptions = function (options) {
    return options
        .filter(function (option) { return 'image' in option; })
        .map(function (option) { return option.image; });
};
export { Block as B, FlowTree as F, ModuleFlow as M, Polyline as P, BlockElement as a, Module as b, FlowTreeNode as c, enUs as e, label as l, nl as n, storedFiles as s };
