UNPKG

@obliczeniowo/elementary

Version:
2,511 lines 150 kB
import * as i0 from '@angular/core';
import { ViewContainerRef, ViewChild, HostBinding, Output, Input, Component, Injectable, EventEmitter, HostListener, ViewChildren, NgModule } from '@angular/core';
import * as i2$1 from '@angular/common';
import { CommonModule } from '@angular/common';
import * as i1 from '@obliczeniowo/elementary/input';
import { InputModule } from '@obliczeniowo/elementary/input';
import * as i2$3 from '@obliczeniowo/elementary/connectors';
import { RelationConnectorComponent, ConnectorsModule } from '@obliczeniowo/elementary/connectors';
import * as i2$2 from '@obliczeniowo/elementary/dropdown-select';
import { DropdownSelectModule } from '@obliczeniowo/elementary/dropdown-select';
import * as i3$1 from '@obliczeniowo/elementary/menu';
import { MenuModule } from '@obliczeniowo/elementary/menu';
import * as i2 from '@obliczeniowo/elementary/buttons';
import { ButtonsModule } from '@obliczeniowo/elementary/buttons';
import * as uuid from 'uuid';
import { Point2D } from '@obliczeniowo/elementary/classes';
import { keys } from '@obliczeniowo/elementary/objects';
import { EventEmitterExt } from '@obliczeniowo/elementary/rx-js-ext';
import { ElementaryMath } from '@obliczeniowo/elementary/math';
import { toCamelCase, allWordsFirstToUpper, firstToUpper } from '@obliczeniowo/elementary/utils';
import * as i3 from '@angular/forms';
import { FormsModule } from '@angular/forms';

class ModellerBoxComponent {
    ref;
    changes;
    modeller;
    model;
    /** world (global translation) */
    world = new Point2D();
    /** local box only translation */
    translate = new Point2D();
    /** translation for dragging this stuff */
    offset = new Point2D();
    // to force display this box on top of any other one in view by set z-index
    index = 0;
    /** Unique per box type registration */
    id;
    /** globally unique id as meany the same type boxes can exists */
    subId;
    /** used only for 'input'/'output' type of model */
    inputModel;
    /** parent */
    parent;
    /** */
    options;
    /** used only for 'input'/'output' type of model */
    outputChanged = new EventEmitterExt();
    /** */
    optionsChanged = new EventEmitterExt();
    dragBox = new EventEmitterExt();
    connector = new EventEmitterExt();
    remove = new EventEmitterExt();
    /** remove connector by id */
    removeConnector = new EventEmitterExt();
    connectors;
    userModel;
    dynamic = false;
    type = 'input';
    get zIndex() {
        return this.index;
    }
    get transform() {
        return this.world.add(this.translate).add(this.offset).toCssTranslate('px');
    }
    containerRef;
    components = [];
    constructor(ref, changes, modeller) {
        this.ref = ref;
        this.changes = changes;
        this.modeller = modeller;
    }
    ngOnChanges(changes) {
        if (changes.model && this.containerRef || this.model && changes.containerRef) {
            this.reload();
        }
        if (changes.inputModel && this.inputModel && this.model && this.containerRef) {
            this.reload();
        }
        if (changes.options && this.containerRef) {
            this.userModel = { ...this.options?.userModel, ...this.userModel };
            this.reload();
        }
        if (changes.translate || changes.offset) {
            this.components.forEach(com => com.instance.recalc());
        }
    }
    ngAfterViewInit() {
        this.reload();
    }
    allConnectors() {
        const connectors = [];
        this.components.forEach(component => {
            if (component.instance.left) {
                connectors.push(component.instance.left);
            }
            if (component.instance.right) {
                connectors.push(component.instance.right);
            }
        });
        return connectors;
    }
    getBoxItemModel() {
        const options = {};
        this.components.forEach(component => Object.assign(options, component.instance.options));
        options.userModel = this.userModel;
        return {
            id: this.id,
            subId: this.subId,
            options: {
                ...options,
                position: this.translate,
            }
        };
    }
    setConnectors(connectors) {
        this.connectors = connectors;
        const arr = Array.from(this.connectors);
        this.components.forEach(component => {
            const id = component.instance.getFullId();
            component.instance.left = undefined;
            component.instance.right = undefined;
            arr.filter(conn => conn.connector?.left === id || conn.connector?.right === id).forEach(conn => {
                if (conn.connector?.left === id) {
                    component.instance.setConnector('left', conn || undefined);
                }
                if (conn.connector?.right === id) {
                    component.instance.setConnector('right', conn || undefined);
                }
            });
        });
    }
    clear() {
        this.components.forEach(component => {
            component.instance.connector.clearSubscriptions();
            component.instance.remove.clearSubscriptions();
            component.instance.changed.clearSubscriptions();
            component.instance.optionsChanged.clearSubscriptions();
            component.destroy();
        });
        this.components = [];
    }
    toDynamic() {
        this.dynamic = true;
    }
    transformUserModel() {
        if (Array.isArray(this.userModel)) {
            const first = this.userModel[0];
            const obj = {};
            const firstKeys = keys(first);
            firstKeys.forEach(key => obj[key] = []);
            this.userModel.forEach(item => {
                firstKeys.forEach(key => obj[key].push(item[key]));
            });
            return obj;
        }
        return this.userModel;
    }
    reload() {
        this.clear();
        this.userModel = this.userModel || this.options?.userModel;
        let userModel = this.transformUserModel();
        (this.model?.type === 'in-out' || !this.inputModel ? this.model?.components || [] :
            keys({ ...this.inputModel, ...userModel })
                .map(key => {
                return {
                    type: this.modeller.getConnector(),
                    id: key,
                    value: this.model?.type === 'input' ? this.inputModel?.[key] : '',
                    removable: !!(userModel || {})?.[key]
                };
            })).forEach(com => {
            const component = this.containerRef.createComponent(com.type, {
                injector: this.containerRef.injector,
            });
            component.instance.connector.subscribe((connector) => {
                this.connector.emit(connector);
            });
            component.instance.optionsChanged.subscribe(() => {
                this.optionsChanged.emit();
            });
            component.instance.changed.subscribe(async () => {
                if (this.model?.type === 'output') {
                    const values = {};
                    this.components.forEach(component => values[component.instance.id] = component.instance.value);
                    if (!this.subId) {
                        this.outputChanged.emit(values);
                    }
                }
            });
            component.setInput('parent', this);
            component.setInput('id', com.id);
            component.setInput('subId', this.subId);
            component.setInput('inputOutputComponent', com?.inputOutputComponent);
            component.setInput('type', com.connectorType || this.model?.type || 'in-out');
            component.setInput('removable', com.removable);
            component.setInput('options', this.options);
            component.setInput('translations', this.model?.translations);
            this.setRemove(component, com);
            if ('input' === this.model?.type) {
                component.setInput('value', com.value);
            }
            // required to start triggering hooks without that is not trigger ngOnChanges/ngOnInit/ngAfterViewInit
            component.changeDetectorRef.detectChanges();
            this.components.push(component);
        });
    }
    setRemove(component, com) {
        if (com.removable) {
            component.instance.remove.subscribe((id) => {
                if (this.userModel && !Array.isArray(this.userModel)) {
                    delete this.userModel[id];
                }
                ;
                this.removeConnector.emit(`${this.id}:${this.subId}:${id}`);
                this.reload();
                this.options = { ...this.options, userModel: this.userModel };
                this.optionsChanged.emit();
                this?.parent?.setConnectors(this.restoreConnectors);
            });
        }
    }
    restoreConnectors() {
        if (this && this.connectors) {
            this.setConnectors(this.connectors);
        }
    }
    add(name) {
        if (!name) {
            if (!this.userModel) {
                name = (keys(this.userModel || {}).length + 1).toString();
            }
            else if (!Array.isArray(this.userModel)) {
                let start = 0;
                do {
                    start++;
                    name = start.toString();
                } while ((this.userModel || {})?.[start] === name);
            }
        }
        if (name === '' || keys({ ...this.inputModel, ...this.userModel }).find(key => key === name)) {
            return;
        }
        this.userModel = { ...this.userModel, [name]: name };
        this.reload();
        this.restoreConnectors();
        this.options = { ...this.options, userModel: this.userModel };
        this.optionsChanged.emit();
    }
    item(parentId, subId, id) {
        return this.components.find(item => this.id === parentId && item.instance.subId === subId && item.instance.id === id);
    }
    recalc() {
        this.components.forEach(com => com.instance.recalc());
    }
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: ModellerBoxComponent, deps: [{ token: i0.ElementRef }, { token: i0.ChangeDetectorRef }, { token: ModellerService }], target: i0.ɵɵFactoryTarget.Component });
    static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.4", type: ModellerBoxComponent, isStandalone: false, selector: "obl-modeller-box", inputs: { model: "model", world: "world", translate: "translate", offset: "offset", index: "index", id: "id", subId: "subId", inputModel: "inputModel", parent: "parent", options: "options" }, outputs: { outputChanged: "outputChanged", optionsChanged: "optionsChanged", dragBox: "dragBox", connector: "connector", remove: "remove", removeConnector: "removeConnector" }, host: { properties: { "style.z-index": "this.zIndex", "style.transform": "this.transform" } }, viewQueries: [{ propertyName: "containerRef", first: true, predicate: ["containerRef"], descendants: true, read: ViewContainerRef }], usesOnChanges: true, ngImport: i0, template: "<div\n  class=\"header\"\n  (mousedown)=\"dragBox.emit({ mouse: $event, component: this })\"\n>\n  {{ model?.translations?.[model?.title || ''] || model?.title }}\n  @if (model?.type === 'in-out') {\n    <button oblButton [icon]=\"'cancel'\" (click)=\"remove.emit(this)\"></button>\n  }\n</div>\n\n<div>\n  <ng-container #containerRef></ng-container>\n</div>\n\n@if (model?.type === 'output' || dynamic) {\n  <div class=\"output\">\n    @if (type === 'input') {\n    <obl-input-wrapper [label]=\"modeller.getTranslation('Add new field')\">\n      <input oblInput #newName type=\"text\"/>\n      <button oblButton [icon]=\"'add'\" (click)=\"add(newName.value); newName.value = ''\" required suffix></button>\n    </obl-input-wrapper>\n  } @else {\n    <button oblButton [icon]=\"'add'\" (click)=\"add()\">{{ modeller.getTranslation('Add new input') }}</button>\n  }\n  </div>\n}\n", styles: [":host{position:absolute;display:block;width:250px;height:auto;border:1px var(--default-border-color) solid;border-radius:10px;background-color:var(--default-background-color)}.header{padding:5px;text-align:center;border-bottom:1px var(--default-border-color) solid;cursor:move;position:relative}.header button{position:absolute;right:2px;top:2px;border-radius:50%;--obl-icon-width: 10px;--obl-default-button-padding: 5px}.output{padding:5px}.output button{margin-left:auto;border-radius:5px;--obl-icon-width: 25px;--obl-default-button-padding: 5px 15px 5px 5px}.output obl-input-wrapper button{border-radius:50%;--obl-icon-width: 10px;--obl-default-button-padding: 5px}\n"], dependencies: [{ kind: "directive", type: i1.InputDirective, selector: "input[oblInput]", inputs: ["outlined"], exportAs: ["oblInput"] }, { kind: "component", type: i1.InputWrapperComponent, selector: "obl-input-wrapper", inputs: ["label", "display", "cancellable", "step", "errors", "translations", "labelAnimation", "small"], outputs: ["loaded"] }, { kind: "directive", type: i2.ButtonDirective, selector: "oblButton, [oblButton]", inputs: ["oblButton", "icon", "blockWhenLoading", "loading", "toggle", "selected", "link", "target"], exportAs: ["oblButton"] }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: ModellerBoxComponent, decorators: [{
            type: Component,
            args: [{ selector: 'obl-modeller-box', standalone: false, template: "<div\n  class=\"header\"\n  (mousedown)=\"dragBox.emit({ mouse: $event, component: this })\"\n>\n  {{ model?.translations?.[model?.title || ''] || model?.title }}\n  @if (model?.type === 'in-out') {\n    <button oblButton [icon]=\"'cancel'\" (click)=\"remove.emit(this)\"></button>\n  }\n</div>\n\n<div>\n  <ng-container #containerRef></ng-container>\n</div>\n\n@if (model?.type === 'output' || dynamic) {\n  <div class=\"output\">\n    @if (type === 'input') {\n    <obl-input-wrapper [label]=\"modeller.getTranslation('Add new field')\">\n      <input oblInput #newName type=\"text\"/>\n      <button oblButton [icon]=\"'add'\" (click)=\"add(newName.value); newName.value = ''\" required suffix></button>\n    </obl-input-wrapper>\n  } @else {\n    <button oblButton [icon]=\"'add'\" (click)=\"add()\">{{ modeller.getTranslation('Add new input') }}</button>\n  }\n  </div>\n}\n", styles: [":host{position:absolute;display:block;width:250px;height:auto;border:1px var(--default-border-color) solid;border-radius:10px;background-color:var(--default-background-color)}.header{padding:5px;text-align:center;border-bottom:1px var(--default-border-color) solid;cursor:move;position:relative}.header button{position:absolute;right:2px;top:2px;border-radius:50%;--obl-icon-width: 10px;--obl-default-button-padding: 5px}.output{padding:5px}.output button{margin-left:auto;border-radius:5px;--obl-icon-width: 25px;--obl-default-button-padding: 5px 15px 5px 5px}.output obl-input-wrapper button{border-radius:50%;--obl-icon-width: 10px;--obl-default-button-padding: 5px}\n"] }]
        }], ctorParameters: () => [{ type: i0.ElementRef }, { type: i0.ChangeDetectorRef }, { type: ModellerService }], propDecorators: { model: [{
                type: Input
            }], world: [{
                type: Input
            }], translate: [{
                type: Input
            }], offset: [{
                type: Input
            }], index: [{
                type: Input
            }], id: [{
                type: Input
            }], subId: [{
                type: Input
            }], inputModel: [{
                type: Input
            }], parent: [{
                type: Input
            }], options: [{
                type: Input
            }], outputChanged: [{
                type: Output
            }], optionsChanged: [{
                type: Output
            }], dragBox: [{
                type: Output
            }], connector: [{
                type: Output
            }], remove: [{
                type: Output
            }], removeConnector: [{
                type: Output
            }], zIndex: [{
                type: HostBinding,
                args: ['style.z-index']
            }], transform: [{
                type: HostBinding,
                args: ['style.transform']
            }], containerRef: [{
                type: ViewChild,
                args: ['containerRef', { read: ViewContainerRef }]
            }] } });

class ConnectorItemComponent {
    ref;
    changes;
    /** */
    left;
    /** */
    right;
    /** */
    parent;
    /** Unique per box type registration */
    id;
    /** Globally unique id as meany the same type boxes can exists */
    subId;
    /** */
    inputOutputComponent;
    /** */
    type = 'in-out';
    /** reserved only for input/output */
    value;
    /** if you can remove item */
    removable;
    /** */
    options;
    /** */
    translations;
    connector = new EventEmitterExt();
    /** emit id to remove item */
    remove = new EventEmitterExt();
    changed = new EventEmitterExt();
    optionsChanged = new EventEmitterExt();
    component;
    containerRef;
    getFullId() {
        return `${this.parent?.id}:${this.subId}:${this.id}`;
    }
    constructor(ref, changes) {
        this.ref = ref;
        this.changes = changes;
    }
    setConnector(side, connector) {
        const set = (component) => {
            if (fullId.includes('get-request')) {
                component.instance.get().then();
            }
            else {
                component.setInput('toTransform', this.value);
            }
            component.changeDetectorRef.detectChanges();
        };
        if (this[side]) {
            this[side]?.input.clearSubscriptions();
        }
        this[side] = connector;
        const fullId = this.getFullId();
        if (side === 'right') {
            this.right?.input.subscribe((value) => {
                this.value = value?.data;
                if (value) {
                    this.changed.emit(this.value);
                }
                if (value?.stack.includes(fullId)) {
                    throw new Error('Endless loop');
                }
                if (this.component) {
                    set(this.component);
                }
                else {
                    this.left?.input.next({ stack: [...(value?.stack || []), fullId], data: this.value });
                }
                this.changes.detectChanges();
            });
        }
        else {
            if (this.component) {
                set(this.component);
                this.left?.input.next({ stack: [...(this.right?.input.getValue()?.stack || []), fullId], data: this.component.instance.value });
            }
            else {
                this.left?.input.next({ stack: [...(this.right?.input.getValue()?.stack || []), fullId], data: this.value });
                this.changed.emit(this.value);
            }
        }
        this.recalc();
    }
    clicked(side, connPoint) {
        if (this.parent?.parent?.removeEmptyConnector(this.getFullId(), side === 'left' ? 'right' : 'left')) {
            setTimeout(() => this.clicked(side, connPoint));
        }
        if (this[side === 'left' ? 'right' : 'left']) {
            return;
        }
        const position = this.getPos(connPoint);
        this.connector.emit({
            [side === 'left' ? 'right' : 'left']: this.getFullId(),
            [side === 'left' ? 'end' : 'start']: position
        });
    }
    ngOnChanges(changes) {
        if (changes.inputOutputComponent && this.containerRef || this.inputOutputComponent && changes.containerRef) {
            this.reload();
        }
        if (changes.options && changes.containerRef) {
            this.reload();
        }
        if (changes.value) {
            this.changed.emit(this.value);
            if (this.component) {
                this.component.setInput('toTransform', this.value);
                this.component.changeDetectorRef.detectChanges();
            }
            else {
                this.left?.input.next({ stack: [...(this.right?.input.getValue()?.stack || []), this.getFullId()], data: this.value });
            }
        }
    }
    ngAfterViewInit() {
        this.reload();
    }
    getPos(el) {
        let parent = el;
        let position = new Point2D(el.offsetLeft, el.offsetTop);
        do {
            parent = parent.parentElement;
            if (parent) {
                position = position.add(new Point2D(parent.offsetLeft, parent.offsetTop));
            }
            if (parent?.parentElement?.nodeName === 'OBL-MODELLER-SPACE') {
                break;
            }
        } while (parent);
        return position.add(this.parent?.translate || new Point2D()).add(this.parent?.offset || new Point2D()).add(new Point2D(5, -18));
    }
    recalc() {
        if (this.left) {
            const left = this.ref.nativeElement.querySelector('div.output-connector');
            if (this.left.connector) {
                this.left.connector.start = this.getPos(left);
            }
        }
        if (this.right) {
            const right = this.ref.nativeElement.querySelector('div.input-connector');
            if (this.right.connector) {
                this.right.connector.end = this.getPos(right);
            }
        }
    }
    transformed = (value) => {
        this.left?.input.next({ stack: [...(value?.stack || []), this.getFullId], data: value });
        this.options = this.component?.instance.options;
        if (!value) {
            this.value = undefined;
            this.changes.detectChanges();
        }
    };
    reload() {
        const { component, inputOutputComponent } = this;
        if (component) {
            component.instance.transformed.clearSubscriptions();
            component.instance.optionsChanged.clearSubscriptions();
            component.instance.changed.clearSubscriptions();
            component.destroy();
        }
        if (inputOutputComponent) {
            this.component = this.containerRef.createComponent(inputOutputComponent, {
                injector: this.containerRef.injector,
            });
            this.component.instance.transformed.subscribe(this.transformed);
            this.component.instance.optionsChanged.subscribe(() => this.optionsChanged.emit());
            this.component.setInput('toTransform', this.value);
            this.component.setInput('options', this.options);
            this.component.setInput('translations', this.translations);
            this.component.changeDetectorRef.detectChanges();
        }
    }
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: ConnectorItemComponent, deps: [{ token: i0.ElementRef }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
    static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.4", type: ConnectorItemComponent, isStandalone: false, selector: "obl-connector-item", inputs: { left: "left", right: "right", parent: "parent", id: "id", subId: "subId", inputOutputComponent: "inputOutputComponent", type: "type", value: "value", removable: "removable", options: "options", translations: "translations" }, outputs: { connector: "connector", remove: "remove", changed: "changed", optionsChanged: "optionsChanged" }, viewQueries: [{ propertyName: "containerRef", first: true, predicate: ["containerRef"], descendants: true, read: ViewContainerRef }], usesOnChanges: true, ngImport: i0, template: "@if (['in-out', 'output'].includes(type)) {\n  <div\n    class=\"input input-connector\"\n    [class.connected]=\"right\"\n    #input\n    (click)=\"clicked('left', input)\"\n  >\n    &gt;\n  </div>\n}\n<div class=\"container\">\n  @if (!inputOutputComponent) {\n    <div>{{ id }}: {{ value | json }}</div>\n  }\n  <ng-container #containerRef></ng-container>\n</div>\n@if (['in-out', 'input'].includes(type)) {\n  <div\n    class=\"output output-connector\"\n    [class.connected]=\"left\"\n    #output\n    (click)=\"clicked('right', output)\"\n  >\n    &lt;\n  </div>\n}\n\n@if (removable) {\n  <button\n    oblButton\n    [icon]=\"'cancel'\"\n    (click)=\"remove.emit(id)\"\n  ></button>\n}", styles: [":host{position:relative;width:100%;display:block;padding:5px}.output,.input{position:absolute;cursor:pointer}.output{right:5px;top:5px}.input{left:-5px;top:5}.container{max-width:calc(100% - 10px);white-space:nowrap;overflow:hidden}button{position:absolute;right:16px;top:5px;border-radius:50%;--obl-icon-width: 10px;--obl-default-button-padding: 5px}.connected{font-weight:700;color:red}\n"], dependencies: [{ kind: "directive", type: i2.ButtonDirective, selector: "oblButton, [oblButton]", inputs: ["oblButton", "icon", "blockWhenLoading", "loading", "toggle", "selected", "link", "target"], exportAs: ["oblButton"] }, { kind: "pipe", type: i2$1.JsonPipe, name: "json" }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: ConnectorItemComponent, decorators: [{
            type: Component,
            args: [{ selector: 'obl-connector-item', standalone: false, template: "@if (['in-out', 'output'].includes(type)) {\n  <div\n    class=\"input input-connector\"\n    [class.connected]=\"right\"\n    #input\n    (click)=\"clicked('left', input)\"\n  >\n    &gt;\n  </div>\n}\n<div class=\"container\">\n  @if (!inputOutputComponent) {\n    <div>{{ id }}: {{ value | json }}</div>\n  }\n  <ng-container #containerRef></ng-container>\n</div>\n@if (['in-out', 'input'].includes(type)) {\n  <div\n    class=\"output output-connector\"\n    [class.connected]=\"left\"\n    #output\n    (click)=\"clicked('right', output)\"\n  >\n    &lt;\n  </div>\n}\n\n@if (removable) {\n  <button\n    oblButton\n    [icon]=\"'cancel'\"\n    (click)=\"remove.emit(id)\"\n  ></button>\n}", styles: [":host{position:relative;width:100%;display:block;padding:5px}.output,.input{position:absolute;cursor:pointer}.output{right:5px;top:5px}.input{left:-5px;top:5}.container{max-width:calc(100% - 10px);white-space:nowrap;overflow:hidden}button{position:absolute;right:16px;top:5px;border-radius:50%;--obl-icon-width: 10px;--obl-default-button-padding: 5px}.connected{font-weight:700;color:red}\n"] }]
        }], ctorParameters: () => [{ type: i0.ElementRef }, { type: i0.ChangeDetectorRef }], propDecorators: { left: [{
                type: Input
            }], right: [{
                type: Input
            }], parent: [{
                type: Input
            }], id: [{
                type: Input
            }], subId: [{
                type: Input
            }], inputOutputComponent: [{
                type: Input
            }], type: [{
                type: Input
            }], value: [{
                type: Input
            }], removable: [{
                type: Input
            }], options: [{
                type: Input
            }], translations: [{
                type: Input
            }], connector: [{
                type: Output
            }], remove: [{
                type: Output
            }], changed: [{
                type: Output
            }], optionsChanged: [{
                type: Output
            }], containerRef: [{
                type: ViewChild,
                args: ['containerRef', { read: ViewContainerRef }]
            }] } });

class IntegerFilterConnectorComponent {
    toTransform;
    /** */
    options;
    /** */
    translations;
    transformed = new EventEmitterExt();
    optionsChanged = new EventEmitterExt();
    value;
    items = [
        {
            id: 'to-floor',
            text: 'To floor',
        },
        {
            id: 'to-ceil',
            text: 'To ceil',
        },
    ];
    selected = this.items[0].id;
    changed(item) {
        this.selected = item.id;
        this.transform();
        this.optionsChanged.emit();
    }
    transform() {
        if (this.toTransform) {
            this.options = { ...this.options, selected: this.selected };
            const transform = (value) => {
                switch (this.selected) {
                    case 'to-floor': {
                        return Math.floor(value);
                    }
                    case 'to-ceil': {
                        return Math.ceil(value);
                    }
                }
                return undefined;
            };
            if (typeof this.toTransform === 'number') {
                this.value = transform(this.toTransform) || 0;
            }
            else if (this.toTransform instanceof Array) {
                this.value = this.toTransform.map((value => transform(value) || 0));
            }
        }
        else {
            this.value = undefined;
        }
        this.transformed.emit(this.value);
    }
    ngOnInit() {
        this.items.forEach((item, index) => {
            this.items[index].text = this.translations?.[item.text] || item.text;
        });
    }
    ngOnChanges(changes) {
        if (changes.toTransform) {
            this.transform();
        }
        if (changes.options) {
            this.selected = this?.options?.selected ?? this.selected;
            this.transform();
        }
    }
    ngOnDestroy() {
        this.transformed.unsubscribe();
    }
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: IntegerFilterConnectorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
    static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.0.4", type: IntegerFilterConnectorComponent, isStandalone: false, selector: "obl-integer-filter-connector", inputs: { toTransform: "toTransform", options: "options", translations: "translations" }, outputs: { transformed: "transformed", optionsChanged: "optionsChanged" }, usesOnChanges: true, ngImport: i0, template: "<obl-dropdown-select\n  [items]=\"items\"\n  (changed)=\"changed($event)\"\n  [select]=\"selected\"\n  [label]=\"translations?.['Operation type'] || 'Operation type'\"\n></obl-dropdown-select>\n", styles: [""], dependencies: [{ kind: "component", type: i2$2.DropdownSelectComponent, selector: "obl-dropdown-select", inputs: ["model", "items", "label", "labelAnimation", "templateSuffix", "templatePrefix", "search", "regExp", "select", "disabled"], outputs: ["changed"] }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: IntegerFilterConnectorComponent, decorators: [{
            type: Component,
            args: [{ selector: 'obl-integer-filter-connector', standalone: false, template: "<obl-dropdown-select\n  [items]=\"items\"\n  (changed)=\"changed($event)\"\n  [select]=\"selected\"\n  [label]=\"translations?.['Operation type'] || 'Operation type'\"\n></obl-dropdown-select>\n" }]
        }], propDecorators: { toTransform: [{
                type: Input
            }], options: [{
                type: Input
            }], translations: [{
                type: Input
            }], transformed: [{
                type: Output
            }], optionsChanged: [{
                type: Output
            }] } });

class ConvertToHistogramComponent {
    toTransform;
    /** */
    options;
    /** */
    translations;
    transformed = new EventEmitterExt();
    optionsChanged = new EventEmitterExt();
    value;
    ranges = 5;
    transform() {
        if (this.toTransform && this.toTransform instanceof Array) {
            const minMax = ElementaryMath.getMinMax(this.toTransform);
            const dm = (minMax.max - minMax.min) / this.ranges;
            if (dm === 0) {
                this.value = [this.toTransform.length];
                return;
            }
            const value = new Array(this.ranges).fill(0);
            this.toTransform.forEach(item => value[Math.min(Math.floor((item - minMax.min) / dm), this.ranges - 1)] += 1);
            this.value = value;
        }
        else {
            this.value = undefined;
        }
        this.transformed.emit(this.value);
    }
    changed(event) {
        this.ranges = +event.value;
        this.options = { ...this.options, ranges: this.ranges };
        this.transform();
        this.optionsChanged.emit();
    }
    ngOnChanges(changes) {
        if (changes.toTransform) {
            this.transform();
        }
        if (changes.options) {
            this.ranges = this?.options?.ranges || this.ranges;
            this.transform();
        }
    }
    ngOnDestroy() {
        this.transformed.unsubscribe();
    }
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: ConvertToHistogramComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
    static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.0.4", type: ConvertToHistogramComponent, isStandalone: false, selector: "obl-convert-to-histogram", inputs: { toTransform: "toTransform", options: "options", translations: "translations" }, outputs: { transformed: "transformed", optionsChanged: "optionsChanged" }, usesOnChanges: true, ngImport: i0, template: "<obl-input-wrapper [label]=\"translations?.Range || 'Range'\">\n  <input type=\"number\" oblInput [value]=\"ranges\" (change)=\"changed($event.target)\" min=\"2\" />\n</obl-input-wrapper>", styles: [""], dependencies: [{ kind: "directive", type: i1.InputDirective, selector: "input[oblInput]", inputs: ["outlined"], exportAs: ["oblInput"] }, { kind: "component", type: i1.InputWrapperComponent, selector: "obl-input-wrapper", inputs: ["label", "display", "cancellable", "step", "errors", "translations", "labelAnimation", "small"], outputs: ["loaded"] }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: ConvertToHistogramComponent, decorators: [{
            type: Component,
            args: [{ selector: 'obl-convert-to-histogram', standalone: false, template: "<obl-input-wrapper [label]=\"translations?.Range || 'Range'\">\n  <input type=\"number\" oblInput [value]=\"ranges\" (change)=\"changed($event.target)\" min=\"2\" />\n</obl-input-wrapper>" }]
        }], propDecorators: { toTransform: [{
                type: Input
            }], options: [{
                type: Input
            }], translations: [{
                type: Input
            }], transformed: [{
                type: Output
            }], optionsChanged: [{
                type: Output
            }] } });

class RangeFilterComponent {
    toTransform;
    /** */
    options;
    /** */
    translations;
    transformed = new EventEmitterExt();
    optionsChanged = new EventEmitterExt();
    max = 10;
    min = 0;
    value;
    updateOptions() {
        this.options = { ...this.options, min: this.min, max: this.max };
    }
    setMin(event) {
        this.min = +(event.target.value ?? this.min);
        this.updateOptions();
        this.transform();
        this.optionsChanged.emit();
    }
    setMax(event) {
        this.max = +(event.target.value ?? this.max);
        this.updateOptions();
        this.transform();
        this.optionsChanged.emit();
    }
    transform() {
        if (this.toTransform instanceof Array) {
            this.value = this.toTransform.filter(value => value >= this.min && value <= this.max);
        }
        else {
            this.value = undefined;
        }
        this.transformed.emit(this.value);
    }
    ngOnChanges(changes) {
        if (changes.toTransform) {
            this.transform();
        }
        if (changes.options) {
            this.min = this.options?.min || this.min;
            this.max = this.options?.max || this.max;
            this.transform();
        }
    }
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: RangeFilterComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
    static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.0.4", type: RangeFilterComponent, isStandalone: false, selector: "obl-range-filter", inputs: { toTransform: "toTransform", options: "options", translations: "translations" }, outputs: { transformed: "transformed", optionsChanged: "optionsChanged" }, usesOnChanges: true, ngImport: i0, template: "<obl-input-wrapper [label]=\"translations?.['Min'] || 'Min'\" [step]=\"1\">\n  <input type=\"number\" oblInput [value]=\"min\" [max]=\"max\" step=\"any\" (change)=\"setMin($event)\" />\n</obl-input-wrapper>\n\n<obl-input-wrapper [label]=\"translations?.['Max'] || 'Max'\" [step]=\"1\">\n  <input type=\"number\" oblInput [value]=\"max\" [min]=\"min\" step=\"any\" (change)=\"setMax($event)\" />\n</obl-input-wrapper>", styles: [""], dependencies: [{ kind: "directive", type: i1.InputDirective, selector: "input[oblInput]", inputs: ["outlined"], exportAs: ["oblInput"] }, { kind: "component", type: i1.InputWrapperComponent, selector: "obl-input-wrapper", inputs: ["label", "display", "cancellable", "step", "errors", "translations", "labelAnimation", "small"], outputs: ["loaded"] }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: RangeFilterComponent, decorators: [{
            type: Component,
            args: [{ selector: 'obl-range-filter', standalone: false, template: "<obl-input-wrapper [label]=\"translations?.['Min'] || 'Min'\" [step]=\"1\">\n  <input type=\"number\" oblInput [value]=\"min\" [max]=\"max\" step=\"any\" (change)=\"setMin($event)\" />\n</obl-input-wrapper>\n\n<obl-input-wrapper [label]=\"translations?.['Max'] || 'Max'\" [step]=\"1\">\n  <input type=\"number\" oblInput [value]=\"max\" [min]=\"min\" step=\"any\" (change)=\"setMax($event)\" />\n</obl-input-wrapper>" }]
        }], propDecorators: { toTransform: [{
                type: Input
            }], options: [{
                type: Input
            }], translations: [{
                type: Input
            }], transformed: [{
                type: Output
            }], optionsChanged: [{
                type: Output
            }] } });

class StringConverterComponent {
    toTransform;
    /** */
    options;
    /** */
    translations;
    transformed = new EventEmitterExt();
    optionsChanged = new EventEmitterExt();
    items = [
        {
            id: 'to-upper-case',
            text: 'To upper case',
        },
        {
            id: 'to-lower-case',
            text: 'To lower case',
        },
        {
            id: 'first-to-upper-case',
            text: 'First letter to upper case'
        },
        {
            id: 'word-first-to-upper-case',
            text: 'Word first letter to upper case'
        },
        {
            id: 'camel-case',
            text: 'To camel case'
        },
        {
            id: 'split',
            text: 'Split',
        },
        {
            id: 'JSON-parse',
            text: 'JSON parse',
        },
        {
            id: 'substring',
            text: 'Substring',
        },
    ];
    selected = this.items[0].id;
    lastError;
    value;
    split = ' ';
    start = 0;
    end = 5;
    transform() {
        if (this.toTransform && typeof this.toTransform === 'string') {
            switch (this.selected) {
                case 'to-upper-case':
                    {
                        this.value = this.toTransform.toUpperCase();
                    }
                    break;
                case 'to-lower-case':
                    {
                        this.value = this.toTransform.toLowerCase();
                    }
                    break;
                case 'first-to-upper-case':
                    {
                        this.value = firstToUpper(this.toTransform);
                    }
                    break;
                case 'word-first-to-upper-case':
                    {
                        this.value = allWordsFirstToUpper(this.toTransform);
                    }
                    break;
                case 'camel-case':
                    {
                        this.value = toCamelCase(this.toTransform);
                    }
                    break;
                case 'split':
                    {
                        this.value = this.toTransform.split(this.split);
                    }
                    break;
                case 'JSON-parse':
                    {
                        try {
                            this.value = JSON.parse(this.toTransform);
                        }
                        catch (error) {
                            this.value = undefined;
                            this.lastError = new Error('String json parse failure');
                        }
                    }
                    break;
                case 'substring':
                    {
                        this.value = this.toTransform.substring(this.start, this.end);
                    }
                    break;
            }
            this.transformed.emit(this.value);
        }
        else {
            this.value = undefined;
            this.transformed.emit(this.value);
            this.lastError = new Error('Value is undefined or is not a string');
        }
    }
    ngOnInit() {
        this.items.forEach((item, index) => {
            this.items[index].text = this.translations?.[item.text] || item.text;
        });
    }
    ngOnChanges(changes) {
        if (changes.toTransform) {
            this.transform();
        }
        if (changes.options) {
            this.selected = this.options?.selected || this.selected;
            this.split = this.options?.split || this.split;
            this.start = this.options?.start || this.start;
            this.end = this.options?.end || this.end;
            this.transform();
        }
    }
    changed(item) {
        this.selected = item.id;
        this.options = { ...this.options, selected: this.selected };
        this.transform();
        this.optionsChanged.emit();
    }
    splitChanged(event) {
        this.split = event.target.value;
        this.options = { ...this.options, split: this.split };
        this.transform();
        this.optionsChanged.emit();
    }
    startChanged(event) {
        this.start = event.target.value;
        this.options = { ...this.options, start: this.start };
        this.transform();
        this.optionsChanged.emit();
    }
    endChanged(event) {
        this.end = event.target.value;
        ;
        this.options = { ...this.options, end: this.end };
        this.transform();
        this.optionsChanged.emit();
    }
    ngOnDestroy() {
        this.transformed.unsubscribe();
    }
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: StringConverterComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
    static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.4", type: StringConverterComponent, isStandalone: false, selector: "obl-string-converter", inputs: { toTransform: "toTransform", options: "options", translations: "translations" }, outputs: { transformed: "transformed", optionsChanged: "optionsChanged" }, usesOnChanges: true, ngImport: i0, template: "<obl-dropdown-select\n  [items]=\"items\"\n  [select]=\"selected\"\n  (changed)=\"changed($event)\"\n  [label]=\"translations?.['Operation type'] || 'Operation type'\"\n></obl-dropdown-select>\n\n@if (selected === 'split') {\n  <obl-input-wrapper [label]=\"translations?.['Split by'] || 'Split by'\">\n    <input type=\"text\" [value]=\"split\" (change)=\"splitChanged($event)\" oblInput />\n  </obl-input-wrapper>\n}\n\n@if (selected === 'substring') {\n  <obl-input-wrapper [label]=\"translations?.Start || 'Start'\" [step]=\"1\">\n    <input\n      type=\"number\"\n      [value]=\"start\"\n      (change)=\"startChanged($event)\"\n      oblInput\n    />\n  </obl-input-wrapper>\n\n  <obl-input-wrapper [label]=\"translations?.End || 'End'\" [step]=\"1\">\n    <input type=\"number\" [value]=\"end\" (change)=\"endChanged($event)\" oblInput />\n  </obl-input-wrapper>\n}\n", styles: [":host obl-input-wrapper{margin-top:5px}\n"], dependencies: [{ kind: "directive", type: i1.InputDirective, selector: "input[oblInput]", inputs: ["outlined"], exportAs: ["oblInput"] }, { kind: "component", type: i1.InputWrapperComponent, selector: "obl-input-wrapper", inputs: ["label", "display", "cancellable", "step", "errors", "translations", "labelAnimation", "small"], outputs: ["loaded"] }, { kind: "component", type: i2$2.DropdownSelectComponent, selector: "obl-dropdown-select", inputs: ["model", "items", "label", "labelAnimation", "templateSuffix", "templatePrefix", "search", "regExp", "select", "disabled"], outputs: ["changed"] }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: StringConverterComponent, decorators: [{
            type: Component,
            args: [{ selector: 'obl-string-converter', standalone: false, template: "<obl-dropdown-select\n  [items]=\"items\"\n  [select]=\"selected\"\n  (changed)=\"changed($event)\"\n  [label]=\"translations?.['Operation type'] || 'Operation type'\"\n></obl-dropdown-select>\n\n@if (selected === 'split') {\n  <obl-input-wrapper [label]=\"translations?.['Split by'] || 'Split by'\">\n    <input type=\"text\" [value]=\"split\" (change)=\"splitChanged($event)\" oblInput />\n  </obl-input-wrapper>\n}\n\n@if (selected === 'substring') {\n  <obl-input-wrapper [label]=\"translations?.Start || 'Start'\" [step]=\"1\">\n    <input\n      type=\"number\"\n      [value]=\"start\"\n      (change)=\"startChanged($event)\"\n      oblInput\n    />\n  </obl-input-wrapper>\n\n  <obl-input-wrapper [label]=\"translations?.End || 'End'\" [step]=\"1\">\n    <input type=\"number\" [value]=\"end\" (change)=\"endChanged($event)\" oblInput />\n  </obl-input-wrapper>\n}\n", styles: [":host obl-input-wrapper{margin-top:5px}\n"] }]
        }], propDecorators: { toTransform: [{
                type: Input
            }], options: [{
                type: Input
            }], translations: [{
                type: Input
            }], transformed: [{
                type: Output
            }], optionsChanged: [{
                type: Output
            }] } });

class SplitBoxComponent extends ModellerBoxComponent {
    reload() {
        this.clear();
        const prepare = { object: 0, ...this.transformUserModel() };
        keys(prepare)
            .map((key, index) => {
            return {
                type: this.modeller.getConnector(),
                id: key,
                value: prepare[key],
                connectorType: index ? 'input' : 'output'
            };
        }).forEach((com, index) => {
            const component = this.containerRef.createComponent(com.type, {
                injector: this.containerRef.injector,
            });
            component.instance.connector.subscribe((connector) => {
                this.connector.emit(connector);
            });
            if (index === 0) {
                component.instance.changed.subscribe((value) => {
                    if (typeof value === 'string' || typeof value === 'number'
                        || JSON.stringify(this.userModel) === JSON.stringify(value)) {
                        return;
                    }
                    this.userModel = value;
                    this.reload();
                    setTimeout(() => this.setConnectors(this.connectors || []));
                });
            }
            component.instance.changed.subscribe(() => {
                if (this.model?.type === 'output') {
                    const values = {};
                    this.components.forEach(component => values[component.instance.id] = component.instance.value);
                    this.outputChanged.emit(values);
                }
            });
            component.setInput('parent', this);
            component.setInput('id', com.id);
            component.setInput('subId', this.subId);
            component.setInput('inputOutputComponent', com?.inputOutputComponent);
            component.setInput('type', com.connectorType || this.model?.type || 'in-out');
            component.setInput('removable', com.removable);
            component.setInput('options', this.options);
            if (index) {
                component.setInput('value', com.value);
            }
            if (com.removable) {
                component.instance.remove.subscribe((id) => {
                    if (this.userModel && !Array.isArray(this.userModel)) {
                        delete this.userModel[id];
                    }
                    ;
                    this.removeConnector.emit(`${this.id}:${this.subId}:${id}`);
                    this.reload();
                    this.restoreConnectors();
                    this.options = { ...this.options, userModel: this.userModel };
                    this.optionsChanged.emit();
                });
            }
            if ('input' === this.model?.type) {
                component.setInput('value', com.value);
            }
            // required to start triggering hooks without that is not trigger ngOnChanges/ngOnInit/ngAfterViewInit
            component.changeDetectorRef.detectChanges();
            this.components.push(component);
        });
    }
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: SplitBoxComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
    static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.4", type: SplitBoxComponent, isStandalone: false, selector: "obl-split-box", usesInheritance: true, ngImport: i0, template: "<div\n  class=\"header\"\n  (mousedown)=\"dragBox.emit({ mouse: $event, component: this })\"\n>\n  {{ model?.translations?.[model?.title || ''] || model?.title }}\n  @if (model?.type === 'in-out') {\n    <button oblButton [icon]=\"'cancel'\" (click)=\"remove.emit(this)\"></button>\n  }\n</div>\n\n<div>\n  <ng-container #containerRef></ng-container>\n</div>\n\n@if (model?.type === 'output' || dynamic) {\n  <div class=\"output\">\n    @if (type === 'input') {\n    <obl-input-wrapper [label]=\"modeller.getTranslation('Add new field')\">\n      <input oblInput #newName type=\"text\"/>\n      <button oblButton [icon]=\"'add'\" (click)=\"add(newName.value); newName.value = ''\" required suffix></button>\n    </obl-input-wrapper>\n  } @else {\n    <button oblButton [icon]=\"'add'\" (click)=\"add()\">{{ modeller.getTranslation('Add new input') }}</button>\n  }\n  </div>\n}\n", styles: [":host{position:absolute;display:block;width:250px;height:auto;border:1px var(--default-border-color) solid;border-radius:10px;background-color:var(--default-background-color)}.header{padding:5px;text-align:center;border-bottom:1px var(--default-border-color) solid;cursor:move;position:relative}.header button{position:absolute;right:2px;top:2px;border-radius:50%;--obl-icon-width: 10px;--obl-default-button-padding: 5px}.output{padding:5px}.output button{margin-left:auto;border-radius:5px;--obl-icon-width: 25px;--obl-default-button-padding: 5px 15px 5px 5px}.output obl-input-wrapper button{border-radius:50%;--obl-icon-width: 10px;--obl-default-button-padding: 5px}\n"], dependencies: [{ kind: "directive", type: i1.InputDirective, selector: "input[oblInput]", inputs: ["outlined"], exportAs: ["oblInput"] }, { kind: "component", type: i1.InputWrapperComponent, selector: "obl-input-wrapper", inputs: ["label", "display", "cancellable", "step", "errors", "translations", "labelAnimation", "small"], outputs: ["loaded"] }, { kind: "directive", type: i2.ButtonDirective, selector: "oblButton, [oblButton]", inputs: ["oblButton", "icon", "blockWhenLoading", "loading", "toggle", "selected", "link", "target"], exportAs: ["oblButton"] }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: SplitBoxComponent, decorators: [{
            type: Component,
            args: [{ selector: 'obl-split-box', standalone: false, template: "<div\n  class=\"header\"\n  (mousedown)=\"dragBox.emit({ mouse: $event, component: this })\"\n>\n  {{ model?.translations?.[model?.title || ''] || model?.title }}\n  @if (model?.type === 'in-out') {\n    <button oblButton [icon]=\"'cancel'\" (click)=\"remove.emit(this)\"></button>\n  }\n</div>\n\n<div>\n  <ng-container #containerRef></ng-container>\n</div>\n\n@if (model?.type === 'output' || dynamic) {\n  <div class=\"output\">\n    @if (type === 'input') {\n    <obl-input-wrapper [label]=\"modeller.getTranslation('Add new field')\">\n      <input oblInput #newName type=\"text\"/>\n      <button oblButton [icon]=\"'add'\" (click)=\"add(newName.value); newName.value = ''\" required suffix></button>\n    </obl-input-wrapper>\n  } @else {\n    <button oblButton [icon]=\"'add'\" (click)=\"add()\">{{ modeller.getTranslation('Add new input') }}</button>\n  }\n  </div>\n}\n", styles: [":host{position:absolute;display:block;width:250px;height:auto;border:1px var(--default-border-color) solid;border-radius:10px;background-color:var(--default-background-color)}.header{padding:5px;text-align:center;border-bottom:1px var(--default-border-color) solid;cursor:move;position:relative}.header button{position:absolute;right:2px;top:2px;border-radius:50%;--obl-icon-width: 10px;--obl-default-button-padding: 5px}.output{padding:5px}.output button{margin-left:auto;border-radius:5px;--obl-icon-width: 25px;--obl-default-button-padding: 5px 15px 5px 5px}.output obl-input-wrapper button{border-radius:50%;--obl-icon-width: 10px;--obl-default-button-padding: 5px}\n"] }]
        }] });

class ValueInputComponent {
    id;
    translations;
    toTransform;
    header = 'Value';
    options;
    transformed = new EventEmitterExt();
    optionsChanged = new EventEmitterExt();
    transform() {
        this.transformed.emit(this.toTransform);
    }
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: ValueInputComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
    static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.0.4", type: ValueInputComponent, isStandalone: false, selector: "obl-value-input", inputs: { id: "id", translations: "translations", toTransform: "toTransform", header: "header", options: "options" }, outputs: { transformed: "transformed", optionsChanged: "optionsChanged" }, ngImport: i0, template: "{{ translations?.[header || ''] || header  }} {{ toTransform | json }}\n", styles: [""], dependencies: [{ kind: "pipe", type: i2$1.JsonPipe, name: "json" }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: ValueInputComponent, decorators: [{
            type: Component,
            args: [{ selector: 'obl-value-input', standalone: false, template: "{{ translations?.[header || ''] || header  }} {{ toTransform | json }}\n" }]
        }], propDecorators: { id: [{
                type: Input
            }], translations: [{
                type: Input
            }], toTransform: [{
                type: Input
            }], header: [{
                type: Input
            }], options: [{
                type: Input
            }], transformed: [{
                type: Output
            }], optionsChanged: [{
                type: Output
            }] } });

class MathBoxComponent extends ModellerBoxComponent {
    values;
    setConnectors(connectors) {
        super.setConnectors(connectors);
        this.components?.[2].instance.component.setInput('toTransform', this.values);
    }
    reload() {
        super.reload();
        if (this.components.length === 3) {
            this.components[0].instance.component.setInput('header', 'Left:');
            this.components[1].instance.component.setInput('header', 'Right:');
            this.components.forEach(component => component.setInput('translations', this.model?.translations));
            this.components[0].instance.changed.subscribe((value) => {
                this.values = { ...this.values, left: value };
                this.components[2].instance.component.setInput('toTransform', this.values);
                this.components[2].changeDetectorRef.detectChanges();
            });
            this.components[1].instance.changed.subscribe((value) => {
                this.values = { ...this.values, right: value };
                this.components[2].instance.component.setInput('toTransform', this.values);
                this.components[2].changeDetectorRef.detectChanges();
            });
        }
    }
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: MathBoxComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
    static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.4", type: MathBoxComponent, isStandalone: false, selector: "obl-math-box", usesInheritance: true, ngImport: i0, template: "<div\n  class=\"header\"\n  (mousedown)=\"dragBox.emit({ mouse: $event, component: this })\"\n>\n  {{ model?.translations?.[model?.title || ''] || model?.title }}\n  @if (model?.type === 'in-out') {\n    <button oblButton [icon]=\"'cancel'\" (click)=\"remove.emit(this)\"></button>\n  }\n</div>\n\n<div>\n  <ng-container #containerRef></ng-container>\n</div>\n\n@if (model?.type === 'output' || dynamic) {\n  <div class=\"output\">\n    @if (type === 'input') {\n    <obl-input-wrapper [label]=\"modeller.getTranslation('Add new field')\">\n      <input oblInput #newName type=\"text\"/>\n      <button oblButton [icon]=\"'add'\" (click)=\"add(newName.value); newName.value = ''\" required suffix></button>\n    </obl-input-wrapper>\n  } @else {\n    <button oblButton [icon]=\"'add'\" (click)=\"add()\">{{ modeller.getTranslation('Add new input') }}</button>\n  }\n  </div>\n}\n", styles: [":host{position:absolute;display:block;width:250px;height:auto;border:1px var(--default-border-color) solid;border-radius:10px;background-color:var(--default-background-color)}.header{padding:5px;text-align:center;border-bottom:1px var(--default-border-color) solid;cursor:move;position:relative}.header button{position:absolute;right:2px;top:2px;border-radius:50%;--obl-icon-width: 10px;--obl-default-button-padding: 5px}.output{padding:5px}.output button{margin-left:auto;border-radius:5px;--obl-icon-width: 25px;--obl-default-button-padding: 5px 15px 5px 5px}.output obl-input-wrapper button{border-radius:50%;--obl-icon-width: 10px;--obl-default-button-padding: 5px}\n"], dependencies: [{ kind: "directive", type: i1.InputDirective, selector: "input[oblInput]", inputs: ["outlined"], exportAs: ["oblInput"] }, { kind: "component", type: i1.InputWrapperComponent, selector: "obl-input-wrapper", inputs: ["label", "display", "cancellable", "step", "errors", "translations", "labelAnimation", "small"], outputs: ["loaded"] }, { kind: "directive", type: i2.ButtonDirective, selector: "oblButton, [oblButton]", inputs: ["oblButton", "icon", "blockWhenLoading", "loading", "toggle", "selected", "link", "target"], exportAs: ["oblButton"] }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: MathBoxComponent, decorators: [{
            type: Component,
            args: [{ selector: 'obl-math-box', standalone: false, template: "<div\n  class=\"header\"\n  (mousedown)=\"dragBox.emit({ mouse: $event, component: this })\"\n>\n  {{ model?.translations?.[model?.title || ''] || model?.title }}\n  @if (model?.type === 'in-out') {\n    <button oblButton [icon]=\"'cancel'\" (click)=\"remove.emit(this)\"></button>\n  }\n</div>\n\n<div>\n  <ng-container #containerRef></ng-container>\n</div>\n\n@if (model?.type === 'output' || dynamic) {\n  <div class=\"output\">\n    @if (type === 'input') {\n    <obl-input-wrapper [label]=\"modeller.getTranslation('Add new field')\">\n      <input oblInput #newName type=\"text\"/>\n      <button oblButton [icon]=\"'add'\" (click)=\"add(newName.value); newName.value = ''\" required suffix></button>\n    </obl-input-wrapper>\n  } @else {\n    <button oblButton [icon]=\"'add'\" (click)=\"add()\">{{ modeller.getTranslation('Add new input') }}</button>\n  }\n  </div>\n}\n", styles: [":host{position:absolute;display:block;width:250px;height:auto;border:1px var(--default-border-color) solid;border-radius:10px;background-color:var(--default-background-color)}.header{padding:5px;text-align:center;border-bottom:1px var(--default-border-color) solid;cursor:move;position:relative}.header button{position:absolute;right:2px;top:2px;border-radius:50%;--obl-icon-width: 10px;--obl-default-button-padding: 5px}.output{padding:5px}.output button{margin-left:auto;border-radius:5px;--obl-icon-width: 25px;--obl-default-button-padding: 5px 15px 5px 5px}.output obl-input-wrapper button{border-radius:50%;--obl-icon-width: 10px;--obl-default-button-padding: 5px}\n"] }]
        }] });

class MathOperatorComponent {
    toTransform;
    /** */
    options;
    /** */
    translations;
    transformed = new EventEmitterExt();
    optionsChanged = new EventEmitterExt();
    items = [
        {
            id: 'add',
            text: 'Add',
        },
        {
            id: 'subtract',
            text: 'Subtract',
        },
        {
            id: 'multiply',
            text: 'Multiply'
        },
        {
            id: 'divide',
            text: 'Divide'
        },
        {
            id: 'power',
            text: 'Power'
        },
        {
            id: 'modulo',
            text: 'Modulo',
        }
    ];
    selected = this.items[0].id;
    value;
    lastError;
    transform() {
        const { left, right } = this.toTransform || {};
        const operation = (left, right, cb) => {
            const leftNumeric = typeof left === 'number';
            const rightNumeric = typeof right === 'number';
            if (leftNumeric && rightNumeric) {
                return cb(left, right);
            }
            else if (!leftNumeric && !rightNumeric) {
                const result = [];
                left.forEach((n, index) => {
                    result.push(cb(n, right[index]));
                });
                return result;
            }
            else if (rightNumeric) {
                const result = [];
                left.forEach(n => {
                    result.push(cb(n, right));
                });
                return result;
            }
            else {
                const result = [];
                right.forEach(n => {
                    result.push(cb(left, n));
                });
                return result;
            }
        };
        const typed = (value) => typeof value === 'number' || Array.isArray(value);
        if (left !== undefined && right !== undefined && typed(left) && typed(right)) {
            switch (this.selected) {
                case 'add':
                    {
                        this.value = operation(left, right, (left, right) => left + right);
                    }
                    break;
                case 'subtract':
                    {
                        this.value = operation(left, right, (left, right) => left - right);
                    }
                    break;
                case 'multiply':
                    {
                        this.value = operation(left, right, (left, right) => left * right);
                    }
                    break;
                case 'divide':
                    {
                        this.value = operation(left, right, (left, right) => left / right);
                    }
                    break;
                case 'power':
                    {
                        this.value = operation(left, right, (left, right) => Math.pow(left, right));
                    }
                    break;
                case 'modulo': {
                    this.value = operation(left, right, (left, right) => left % right);
                }
            }
            this.transformed.emit(this.value);
        }
        else {
            this.value = undefined;
            this.transformed.emit(this.value);
            this.lastError = new Error('Value is undefined or is not a number');
        }
    }
    ngOnInit() {
        this.items.forEach((item, index) => {
            this.items[index].text = this.translations?.[item.text] || item.text;
        });
    }
    ngOnChanges(changes) {
        if (changes.toTransform) {
            this.transform();
        }
        if (changes.options) {
            this.selected = this.options?.selected || this.selected;
            this.transform();
        }
    }
    changed(item) {
        this.selected = item.id;
        this.options = { ...this.options, selected: this.selected };
        this.transform();
        this.optionsChanged.emit();
    }
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: MathOperatorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
    static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.0.4", type: MathOperatorComponent, isStandalone: false, selector: "obl-math-operator", inputs: { toTransform: "toTransform", options: "options", translations: "translations" }, outputs: { transformed: "transformed", optionsChanged: "optionsChanged" }, usesOnChanges: true, ngImport: i0, template: "<obl-dropdown-select\n  [items]=\"items\"\n  [select]=\"selected\"\n  (changed)=\"changed($event)\"\n  [label]=\"translations?.['Operator type'] || 'Operator type'\"\n></obl-dropdown-select>\n", styles: [""], dependencies: [{ kind: "component", type: i2$2.DropdownSelectComponent, selector: "obl-dropdown-select", inputs: ["model", "items", "label", "labelAnimation", "templateSuffix", "templatePrefix", "search", "regExp", "select", "disabled"], outputs: ["changed"] }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: MathOperatorComponent, decorators: [{
            type: Component,
            args: [{ selector: 'obl-math-operator', standalone: false, template: "<obl-dropdown-select\n  [items]=\"items\"\n  [select]=\"selected\"\n  (changed)=\"changed($event)\"\n  [label]=\"translations?.['Operator type'] || 'Operator type'\"\n></obl-dropdown-select>\n" }]
        }], propDecorators: { toTransform: [{
                type: Input
            }], options: [{
                type: Input
            }], translations: [{
                type: Input
            }], transformed: [{
                type: Output
            }], optionsChanged: [{
                type: Output
            }] } });

class ConstOrValueComponent {
    toTransform = Math.PI;
    /** */
    options;
    /** */
    translations;
    transformed = new EventEmitterExt();
    optionsChanged = new EventEmitterExt();
    items = [
        {
            id: 'pi',
            text: 'Pi π',
        },
        {
            id: 'e',
            text: 'e',
        },
        {
            id: 'gold',
            text: 'Gold'
        },
        {
            id: 'earth-gravity',
            text: 'Earth gravity'
        },
        {
            id: 'gravity-const',
            text: 'Gravity const'
        },
        {
            id: 'light-speed',
            text: 'Light speed',
        },
        {
            id: 'variable',
            text: 'Numeric variable'
        },
        {
            id: 'planck-constant',
            text: 'Planck constant'
        },
        {
            id: 'apery-const',
            text: 'Apéry const'
        },
        {
            id: 'newman-const',
            text: 'Newman const'
        },
        {
            id: 'string',
            text: 'Text value'
        },
        {
            id: 'json-value',
            text: 'JSON variable'
        }
    ];
    selected = this.items[0].id;
    value;
    lastError;
    values = {
        pi: Math.PI,
        e: Math.E,
        gold: (Math.sqrt(5) - 1) / 2,
        'earth-gravity': 9.8065,
        'gravity-const': 6.67259e-11,
        'light-speed': 299792458,
        'planck-constant': 6.62807015e-24,
        'apery-const': 1.2020569031595942853997381,
        'newman-const': 2.7e-9,
        variable: 0,
        string: '',
        'json-value': '{}'
    };
    transform() {
        try {
            this.value = this.selected === 'json-value' ? JSON.parse(this.values?.[this.selected] || '{}') : this.values[this.selected];
            this.transformed.emit(this.value);
        }
        catch (e) {
            this.transformed.emit(undefined);
        }
    }
    ngOnInit() {
        this.items.forEach((item, index) => {
            this.items[index].text = this.translations?.[item.text] || item.text;
        });
    }
    ngOnChanges(changes) {
        if (changes.options) {
            this.selected = this.options?.selected || this.selected;
            this.values['variable'] = this.options?.value || 0;
            this.values['string'] = this.options?.string || '';
            this.values['json-value'] = this.options?.['json-value'] || '{}';
            this.transform();
        }
    }
    changed(item) {
        this.selected = item.id;
        this.options = { ...this.options, selected: item.id };
        this.transform();
        this.optionsChanged.emit();
    }
    variableChanged(variable) {
        this.values['variable'] = variable.target.valueAsNumber;
        this.options = { ...this.options, value: this.values['variable'] };
        this.transform();
        this.optionsChanged.emit();
    }
    stringChanged(variable) {
        this.values['string'] = variable.target.value;
        this.options = { ...this.options, string: this.values['string'] };
        this.transform();
        this.optionsChanged.emit();
    }
    jsonChanged(variable) {
        this.values['json-value'] = variable.target.value;
        this.options = { ...this.options, 'json-value': this.values['json-value'] };
        this.transform();
        this.optionsChanged.emit();
    }
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: ConstOrValueComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
    static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.4", type: ConstOrValueComponent, isStandalone: false, selector: "obl-const-or-value", inputs: { toTransform: "toTransform", options: "options", translations: "translations" }, outputs: { transformed: "transformed", optionsChanged: "optionsChanged" }, usesOnChanges: true, ngImport: i0, template: "<obl-dropdown-select\n  [items]=\"items\"\n  [select]=\"selected\"\n  (changed)=\"changed($event)\"\n  [label]=\"translations?.['Constant / variable:'] || 'Constant / variable:'\"\n></obl-dropdown-select>\n\n@if (selected === 'variable') {\n  <obl-input-wrapper\n    [label]=\"translations?.['Value:'] || 'Value:'\"\n    [step]=\"1\"\n  >\n    <input\n      type=\"number\"\n      [value]=\"values['variable']\"\n      (change)=\"variableChanged($event)\"\n      (keyup)=\"variableChanged($event)\"\n      oblInput\n    />\n  </obl-input-wrapper>\n}\n\n@if (selected === 'string') {\n  <obl-input-wrapper\n    [label]=\"translations?.['Text value:'] || 'Text value:'\"\n    [step]=\"1\"\n  >\n    <input\n      [value]=\"values['string']\"\n      (change)=\"stringChanged($event)\"\n      (keyup)=\"stringChanged($event)\"\n      oblInput\n    />\n  </obl-input-wrapper>\n}\n\n@if (selected === 'json-value') {\n  <obl-textarea-wrapper\n    [label]=\"translations?.['JSON value:'] || 'JSON value:'\"\n  >\n    <textarea\n      [value]=\"values['json-value']\"\n      (change)=\"jsonChanged($event)\"\n      (keyup)=\"jsonChanged($event)\"\n      oblTextArea\n    ></textarea>\n  </obl-textarea-wrapper>\n}\n", styles: [""], dependencies: [{ kind: "directive", type: i1.InputDirective, selector: "input[oblInput]", inputs: ["outlined"], exportAs: ["oblInput"] }, { kind: "directive", type: i1.TextAreaDirective, selector: "textarea[oblTextArea]", inputs: ["outlined", "noResize"], exportAs: ["oblTextArea"] }, { kind: "component", type: i1.InputWrapperComponent, selector: "obl-input-wrapper", inputs: ["label", "display", "cancellable", "step", "errors", "translations", "labelAnimation", "small"], outputs: ["loaded"] }, { kind: "component", type: i1.TextAreaWrapperComponent, selector: "obl-textarea-wrapper", inputs: ["label", "display", "labelAnimation"] }, { kind: "component", type: i2$2.DropdownSelectComponent, selector: "obl-dropdown-select", inputs: ["model", "items", "label", "labelAnimation", "templateSuffix", "templatePrefix", "search", "regExp", "select", "disabled"], outputs: ["changed"] }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: ConstOrValueComponent, decorators: [{
            type: Component,
            args: [{ selector: 'obl-const-or-value', standalone: false, template: "<obl-dropdown-select\n  [items]=\"items\"\n  [select]=\"selected\"\n  (changed)=\"changed($event)\"\n  [label]=\"translations?.['Constant / variable:'] || 'Constant / variable:'\"\n></obl-dropdown-select>\n\n@if (selected === 'variable') {\n  <obl-input-wrapper\n    [label]=\"translations?.['Value:'] || 'Value:'\"\n    [step]=\"1\"\n  >\n    <input\n      type=\"number\"\n      [value]=\"values['variable']\"\n      (change)=\"variableChanged($event)\"\n      (keyup)=\"variableChanged($event)\"\n      oblInput\n    />\n  </obl-input-wrapper>\n}\n\n@if (selected === 'string') {\n  <obl-input-wrapper\n    [label]=\"translations?.['Text value:'] || 'Text value:'\"\n    [step]=\"1\"\n  >\n    <input\n      [value]=\"values['string']\"\n      (change)=\"stringChanged($event)\"\n      (keyup)=\"stringChanged($event)\"\n      oblInput\n    />\n  </obl-input-wrapper>\n}\n\n@if (selected === 'json-value') {\n  <obl-textarea-wrapper\n    [label]=\"translations?.['JSON value:'] || 'JSON value:'\"\n  >\n    <textarea\n      [value]=\"values['json-value']\"\n      (change)=\"jsonChanged($event)\"\n      (keyup)=\"jsonChanged($event)\"\n      oblTextArea\n    ></textarea>\n  </obl-textarea-wrapper>\n}\n" }]
        }], propDecorators: { toTransform: [{
                type: Input
            }], options: [{
                type: Input
            }], translations: [{
                type: Input
            }], transformed: [{
                type: Output
            }], optionsChanged: [{
                type: Output
            }] } });

class JoinArrayToObjectBoxComponent extends ModellerBoxComponent {
    dynamic = true;
    reload() {
        this.clear();
        this.userModel = { ...this.options?.userModel, ...this.userModel };
        let userModel = this.transformUserModel();
        keys({ ...(this.model?.components || {}), ...userModel })
            .map((key, index) => {
            return {
                type: this.modeller.getConnector(),
                id: !index ? this.model?.components[0].id : key,
                value: this.model?.type === 'input' ? this.inputModel?.[key] : '',
                removable: !!(userModel || {})?.[key]
            };
        }).forEach((com, index) => {
            const component = this.containerRef.createComponent(com.type, {
                injector: this.containerRef.injector,
            });
            component.instance.connector.subscribe((connector) => {
                this.connector.emit(connector);
            });
            component.instance.optionsChanged.subscribe(() => this.optionsChanged.emit());
            component.setInput('parent', this);
            component.setInput('id', com.id);
            component.setInput('subId', this.subId);
            component.setInput('inputOutputComponent', com?.inputOutputComponent);
            component.setInput('type', index && 'output' || 'input');
            component.setInput('removable', com.removable);
            component.setInput('options', this.options);
            component.setInput('translations', this.model?.translations);
            this.setRemove(component, com);
            if (com.removable) {
                component.instance.optionsChanged.subscribe(() => {
                    this.optionsChanged.emit();
                });
                component.instance.changed.subscribe(() => {
                    const collect = {};
                    let length = 0;
                    this.components.forEach((com, index) => {
                        if (index) {
                            collect[com.instance.id] = com.instance.value;
                            length = Math.max(com.instance.value?.length, length);
                        }
                    });
                    const objects = [];
                    for (let i = 0; i < length; i++) {
                        const obj = {};
                        keys(collect).forEach(key => {
                            obj[key] = collect[key][i];
                        });
                        objects.push(obj);
                    }
                    this.components[0].setInput('value', objects);
                });
            }
            if ('input' === this.model?.type) {
                component.setInput('value', com.value);
            }
            // required to start triggering hooks without that is not trigger ngOnChanges/ngOnInit/ngAfterViewInit
            component.changeDetectorRef.detectChanges();
            this.components.push(component);
        });
    }
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: JoinArrayToObjectBoxComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
    static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.4", type: JoinArrayToObjectBoxComponent, isStandalone: false, selector: "obl-join-array-to-object-box", usesInheritance: true, ngImport: i0, template: "<div\n  class=\"header\"\n  (mousedown)=\"dragBox.emit({ mouse: $event, component: this })\"\n>\n  {{ model?.translations?.[model?.title || ''] || model?.title }}\n  @if (model?.type === 'in-out') {\n    <button oblButton [icon]=\"'cancel'\" (click)=\"remove.emit(this)\"></button>\n  }\n</div>\n\n<div>\n  <ng-container #containerRef></ng-container>\n</div>\n\n@if (model?.type === 'output' || dynamic) {\n  <div class=\"output\">\n    @if (type === 'input') {\n    <obl-input-wrapper [label]=\"modeller.getTranslation('Add new field')\">\n      <input oblInput #newName type=\"text\"/>\n      <button oblButton [icon]=\"'add'\" (click)=\"add(newName.value); newName.value = ''\" required suffix></button>\n    </obl-input-wrapper>\n  } @else {\n    <button oblButton [icon]=\"'add'\" (click)=\"add()\">{{ modeller.getTranslation('Add new input') }}</button>\n  }\n  </div>\n}\n", styles: [":host{position:absolute;display:block;width:250px;height:auto;border:1px var(--default-border-color) solid;border-radius:10px;background-color:var(--default-background-color)}.header{padding:5px;text-align:center;border-bottom:1px var(--default-border-color) solid;cursor:move;position:relative}.header button{position:absolute;right:2px;top:2px;border-radius:50%;--obl-icon-width: 10px;--obl-default-button-padding: 5px}.output{padding:5px}.output button{margin-left:auto;border-radius:5px;--obl-icon-width: 25px;--obl-default-button-padding: 5px 15px 5px 5px}.output obl-input-wrapper button{border-radius:50%;--obl-icon-width: 10px;--obl-default-button-padding: 5px}\n"], dependencies: [{ kind: "directive", type: i1.InputDirective, selector: "input[oblInput]", inputs: ["outlined"], exportAs: ["oblInput"] }, { kind: "component", type: i1.InputWrapperComponent, selector: "obl-input-wrapper", inputs: ["label", "display", "cancellable", "step", "errors", "translations", "labelAnimation", "small"], outputs: ["loaded"] }, { kind: "directive", type: i2.ButtonDirective, selector: "oblButton, [oblButton]", inputs: ["oblButton", "icon", "blockWhenLoading", "loading", "toggle", "selected", "link", "target"], exportAs: ["oblButton"] }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: JoinArrayToObjectBoxComponent, decorators: [{
            type: Component,
            args: [{ selector: 'obl-join-array-to-object-box', standalone: false, template: "<div\n  class=\"header\"\n  (mousedown)=\"dragBox.emit({ mouse: $event, component: this })\"\n>\n  {{ model?.translations?.[model?.title || ''] || model?.title }}\n  @if (model?.type === 'in-out') {\n    <button oblButton [icon]=\"'cancel'\" (click)=\"remove.emit(this)\"></button>\n  }\n</div>\n\n<div>\n  <ng-container #containerRef></ng-container>\n</div>\n\n@if (model?.type === 'output' || dynamic) {\n  <div class=\"output\">\n    @if (type === 'input') {\n    <obl-input-wrapper [label]=\"modeller.getTranslation('Add new field')\">\n      <input oblInput #newName type=\"text\"/>\n      <button oblButton [icon]=\"'add'\" (click)=\"add(newName.value); newName.value = ''\" required suffix></button>\n    </obl-input-wrapper>\n  } @else {\n    <button oblButton [icon]=\"'add'\" (click)=\"add()\">{{ modeller.getTranslation('Add new input') }}</button>\n  }\n  </div>\n}\n", styles: [":host{position:absolute;display:block;width:250px;height:auto;border:1px var(--default-border-color) solid;border-radius:10px;background-color:var(--default-background-color)}.header{padding:5px;text-align:center;border-bottom:1px var(--default-border-color) solid;cursor:move;position:relative}.header button{position:absolute;right:2px;top:2px;border-radius:50%;--obl-icon-width: 10px;--obl-default-button-padding: 5px}.output{padding:5px}.output button{margin-left:auto;border-radius:5px;--obl-icon-width: 25px;--obl-default-button-padding: 5px 15px 5px 5px}.output obl-input-wrapper button{border-radius:50%;--obl-icon-width: 10px;--obl-default-button-padding: 5px}\n"] }]
        }] });

class SplitInputBoxComponent extends ModellerBoxComponent {
    dynamic = true;
    reload() {
        this.clear();
        this.userModel = { ...this.options?.userModel, ...this.userModel };
        let userModel = this.transformUserModel();
        keys({ ...(this.model?.components || {}), ...userModel })
            .map((key, index) => {
            return {
                type: this.modeller.getConnector(),
                id: !index ? this.model?.components[0].id : key,
                value: this.model?.type === 'input' ? this.inputModel?.[key] : '',
                removable: !!(userModel || {})?.[key]
            };
        }).forEach((com, index) => {
            const component = this.containerRef.createComponent(com.type, {
                injector: this.containerRef.injector,
            });
            component.instance.connector.subscribe((connector) => {
                this.connector.emit(connector);
            });
            component.instance.optionsChanged.subscribe(() => this.optionsChanged.emit());
            component.setInput('parent', this);
            component.setInput('id', com.id);
            component.setInput('subId', this.subId);
            component.setInput('inputOutputComponent', com?.inputOutputComponent);
            component.setInput('type', index && 'input' || 'output');
            component.setInput('removable', com.removable);
            component.setInput('options', this.options);
            component.setInput('translations', this.model?.translations);
            this.setRemove(component, com);
            if (com.removable) {
                component.instance.optionsChanged.subscribe(() => {
                    this.optionsChanged.emit();
                });
            }
            else {
                component.instance.changed.subscribe((value) => {
                    this.components.forEach((com, index) => {
                        if (index) {
                            com.setInput('value', value);
                        }
                    });
                });
            }
            if ('input' === this.model?.type) {
                component.setInput('value', com.value);
            }
            // required to start triggering hooks without that is not trigger ngOnChanges/ngOnInit/ngAfterViewInit
            component.changeDetectorRef.detectChanges();
            this.components.push(component);
        });
    }
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: SplitInputBoxComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
    static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.4", type: SplitInputBoxComponent, isStandalone: false, selector: "obl-split-input-box", usesInheritance: true, ngImport: i0, template: "<div\n  class=\"header\"\n  (mousedown)=\"dragBox.emit({ mouse: $event, component: this })\"\n>\n  {{ model?.translations?.[model?.title || ''] || model?.title }}\n  @if (model?.type === 'in-out') {\n    <button oblButton [icon]=\"'cancel'\" (click)=\"remove.emit(this)\"></button>\n  }\n</div>\n\n<div>\n  <ng-container #containerRef></ng-container>\n</div>\n\n@if (model?.type === 'output' || dynamic) {\n  <div class=\"output\">\n    @if (type === 'input') {\n    <obl-input-wrapper [label]=\"modeller.getTranslation('Add new field')\">\n      <input oblInput #newName type=\"text\"/>\n      <button oblButton [icon]=\"'add'\" (click)=\"add(newName.value); newName.value = ''\" required suffix></button>\n    </obl-input-wrapper>\n  } @else {\n    <button oblButton [icon]=\"'add'\" (click)=\"add()\">{{ modeller.getTranslation('Add new input') }}</button>\n  }\n  </div>\n}\n", styles: [":host{position:absolute;display:block;width:250px;height:auto;border:1px var(--default-border-color) solid;border-radius:10px;background-color:var(--default-background-color)}.header{padding:5px;text-align:center;border-bottom:1px var(--default-border-color) solid;cursor:move;position:relative}.header button{position:absolute;right:2px;top:2px;border-radius:50%;--obl-icon-width: 10px;--obl-default-button-padding: 5px}.output{padding:5px}.output button{margin-left:auto;border-radius:5px;--obl-icon-width: 25px;--obl-default-button-padding: 5px 15px 5px 5px}.output obl-input-wrapper button{border-radius:50%;--obl-icon-width: 10px;--obl-default-button-padding: 5px}\n"], dependencies: [{ kind: "directive", type: i1.InputDirective, selector: "input[oblInput]", inputs: ["outlined"], exportAs: ["oblInput"] }, { kind: "component", type: i1.InputWrapperComponent, selector: "obl-input-wrapper", inputs: ["label", "display", "cancellable", "step", "errors", "translations", "labelAnimation", "small"], outputs: ["loaded"] }, { kind: "directive", type: i2.ButtonDirective, selector: "oblButton, [oblButton]", inputs: ["oblButton", "icon", "blockWhenLoading", "loading", "toggle", "selected", "link", "target"], exportAs: ["oblButton"] }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: SplitInputBoxComponent, decorators: [{
            type: Component,
            args: [{ selector: 'obl-split-input-box', standalone: false, template: "<div\n  class=\"header\"\n  (mousedown)=\"dragBox.emit({ mouse: $event, component: this })\"\n>\n  {{ model?.translations?.[model?.title || ''] || model?.title }}\n  @if (model?.type === 'in-out') {\n    <button oblButton [icon]=\"'cancel'\" (click)=\"remove.emit(this)\"></button>\n  }\n</div>\n\n<div>\n  <ng-container #containerRef></ng-container>\n</div>\n\n@if (model?.type === 'output' || dynamic) {\n  <div class=\"output\">\n    @if (type === 'input') {\n    <obl-input-wrapper [label]=\"modeller.getTranslation('Add new field')\">\n      <input oblInput #newName type=\"text\"/>\n      <button oblButton [icon]=\"'add'\" (click)=\"add(newName.value); newName.value = ''\" required suffix></button>\n    </obl-input-wrapper>\n  } @else {\n    <button oblButton [icon]=\"'add'\" (click)=\"add()\">{{ modeller.getTranslation('Add new input') }}</button>\n  }\n  </div>\n}\n", styles: [":host{position:absolute;display:block;width:250px;height:auto;border:1px var(--default-border-color) solid;border-radius:10px;background-color:var(--default-background-color)}.header{padding:5px;text-align:center;border-bottom:1px var(--default-border-color) solid;cursor:move;position:relative}.header button{position:absolute;right:2px;top:2px;border-radius:50%;--obl-icon-width: 10px;--obl-default-button-padding: 5px}.output{padding:5px}.output button{margin-left:auto;border-radius:5px;--obl-icon-width: 25px;--obl-default-button-padding: 5px 15px 5px 5px}.output obl-input-wrapper button{border-radius:50%;--obl-icon-width: 10px;--obl-default-button-padding: 5px}\n"] }]
        }] });

class GenerateComponent {
    toTransform;
    /** */
    options;
    /** */
    translations;
    transformed = new EventEmitterExt();
    optionsChanged = new EventEmitterExt();
    items = [
        {
            id: 'start-step-count',
            text: 'Start, step and count',
        },
        {
            id: 'start-end-count',
            text: 'Start, end and count',
        },
    ];
    selected = this.items[0].id;
    value;
    start = 0;
    end = 1;
    step = 1;
    count = 2;
    constructor() { }
    ngOnInit() {
        this.items.forEach((item, index) => {
            this.items[index].text = this.translations?.[item.text] || item.text;
        });
    }
    ngOnChanges(changes) {
        if (changes.toTransform) {
            this.transform();
        }
        if (changes.options) {
            this.selected = this?.options?.selected ?? this.selected;
            const convert = (v, def) => v !== undefined && +v || def;
            this.start = convert(this?.options?.start, this.start);
            this.end = convert(this?.options?.end, this.end);
            this.step = convert(this?.options?.step, this.step);
            this.count = convert(this?.options?.count, this.count);
            this.transform();
        }
    }
    changed(item) {
        this.selected = item.id;
        this.options = { ...this.options, selected: this.selected };
        setTimeout(() => this.optionsChanged.emit());
        this.transform();
    }
    transform() {
        const generate = (step) => {
            this.value = [];
            for (let i = 0; i < this.count; i++) {
                this.value.push(i * step + this.start);
            }
        };
        switch (this.selected) {
            case 'start-step-count':
                {
                    generate(this.step);
                }
                break;
            case 'start-end-count':
                {
                    const step = (this.end - this.start) / this.count;
                    if (step) {
                        generate(step);
                    }
                }
                break;
        }
        this.transformed.emit(this.value);
    }
    ngOnDestroy() {
        this.transformed.unsubscribe();
    }
    set(field, ev) {
        this[field] = ev.target.valueAsNumber;
        this.options = { ...this.options, [field]: +ev.target.valueAsNumber };
        setTimeout(() => this.optionsChanged.emit());
        this.transform();
    }
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: GenerateComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
    static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.4", type: GenerateComponent, isStandalone: false, selector: "obl-generate", inputs: { toTransform: "toTransform", options: "options", translations: "translations" }, outputs: { transformed: "transformed", optionsChanged: "optionsChanged" }, usesOnChanges: true, ngImport: i0, template: "<obl-dropdown-select\n  [items]=\"items\"\n  (changed)=\"changed($event)\"\n  [select]=\"selected\"\n  [label]=\"translations?.['Generating type'] || 'Generating type'\"\n></obl-dropdown-select>\n\n@if (selected === 'start-step-count') {\n  <div class=\"output\">\n    <obl-input-wrapper [label]=\"translations?.['Start'] || 'Start'\">\n      <input oblInput type=\"number\" [value]=\"start\" (change)=\"set('start', $event)\"/>\n    </obl-input-wrapper>\n\n    <obl-input-wrapper [label]=\"translations?.['Step'] || 'Step'\">\n      <input oblInput type=\"number\" [value]=\"step\" (change)=\"set('step', $event)\"/>\n    </obl-input-wrapper>\n\n    <obl-input-wrapper [label]=\"translations?.['Rounds'] || 'Rounds'\">\n      <input oblInput type=\"number\" [value]=\"count\" (change)=\"set('count', $event)\"/>\n    </obl-input-wrapper>\n  </div>\n\n  <div class=\"output\">\n    <obl-input-wrapper [label]=\"translations?.['Start'] || 'Start'\">\n      <input oblInput type=\"number\" [value]=\"start\" (change)=\"set('start', $event)\"/>\n    </obl-input-wrapper>\n\n    <obl-input-wrapper [label]=\"translations?.['End'] || 'End'\">\n      <input oblInput type=\"number\" [value]=\"end\" (change)=\"set('end', $event)\"/>\n    </obl-input-wrapper>\n\n    <obl-input-wrapper [label]=\"translations?.['Rounds'] || 'Rounds'\">\n      <input oblInput type=\"number\" [value]=\"count\" (change)=\"set('count', $event)\"/>\n    </obl-input-wrapper>\n  </div>\n}", styles: [""], dependencies: [{ kind: "directive", type: i1.InputDirective, selector: "input[oblInput]", inputs: ["outlined"], exportAs: ["oblInput"] }, { kind: "component", type: i1.InputWrapperComponent, selector: "obl-input-wrapper", inputs: ["label", "display", "cancellable", "step", "errors", "translations", "labelAnimation", "small"], outputs: ["loaded"] }, { kind: "component", type: i2$2.DropdownSelectComponent, selector: "obl-dropdown-select", inputs: ["model", "items", "label", "labelAnimation", "templateSuffix", "templatePrefix", "search", "regExp", "select", "disabled"], outputs: ["changed"] }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: GenerateComponent, decorators: [{
            type: Component,
            args: [{ selector: 'obl-generate', standalone: false, template: "<obl-dropdown-select\n  [items]=\"items\"\n  (changed)=\"changed($event)\"\n  [select]=\"selected\"\n  [label]=\"translations?.['Generating type'] || 'Generating type'\"\n></obl-dropdown-select>\n\n@if (selected === 'start-step-count') {\n  <div class=\"output\">\n    <obl-input-wrapper [label]=\"translations?.['Start'] || 'Start'\">\n      <input oblInput type=\"number\" [value]=\"start\" (change)=\"set('start', $event)\"/>\n    </obl-input-wrapper>\n\n    <obl-input-wrapper [label]=\"translations?.['Step'] || 'Step'\">\n      <input oblInput type=\"number\" [value]=\"step\" (change)=\"set('step', $event)\"/>\n    </obl-input-wrapper>\n\n    <obl-input-wrapper [label]=\"translations?.['Rounds'] || 'Rounds'\">\n      <input oblInput type=\"number\" [value]=\"count\" (change)=\"set('count', $event)\"/>\n    </obl-input-wrapper>\n  </div>\n\n  <div class=\"output\">\n    <obl-input-wrapper [label]=\"translations?.['Start'] || 'Start'\">\n      <input oblInput type=\"number\" [value]=\"start\" (change)=\"set('start', $event)\"/>\n    </obl-input-wrapper>\n\n    <obl-input-wrapper [label]=\"translations?.['End'] || 'End'\">\n      <input oblInput type=\"number\" [value]=\"end\" (change)=\"set('end', $event)\"/>\n    </obl-input-wrapper>\n\n    <obl-input-wrapper [label]=\"translations?.['Rounds'] || 'Rounds'\">\n      <input oblInput type=\"number\" [value]=\"count\" (change)=\"set('count', $event)\"/>\n    </obl-input-wrapper>\n  </div>\n}" }]
        }], ctorParameters: () => [], propDecorators: { toTransform: [{
                type: Input
            }], options: [{
                type: Input
            }], translations: [{
                type: Input
            }], transformed: [{
                type: Output
            }], optionsChanged: [{
                type: Output
            }] } });

class ConcatArrayBoxComponent extends ModellerBoxComponent {
    ref;
    changes;
    modeller;
    constructor(ref, changes, modeller) {
        super(ref, changes, modeller);
        this.ref = ref;
        this.changes = changes;
        this.modeller = modeller;
        this.type = 'button';
        this.dynamic = true;
    }
    reload() {
        this.clear();
        this.userModel = { ...this.options?.userModel, ...this.userModel };
        let userModel = this.transformUserModel();
        keys({ ...(this.model?.components || {}), ...userModel })
            .map((key, index) => {
            return {
                type: this.modeller.getConnector(),
                id: !index ? this.model?.components[0].id : key,
                value: this.model?.type === 'input' ? this.inputModel?.[key] : '',
                removable: !!(userModel || {})?.[key]
            };
        }).forEach((com, index) => {
            const component = this.containerRef.createComponent(com.type, {
                injector: this.containerRef.injector,
            });
            component.instance.connector.subscribe((connector) => {
                this.connector.emit(connector);
            });
            component.instance.optionsChanged.subscribe(() => this.optionsChanged.emit());
            component.setInput('parent', this);
            component.setInput('id', com.id);
            component.setInput('subId', this.subId);
            component.setInput('inputOutputComponent', com?.inputOutputComponent);
            component.setInput('type', index && 'output' || 'input');
            component.setInput('removable', com.removable);
            component.setInput('options', this.options);
            component.setInput('translations', this.model?.translations);
            this.setRemove(component, com);
            if (com.removable) {
                component.instance.optionsChanged.subscribe(() => {
                    this.optionsChanged.emit();
                });
                component.instance.changed.subscribe(() => {
                    let concat = [];
                    this.components.forEach((com, index) => {
                        if (index) {
                            const value = com.instance.value;
                            concat = concat.concat(Array.isArray(value) && value || [value]);
                        }
                    });
                    this.components[0].setInput('value', concat);
                });
            }
            if ('input' === this.model?.type) {
                component.setInput('value', com.value);
            }
            // required to start triggering hooks without that is not trigger ngOnChanges/ngOnInit/ngAfterViewInit
            component.changeDetectorRef.detectChanges();
            this.components.push(component);
        });
    }
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: ConcatArrayBoxComponent, deps: [{ token: i0.ElementRef }, { token: i0.ChangeDetectorRef }, { token: ModellerService }], target: i0.ɵɵFactoryTarget.Component });
    static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.4", type: ConcatArrayBoxComponent, isStandalone: false, selector: "obl-concat-array-box", usesInheritance: true, ngImport: i0, template: "<div\n  class=\"header\"\n  (mousedown)=\"dragBox.emit({ mouse: $event, component: this })\"\n>\n  {{ model?.translations?.[model?.title || ''] || model?.title }}\n  @if (model?.type === 'in-out') {\n    <button oblButton [icon]=\"'cancel'\" (click)=\"remove.emit(this)\"></button>\n  }\n</div>\n\n<div>\n  <ng-container #containerRef></ng-container>\n</div>\n\n@if (model?.type === 'output' || dynamic) {\n  <div class=\"output\">\n    @if (type === 'input') {\n    <obl-input-wrapper [label]=\"modeller.getTranslation('Add new field')\">\n      <input oblInput #newName type=\"text\"/>\n      <button oblButton [icon]=\"'add'\" (click)=\"add(newName.value); newName.value = ''\" required suffix></button>\n    </obl-input-wrapper>\n  } @else {\n    <button oblButton [icon]=\"'add'\" (click)=\"add()\">{{ modeller.getTranslation('Add new input') }}</button>\n  }\n  </div>\n}\n", styles: [":host{position:absolute;display:block;width:250px;height:auto;border:1px var(--default-border-color) solid;border-radius:10px;background-color:var(--default-background-color)}.header{padding:5px;text-align:center;border-bottom:1px var(--default-border-color) solid;cursor:move;position:relative}.header button{position:absolute;right:2px;top:2px;border-radius:50%;--obl-icon-width: 10px;--obl-default-button-padding: 5px}.output{padding:5px}.output button{margin-left:auto;border-radius:5px;--obl-icon-width: 25px;--obl-default-button-padding: 5px 15px 5px 5px}.output obl-input-wrapper button{border-radius:50%;--obl-icon-width: 10px;--obl-default-button-padding: 5px}\n"], dependencies: [{ kind: "directive", type: i1.InputDirective, selector: "input[oblInput]", inputs: ["outlined"], exportAs: ["oblInput"] }, { kind: "component", type: i1.InputWrapperComponent, selector: "obl-input-wrapper", inputs: ["label", "display", "cancellable", "step", "errors", "translations", "labelAnimation", "small"], outputs: ["loaded"] }, { kind: "directive", type: i2.ButtonDirective, selector: "oblButton, [oblButton]", inputs: ["oblButton", "icon", "blockWhenLoading", "loading", "toggle", "selected", "link", "target"], exportAs: ["oblButton"] }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: ConcatArrayBoxComponent, decorators: [{
            type: Component,
            args: [{ selector: 'obl-concat-array-box', standalone: false, template: "<div\n  class=\"header\"\n  (mousedown)=\"dragBox.emit({ mouse: $event, component: this })\"\n>\n  {{ model?.translations?.[model?.title || ''] || model?.title }}\n  @if (model?.type === 'in-out') {\n    <button oblButton [icon]=\"'cancel'\" (click)=\"remove.emit(this)\"></button>\n  }\n</div>\n\n<div>\n  <ng-container #containerRef></ng-container>\n</div>\n\n@if (model?.type === 'output' || dynamic) {\n  <div class=\"output\">\n    @if (type === 'input') {\n    <obl-input-wrapper [label]=\"modeller.getTranslation('Add new field')\">\n      <input oblInput #newName type=\"text\"/>\n      <button oblButton [icon]=\"'add'\" (click)=\"add(newName.value); newName.value = ''\" required suffix></button>\n    </obl-input-wrapper>\n  } @else {\n    <button oblButton [icon]=\"'add'\" (click)=\"add()\">{{ modeller.getTranslation('Add new input') }}</button>\n  }\n  </div>\n}\n", styles: [":host{position:absolute;display:block;width:250px;height:auto;border:1px var(--default-border-color) solid;border-radius:10px;background-color:var(--default-background-color)}.header{padding:5px;text-align:center;border-bottom:1px var(--default-border-color) solid;cursor:move;position:relative}.header button{position:absolute;right:2px;top:2px;border-radius:50%;--obl-icon-width: 10px;--obl-default-button-padding: 5px}.output{padding:5px}.output button{margin-left:auto;border-radius:5px;--obl-icon-width: 25px;--obl-default-button-padding: 5px 15px 5px 5px}.output obl-input-wrapper button{border-radius:50%;--obl-icon-width: 10px;--obl-default-button-padding: 5px}\n"] }]
        }], ctorParameters: () => [{ type: i0.ElementRef }, { type: i0.ChangeDetectorRef }, { type: ModellerService }] });

class FormulaBoxComponent extends ModellerBoxComponent {
    dynamic = true;
    reload() {
        this.clear();
        this.userModel = { ...this.options?.userModel, ...this.userModel };
        let userModel = this.transformUserModel();
        keys({ ...(this.model?.components || {}), ...userModel })
            .map((key, index) => {
            return {
                type: this.modeller.getConnector(),
                id: !index ? this.model?.components[0].id : key,
                value: this.model?.type === 'input' ? this.inputModel?.[key] : '',
                removable: !!(userModel || {})?.[key],
                inputOutputComponent: !index && this.model?.components[0]?.inputOutputComponent || undefined
            };
        }).forEach((com, index) => {
            const component = this.containerRef.createComponent(com.type, {
                injector: this.containerRef.injector,
            });
            component.instance.connector.subscribe((connector) => {
                this.connector.emit(connector);
            });
            component.instance.optionsChanged.subscribe(() => this.optionsChanged.emit());
            component.setInput('parent', this);
            component.setInput('id', com.id);
            component.setInput('subId', this.subId);
            component.setInput('inputOutputComponent', com?.inputOutputComponent);
            component.setInput('type', index && 'output' || 'input');
            component.setInput('removable', com.removable);
            component.setInput('options', this.options);
            component.setInput('translations', this.model?.translations);
            this.setRemove(component, com);
            if (com.removable) {
                component.instance.optionsChanged.subscribe(() => {
                    this.optionsChanged.emit();
                });
                component.instance.changed.subscribe(() => {
                    const collect = {};
                    this.components.forEach((com, index) => {
                        if (index) {
                            collect[com.instance.id] = com.instance.value;
                        }
                    });
                    this.components[0].setInput('value', collect);
                });
            }
            if ('input' === this.model?.type) {
                component.setInput('value', com.value);
            }
            // required to start triggering hooks without that is not trigger ngOnChanges/ngOnInit/ngAfterViewInit
            component.changeDetectorRef.detectChanges();
            this.components.push(component);
        });
    }
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: FormulaBoxComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
    static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.4", type: FormulaBoxComponent, isStandalone: false, selector: "obl-formula-box", usesInheritance: true, ngImport: i0, template: "<div\n  class=\"header\"\n  (mousedown)=\"dragBox.emit({ mouse: $event, component: this })\"\n>\n  {{ model?.translations?.[model?.title || ''] || model?.title }}\n  @if (model?.type === 'in-out') {\n    <button oblButton [icon]=\"'cancel'\" (click)=\"remove.emit(this)\"></button>\n  }\n</div>\n\n<div>\n  <ng-container #containerRef></ng-container>\n</div>\n\n@if (model?.type === 'output' || dynamic) {\n  <div class=\"output\">\n    @if (type === 'input') {\n    <obl-input-wrapper [label]=\"modeller.getTranslation('Add new field')\">\n      <input oblInput #newName type=\"text\"/>\n      <button oblButton [icon]=\"'add'\" (click)=\"add(newName.value); newName.value = ''\" required suffix></button>\n    </obl-input-wrapper>\n  } @else {\n    <button oblButton [icon]=\"'add'\" (click)=\"add()\">{{ modeller.getTranslation('Add new input') }}</button>\n  }\n  </div>\n}\n", styles: [":host{position:absolute;display:block;width:250px;height:auto;border:1px var(--default-border-color) solid;border-radius:10px;background-color:var(--default-background-color)}.header{padding:5px;text-align:center;border-bottom:1px var(--default-border-color) solid;cursor:move;position:relative}.header button{position:absolute;right:2px;top:2px;border-radius:50%;--obl-icon-width: 10px;--obl-default-button-padding: 5px}.output{padding:5px}.output button{margin-left:auto;border-radius:5px;--obl-icon-width: 25px;--obl-default-button-padding: 5px 15px 5px 5px}.output obl-input-wrapper button{border-radius:50%;--obl-icon-width: 10px;--obl-default-button-padding: 5px}\n"], dependencies: [{ kind: "directive", type: i1.InputDirective, selector: "input[oblInput]", inputs: ["outlined"], exportAs: ["oblInput"] }, { kind: "component", type: i1.InputWrapperComponent, selector: "obl-input-wrapper", inputs: ["label", "display", "cancellable", "step", "errors", "translations", "labelAnimation", "small"], outputs: ["loaded"] }, { kind: "directive", type: i2.ButtonDirective, selector: "oblButton, [oblButton]", inputs: ["oblButton", "icon", "blockWhenLoading", "loading", "toggle", "selected", "link", "target"], exportAs: ["oblButton"] }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: FormulaBoxComponent, decorators: [{
            type: Component,
            args: [{ selector: 'obl-formula-box', standalone: false, template: "<div\n  class=\"header\"\n  (mousedown)=\"dragBox.emit({ mouse: $event, component: this })\"\n>\n  {{ model?.translations?.[model?.title || ''] || model?.title }}\n  @if (model?.type === 'in-out') {\n    <button oblButton [icon]=\"'cancel'\" (click)=\"remove.emit(this)\"></button>\n  }\n</div>\n\n<div>\n  <ng-container #containerRef></ng-container>\n</div>\n\n@if (model?.type === 'output' || dynamic) {\n  <div class=\"output\">\n    @if (type === 'input') {\n    <obl-input-wrapper [label]=\"modeller.getTranslation('Add new field')\">\n      <input oblInput #newName type=\"text\"/>\n      <button oblButton [icon]=\"'add'\" (click)=\"add(newName.value); newName.value = ''\" required suffix></button>\n    </obl-input-wrapper>\n  } @else {\n    <button oblButton [icon]=\"'add'\" (click)=\"add()\">{{ modeller.getTranslation('Add new input') }}</button>\n  }\n  </div>\n}\n", styles: [":host{position:absolute;display:block;width:250px;height:auto;border:1px var(--default-border-color) solid;border-radius:10px;background-color:var(--default-background-color)}.header{padding:5px;text-align:center;border-bottom:1px var(--default-border-color) solid;cursor:move;position:relative}.header button{position:absolute;right:2px;top:2px;border-radius:50%;--obl-icon-width: 10px;--obl-default-button-padding: 5px}.output{padding:5px}.output button{margin-left:auto;border-radius:5px;--obl-icon-width: 25px;--obl-default-button-padding: 5px 15px 5px 5px}.output obl-input-wrapper button{border-radius:50%;--obl-icon-width: 10px;--obl-default-button-padding: 5px}\n"] }]
        }] });

class FormulaComponent {
    toTransform;
    /** */
    options;
    /** */
    translations;
    transformed = new EventEmitterExt();
    optionsChanged = new EventEmitterExt();
    formula = '';
    value;
    transform() {
        const toTransform = this.toTransform || {};
        if (toTransform) {
            let length = undefined;
            keys(toTransform).forEach(key => length = Array.isArray(this.toTransform?.[key]) && (toTransform?.[key]).length || undefined);
            let converted;
            if (length !== undefined) {
                converted = [];
                length = length || 1;
                for (let i = 0; i < length; i++) {
                    const collect = {};
                    keys(toTransform).forEach(key => {
                        const value = toTransform?.[key];
                        if (Array.isArray(value)) {
                            collect[key] = value[i];
                        }
                        else {
                            collect[key] = value;
                        }
                    });
                    converted.push(collect);
                }
            }
            else {
                converted = toTransform;
            }
            try {
                const formula = JSON.parse(this.formula);
                let value;
                if (Array.isArray(converted)) {
                    value = [];
                    converted.forEach(values => {
                        value.push(ElementaryMath.calculate(formula, values));
                    });
                }
                else {
                    value = ElementaryMath.calculate(formula, converted);
                }
                this.value = value;
            }
            catch (e) {
                console.log(e);
            }
        }
        else {
            this.value = undefined;
        }
        this.transformed.emit(this.value);
    }
    changed(event) {
        this.formula = event.value;
        this.options = { ...this.options, formula: this.formula };
        this.transform();
        this.optionsChanged.emit();
    }
    ngOnChanges(changes) {
        if (changes.toTransform) {
            this.transform();
        }
        if (changes.options) {
            this.formula = this?.options?.formula || this.formula;
            this.transform();
        }
    }
    ngOnDestroy() {
        this.transformed.unsubscribe();
    }
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: FormulaComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
    static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.0.4", type: FormulaComponent, isStandalone: false, selector: "obl-formula", inputs: { toTransform: "toTransform", options: "options", translations: "translations" }, outputs: { transformed: "transformed", optionsChanged: "optionsChanged" }, usesOnChanges: true, ngImport: i0, template: "<obl-input-wrapper [label]=\"translations?.Formula || 'Formula'\">\n  <input\n    type=\"text\"\n    oblInput\n    [value]=\"formula\"\n    (change)=\"changed($event.target)\"\n    (keyup)=\"changed(form)\"\n    #form\n  />\n</obl-input-wrapper>\n\n<fieldset>\n  <legend>{{ translations?.Example || 'Example' }}</legend>\n  <p>[\"*\", [\"sin\", [\"get\", \"x\"]], [\"cos\", [\"get\", \"y\"]]]</p>\n</fieldset>", styles: [":root{--obl-spinner-width: 30px;--obl-font-size: 14px}fieldset{border-radius:5px;padding:0 5px 5px}fieldset legend{font-size:12px;border:1px solid get-default-color(border-color);border-radius:5px}fieldset p{margin:0;white-space:normal}\n"], dependencies: [{ kind: "directive", type: i1.InputDirective, selector: "input[oblInput]", inputs: ["outlined"], exportAs: ["oblInput"] }, { kind: "component", type: i1.InputWrapperComponent, selector: "obl-input-wrapper", inputs: ["label", "display", "cancellable", "step", "errors", "translations", "labelAnimation", "small"], outputs: ["loaded"] }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: FormulaComponent, decorators: [{
            type: Component,
            args: [{ selector: 'obl-formula', standalone: false, template: "<obl-input-wrapper [label]=\"translations?.Formula || 'Formula'\">\n  <input\n    type=\"text\"\n    oblInput\n    [value]=\"formula\"\n    (change)=\"changed($event.target)\"\n    (keyup)=\"changed(form)\"\n    #form\n  />\n</obl-input-wrapper>\n\n<fieldset>\n  <legend>{{ translations?.Example || 'Example' }}</legend>\n  <p>[\"*\", [\"sin\", [\"get\", \"x\"]], [\"cos\", [\"get\", \"y\"]]]</p>\n</fieldset>", styles: [":root{--obl-spinner-width: 30px;--obl-font-size: 14px}fieldset{border-radius:5px;padding:0 5px 5px}fieldset legend{font-size:12px;border:1px solid get-default-color(border-color);border-radius:5px}fieldset p{margin:0;white-space:normal}\n"] }]
        }], propDecorators: { toTransform: [{
                type: Input
            }], options: [{
                type: Input
            }], translations: [{
                type: Input
            }], transformed: [{
                type: Output
            }], optionsChanged: [{
                type: Output
            }] } });

class GetRequestComponent {
    /** */
    options;
    /** */
    translations;
    transformed = new EventEmitterExt();
    optionsChanged = new EventEmitterExt();
    path = '';
    toTransform;
    ngOnInit() {
    }
    async get() {
        const [resp, error] = await fetch(this.path).then(resp => resp.json());
        if (resp) {
            this.toTransform = resp;
            this.transformed.emit(resp);
        }
    }
    ngOnChanges(changes) {
        if (changes.options) {
            this.path = this.options?.path || this.path;
            this.get().then();
        }
    }
    transform() {
        this.transformed.emit(this.toTransform);
    }
    changed() {
        this.options = { ...this.options, path: this.path };
        this.transformed.emit(this.toTransform);
        this.optionsChanged.emit();
    }
    ngOnDestroy() {
        this.transformed.unsubscribe();
    }
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: GetRequestComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
    static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.0.4", type: GetRequestComponent, isStandalone: false, selector: "obl-get-request", inputs: { options: "options", translations: "translations", toTransform: "toTransform" }, outputs: { transformed: "transformed", optionsChanged: "optionsChanged" }, usesOnChanges: true, ngImport: i0, template: "<obl-input-wrapper>\n  <input oblInput [(ngModel)]=\"path\" (change)=\"changed()\" />\n  <div suffix>\n    <button oblButton icon=\"ok\" (click)=\"get()\"></button>\n  </div>\n</obl-input-wrapper>\n", styles: ["obl-input-wrapper button{border-radius:50%;--obl-icon-width: 14px;--obl-default-button-padding: 5px}\n"], dependencies: [{ kind: "directive", type: i1.InputDirective, selector: "input[oblInput]", inputs: ["outlined"], exportAs: ["oblInput"] }, { kind: "component", type: i1.InputWrapperComponent, selector: "obl-input-wrapper", inputs: ["label", "display", "cancellable", "step", "errors", "translations", "labelAnimation", "small"], outputs: ["loaded"] }, { kind: "directive", type: i2.ButtonDirective, selector: "oblButton, [oblButton]", inputs: ["oblButton", "icon", "blockWhenLoading", "loading", "toggle", "selected", "link", "target"], exportAs: ["oblButton"] }, { kind: "directive", type: i3.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i3.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: GetRequestComponent, decorators: [{
            type: Component,
            args: [{ selector: 'obl-get-request', standalone: false, template: "<obl-input-wrapper>\n  <input oblInput [(ngModel)]=\"path\" (change)=\"changed()\" />\n  <div suffix>\n    <button oblButton icon=\"ok\" (click)=\"get()\"></button>\n  </div>\n</obl-input-wrapper>\n", styles: ["obl-input-wrapper button{border-radius:50%;--obl-icon-width: 14px;--obl-default-button-padding: 5px}\n"] }]
        }], propDecorators: { options: [{
                type: Input
            }], translations: [{
                type: Input
            }], transformed: [{
                type: Output
            }], optionsChanged: [{
                type: Output
            }], toTransform: [{
                type: Input
            }] } });

class ModellerService {
    models = new Map();
    translations = {};
    menuItems = [];
    constructor() {
        this.register('input', {
            title: 'Input',
            components: [],
            type: 'input',
            translations: this.translations
        });
        this.register('output', {
            title: 'Output',
            components: [],
            type: 'output',
            translations: this.translations
        });
        const type = 'in-out';
        this.register('convert-to-histogram', {
            title: 'Convert to histogram',
            components: [
                { type: ConnectorItemComponent, id: 'histogram', inputOutputComponent: ConvertToHistogramComponent }
            ],
            type,
            translations: this.translations
        });
        this.register('integer', {
            title: 'Integer filter',
            components: [
                { type: ConnectorItemComponent, id: 'integer', inputOutputComponent: IntegerFilterConnectorComponent },
            ],
            type,
            translations: this.translations
        });
        this.register('range', {
            title: 'Range filter',
            components: [
                { type: ConnectorItemComponent, id: 'ranges', inputOutputComponent: RangeFilterComponent },
            ],
            type,
            translations: this.translations
        });
        this.register('string-converter', {
            title: 'String converter',
            components: [
                { type: ConnectorItemComponent, id: 'string-converter', inputOutputComponent: StringConverterComponent },
            ],
            type,
            translations: this.translations
        });
        this.register('split-object', {
            title: 'Split object',
            components: [
                { type: ConnectorItemComponent, id: 'split-object', connectorType: 'output' }
            ],
            box: SplitBoxComponent,
            type,
            translations: this.translations
        });
        this.register('math-operator', {
            title: 'Math operator',
            components: [
                { type: ConnectorItemComponent, id: 'left', connectorType: 'output', inputOutputComponent: ValueInputComponent },
                { type: ConnectorItemComponent, id: 'right', connectorType: 'output', inputOutputComponent: ValueInputComponent },
                { type: ConnectorItemComponent, id: 'math-operator', connectorType: 'input', inputOutputComponent: MathOperatorComponent }
            ],
            box: MathBoxComponent,
            type,
            translations: this.translations
        });
        this.register('const-or-variable', {
            title: 'Constant or variable',
            components: [
                { type: ConnectorItemComponent, id: 'const-or-value', connectorType: 'input', inputOutputComponent: ConstOrValueComponent },
            ],
            type,
            translations: this.translations
        });
        this.register('join-array-to-object', {
            title: 'Join array to object',
            components: [
                { type: ConnectorItemComponent, id: 'convert', connectorType: 'input' },
            ],
            type,
            box: JoinArrayToObjectBoxComponent,
            translations: this.translations
        });
        this.register('split-input', {
            title: 'Split input',
            components: [
                { type: ConnectorItemComponent, id: 'split', connectorType: 'output' },
            ],
            type,
            box: SplitInputBoxComponent,
            translations: this.translations
        });
        this.register('generate', {
            title: 'Generate',
            components: [
                { type: ConnectorItemComponent, id: 'generate-array', connectorType: 'input', inputOutputComponent: GenerateComponent }
            ],
            type,
            translations: this.translations
        });
        this.register('concat-arrays', {
            title: 'Concat arrays',
            components: [
                { type: ConnectorItemComponent, id: 'concat', connectorType: 'input' }
            ],
            type,
            box: ConcatArrayBoxComponent,
            translations: this.translations
        });
        this.register('formula', {
            title: 'Formula',
            components: [
                { type: ConnectorItemComponent, id: 'formula-calc', connectorType: 'input', inputOutputComponent: FormulaComponent }
            ],
            type,
            box: FormulaBoxComponent,
            translations: this.translations
        });
        this.register('get-request', {
            title: 'Get request',
            components: [
                { type: ConnectorItemComponent, id: 'get-request-input', connectorType: 'input', inputOutputComponent: GetRequestComponent },
            ],
            type,
            translations: this.translations
        });
    }
    setTranslations(translations) {
        keys(translations).forEach(key => {
            this.translations[key] = translations[key];
        });
    }
    getTranslations() {
        return this.translations;
    }
    getConnector() {
        return ConnectorItemComponent;
    }
    register(id, model) {
        if (this.models.has(id)) {
            throw `This id=${id} is already in use`;
        }
        this.models.set(id, model);
        this.setMenuItems();
    }
    create(id, container, subId, options) {
        if (!container) {
            throw new Error('container instance not exist');
        }
        if (!this.models.has(id)) {
            throw `This id=${id} component was not registered`;
        }
        const model = this.models.get(id);
        const componentRef = container.createComponent(model?.box || ModellerBoxComponent, {
            injector: container.injector,
        });
        componentRef.setInput('model', model);
        componentRef.setInput('id', id);
        componentRef.setInput('subId', !['input', 'output'].includes(model?.type || '') && subId || '');
        const { position } = options || {};
        componentRef.setInput('translate', new Point2D(position?.x || 0, position?.y || 0));
        return componentRef;
    }
    setMenuItems() {
        const menuItems = [];
        const exclude = ['input', 'output'];
        this.models.forEach((value, key) => {
            if (!exclude.includes(key)) {
                menuItems.push({
                    id: key,
                    text: key.replace(/\-/g, ' '),
                    command: key
                });
            }
        });
        this.menuItems = menuItems;
    }
    getTranslation(en) {
        return this.translations?.[en] || en;
    }
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: ModellerService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
    static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: ModellerService, providedIn: 'root' });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: ModellerService, decorators: [{
            type: Injectable,
            args: [{
                    providedIn: 'root'
                }]
        }], ctorParameters: () => [] });

class ModellerSpaceComponent {
    modeller;
    ref;
    boxes = [];
    /** */
    connectorsSet = [];
    /** Inputs values to filtering out */
    input = {};
    /**  */
    output = new EventEmitter();
    /** */
    connectorsSetChanged = new EventEmitter();
    /** */
    boxesChanged = new EventEmitter();
    /** Output filtered out values */
    _output = {};
    components = [];
    translation = new Point2D(0, 0);
    buttons = 0;
    mouse = new Point2D();
    mousePos = new Point2D();
    clickedPlace = new Point2D();
    selected;
    source;
    connectors = [];
    create;
    connectorsComponents;
    containerRef;
    timer;
    mousemove(event) {
        const rect = this.ref.nativeElement.getBoundingClientRect();
        this.mousePos = new Point2D(event.clientX - rect.x, event.clientY - rect.y);
        if (this.create) {
            if (!this.timer) {
                this.timer = setInterval(() => {
                    if (this.mousePos.y < 50) {
                        this.translation = this.translation.add(new Point2D(0, 10));
                        this.moveCreated();
                        this.recalcPos();
                    }
                    if (this.mousePos.y > rect.height - 50) {
                        this.translation = this.translation.add(new Point2D(0, -10));
                        this.moveCreated();
                        this.recalcPos();
                    }
                    if (this.mousePos.x < 50) {
                        this.translation = this.translation.add(new Point2D(10, 0));
                        this.moveCreated();
                        this.recalcPos();
                    }
                    if (this.mousePos.x > rect.width - 50) {
                        this.translation = this.translation.add(new Point2D(-10, 0));
                        this.moveCreated();
                        this.recalcPos();
                    }
                }, 100);
            }
            this.moveCreated();
        }
        else if (this.timer) {
            clearInterval(this.timer);
            this.timer = undefined;
        }
        if (this.buttons === 1) {
            const move = () => this.mouse = new Point2D(event.x, event.y).subtract(this.clickedPlace);
            if (this.selected) {
                move();
                this.selected.offset = new Point2D(event.x, event.y).subtract(this.clickedPlace);
                this.selected.recalc();
            }
            else {
                if (this.source !== 'svg') {
                    return;
                }
                move();
                this.recalcPos();
            }
        }
    }
    mousedown(event) {
        this.buttons = event.buttons;
        this.clickedPlace.x = event.x;
        this.clickedPlace.y = event.y;
        this.source = event.target.nodeName;
        if (['svg', 'path'].includes(this.source || '')) {
            this.create = undefined;
        }
    }
    mouseup(event) {
        // eslint-disable-next-line eqeqeq
        if (this.buttons == 1) {
            if (this.selected) {
                this.selected.translate = this.selected.translate.add(this.selected.offset);
                this.selected.offset = new Point2D();
                this.selected.recalc();
                this.setBoxes();
            }
            else {
                this.translation = this.translation.add(this.mouse);
            }
        }
        this.buttons = event.button;
        this.mouse = new Point2D();
        this.selected = undefined;
    }
    moveCreated() {
        if (this.create) {
            if (this.create.right) {
                this.create.start = this.mousePos.subtract(this.translation);
            }
            else {
                this.create.end = this.mousePos.subtract(this.translation);
            }
        }
    }
    setBoxes() {
        this.boxes = this.components.map(com => com.instance.getBoxItemModel());
        this.boxesChanged.emit(this.boxes);
    }
    constructor(modeller, ref) {
        this.modeller = modeller;
        this.ref = ref;
    }
    recalcPos() {
        this.components.forEach(component => component.instance.world = this.translation.add(this.mouse));
    }
    ngOnChanges(changes) {
        if (changes.boxes) {
            this.reload();
            this.boxesChanged.emit(this.boxes);
        }
        if (changes.input) {
            this.setInputOutput();
        }
    }
    ngAfterViewInit() {
        setTimeout(() => {
            this.reload();
            this.setInputOutput();
            if (this.connectorsSet) {
                this.connectors = [...this.connectorsSet];
                this.setConnectors();
                this.components.forEach(component => {
                    component.instance.recalc();
                });
            }
        });
    }
    ngOnDestroy() {
        if (this.timer) {
            clearInterval(this.timer);
        }
    }
    setInputOutput() {
        const input = this.getInput();
        const output = this.getOutput();
        if (input && output) {
            input.setInput('inputModel', this.input);
            input.changeDetectorRef.detectChanges();
            output.setInput('inputModel', this.input);
            output.changeDetectorRef.detectChanges();
        }
    }
    setConnectors(after) {
        setTimeout(() => {
            this.components.forEach(component => {
                component.instance.setConnectors(Array.from(this.connectorsComponents));
            });
            if (after) {
                after();
            }
        });
    }
    removeEmptyConnector(fullId, side) {
        const find = this.connectors.find(con => con?.[side] === fullId);
        if (find) {
            const conn = this.getById(find?.[side === 'left' ? 'right' : 'left'] || '');
            if (conn?.instance?.[side === 'left' ? 'right' : 'left'] || !conn) {
                this.removeConnector(find);
                return true;
            }
        }
        return false;
    }
    reload() {
        if (this.boxes && this.containerRef) {
            /** remove components before reinitialize */
            this.components.forEach((component, index) => {
                if (!this.boxes?.find(box => box.id === component.instance.id && box.subId === component.instance.subId)) {
                    if (component.instance.model?.type === 'in-out' &&
                        component.instance.id !== 'input' && component.instance.id !== 'output' && component.instance.subId) {
                        component.instance.dragBox.clearSubscriptions();
                        component.instance.connector.clearSubscriptions();
                        component.instance.remove.clearSubscriptions();
                        component.instance.removeConnector.clearSubscriptions();
                        component.instance.optionsChanged.clearSubscriptions();
                        component.destroy();
                        this.components[index] = undefined;
                    }
                }
            });
            this.components = this.components.filter(component => {
                return component;
            });
            const input = this.boxes.find(box => box.id === 'input' && box.subId === '');
            const output = this.boxes.find(box => box.id === 'output' && box.subId === '');
            (this.components.length
                ? this.boxes
                : Array.from([
                    {
                        id: 'input',
                        subId: '',
                        options: input?.options
                    },
                    {
                        id: 'output',
                        subId: '',
                        options: output?.options
                    }
                ]).concat(this.boxes)).forEach((box, index) => {
                if (!this.components.find(component => component.instance.id === box.id && component.instance.subId === box.subId)) {
                    box.subId = box.subId || uuid.v4();
                    let options = {};
                    const rect = this.ref.nativeElement.getBoundingClientRect();
                    if (box.options) {
                        options = box.options;
                    }
                    else {
                        if (box.id === 'input' || box.id === 'output') {
                            options.position = {
                                x: box.id === 'input' ? 10 : rect.width - 260,
                                y: 10
                            };
                        }
                        else {
                            options.position = this.mousePos.subtract(this.translation);
                        }
                    }
                    const component = this.modeller.create(box.id, this.containerRef, box.subId, options);
                    component.instance.optionsChanged.subscribe(() => {
                        this.setBoxes();
                        this.boxesChanged.emit(this.boxes);
                    });
                    component.instance.dragBox.subscribe(data => {
                        this.selected = data.component;
                        this.create = undefined;
                        this.components.sort((p, c) => p.instance.index - c.instance.index).forEach((component, index) => {
                            if (component.instance !== this.selected) {
                                component.setInput('index', index);
                                component.changeDetectorRef.detectChanges();
                            }
                            else {
                                component.setInput('index', this.components.length);
                                component.changeDetectorRef.detectChanges();
                            }
                        });
                    });
                    component.instance.connector.subscribe(connector => {
                        if (!this.create) {
                            if (connector.left) {
                                connector.end = this.mousePos.subtract(this.translation);
                            }
                            else if (connector.right) {
                                connector.start = this.mousePos.subtract(this.translation);
                            }
                            this.create = connector;
                        }
                        else {
                            this.create = { ...this.create, ...connector };
                            if (this.create.left && this.create.right) {
                                this.connectors.push(this.create);
                                this.emitConnectorsSet();
                            }
                            this.create = undefined;
                            this.setConnectors();
                        }
                    });
                    component.instance.removeConnector.subscribe((id) => {
                        const connector = this.connectors.find(conn => conn?.left === id || conn?.right === id);
                        if (connector) {
                            this.removeConnector(connector);
                        }
                    });
                    if (box.id !== 'input' && box.id !== 'output') {
                        component.instance.remove.subscribe(component => {
                            component.allConnectors().forEach(connector => {
                                if (connector.connector?.left) {
                                    const found = this.connectors.find(conn => conn.left === connector.connector?.left || conn.right === connector.connector?.right);
                                    if (found) {
                                        this.removeConnector(found);
                                    }
                                }
                            });
                            this.boxes = (this.boxes || []).filter(box => box.id !== component.id || box.subId !== component.subId);
                            this.reload();
                            this.boxesChanged.emit(this.boxes);
                        });
                    }
                    if (box.id === 'output') {
                        component.instance.outputChanged.subscribe(value => {
                            this.output.emit(value);
                        });
                    }
                    component.setInput('options', options);
                    component.setInput('index', index);
                    component.setInput('parent', this);
                    component.changeDetectorRef.detectChanges();
                    this.components.push(component);
                }
            });
            this.recalcPos();
        }
    }
    getById(id) {
        const [parentId, subId, itemId] = id.split(':');
        const item = this.components.map((item) => item.instance.item(parentId, subId, itemId)).filter(v => v)?.[0];
        return item;
    }
    /** by assumption first one should be an output and should always exist */
    getInput() {
        return this.components[0];
    }
    /** by assumption second one should be an output and should always exist */
    getOutput() {
        return this.components[1];
    }
    menuClicked(command) {
        this.boxes = [...(this.boxes || []), {
                id: command
            }];
        this.reload();
        // this.boxesChanged.emit(this.boxes);
        this.setBoxes();
    }
    removeConnector(connector) {
        const left = this.getById(connector?.left || '');
        if (left) {
            left.instance.parent.connectors = [];
            left.instance.input?.clearSubscriptions();
            left.instance.left = undefined;
            left.changeDetectorRef.detectChanges();
        }
        const right = this.getById(connector?.right || '');
        if (right) {
            right.instance.parent.connectors = [];
            right.instance.input?.clearSubscriptions();
            right.instance.right = undefined;
            right.setInput('value', undefined);
            right.instance.value = undefined;
            right.changeDetectorRef.detectChanges();
        }
        this.connectors = this.connectors.filter(con => con !== connector);
        this.emitConnectorsSet();
    }
    emitConnectorsSet() {
        this.connectorsSet = this.connectors.map(conn => ({ left: conn.left, right: conn.right }));
        this.connectorsSetChanged.emit(this.connectorsSet);
    }
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: ModellerSpaceComponent, deps: [{ token: ModellerService }, { token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component });
    static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.4", type: ModellerSpaceComponent, isStandalone: false, selector: "obl-modeller-space", inputs: { boxes: "boxes", connectorsSet: "connectorsSet", input: "input" }, outputs: { output: "output", connectorsSetChanged: "connectorsSetChanged", boxesChanged: "boxesChanged" }, host: { listeners: { "mousemove": "mousemove($event)", "mousedown": "mousedown($event)", "mouseup": "mouseup($event)" } }, viewQueries: [{ propertyName: "containerRef", first: true, predicate: ["containerRef"], descendants: true, read: ViewContainerRef }, { propertyName: "connectorsComponents", predicate: RelationConnectorComponent, descendants: true }], usesOnChanges: true, ngImport: i0, template: "<svg>\n  <g\n    [attr.transform]=\"\n      (selected ? translation : translation.add(mouse)).toCssTranslate()\n    \"\n  >\n    @for (connector of connectors; track $index) {\n      <g\n        obl-relation-connector\n        [right]=\"connector.end\"\n        [left]=\"connector.start\"\n        [connector]=\"connector\"\n        (clicked)=\"removeConnector(connector)\"\n      ></g>\n    }\n\n    @if (create) {\n      <g\n        obl-relation-connector\n        [right]=\"create.end\"\n        [left]=\"create.start\"\n        [connector]=\"create\"\n      ></g>\n    }\n  </g>\n</svg>\n\n<ng-container #containerRef></ng-container>\n\n<obl-menu\n  [target]=\"ref.nativeElement\"\n  [items]=\"modeller.menuItems\"\n  [translations]=\"modeller.getTranslations()\"\n  (clicked)=\"menuClicked($event)\"\n></obl-menu>\n", styles: [":host{display:flex;position:relative;width:100%;height:80vh;border:1px var(--default-border-color) solid;overflow:hidden;-webkit-user-select:none;-ms-user-select:none;user-select:none}svg{position:absolute;display:block;width:100%;height:100%;top:0;left:0}::ng-deep .obl-menu{z-index:10000}\n"], dependencies: [{ kind: "component", type: i2$3.RelationConnectorComponent, selector: "g[obl-relation-connector]", inputs: ["left", "right", "connector", "highlighted", "offset", "defaultColor", "menu", "translations", "disabled", "input"], outputs: ["clicked", "remove", "editColor"] }, { kind: "component", type: i3$1.MenuComponent, selector: "obl-menu", inputs: ["opened", "target", "items", "translations"], outputs: ["clicked"] }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: ModellerSpaceComponent, decorators: [{
            type: Component,
            args: [{ selector: 'obl-modeller-space', standalone: false, template: "<svg>\n  <g\n    [attr.transform]=\"\n      (selected ? translation : translation.add(mouse)).toCssTranslate()\n    \"\n  >\n    @for (connector of connectors; track $index) {\n      <g\n        obl-relation-connector\n        [right]=\"connector.end\"\n        [left]=\"connector.start\"\n        [connector]=\"connector\"\n        (clicked)=\"removeConnector(connector)\"\n      ></g>\n    }\n\n    @if (create) {\n      <g\n        obl-relation-connector\n        [right]=\"create.end\"\n        [left]=\"create.start\"\n        [connector]=\"create\"\n      ></g>\n    }\n  </g>\n</svg>\n\n<ng-container #containerRef></ng-container>\n\n<obl-menu\n  [target]=\"ref.nativeElement\"\n  [items]=\"modeller.menuItems\"\n  [translations]=\"modeller.getTranslations()\"\n  (clicked)=\"menuClicked($event)\"\n></obl-menu>\n", styles: [":host{display:flex;position:relative;width:100%;height:80vh;border:1px var(--default-border-color) solid;overflow:hidden;-webkit-user-select:none;-ms-user-select:none;user-select:none}svg{position:absolute;display:block;width:100%;height:100%;top:0;left:0}::ng-deep .obl-menu{z-index:10000}\n"] }]
        }], ctorParameters: () => [{ type: ModellerService }, { type: i0.ElementRef }], propDecorators: { boxes: [{
                type: Input
            }], connectorsSet: [{
                type: Input
            }], input: [{
                type: Input
            }], output: [{
                type: Output
            }], connectorsSetChanged: [{
                type: Output
            }], boxesChanged: [{
                type: Output
            }], connectorsComponents: [{
                type: ViewChildren,
                args: [RelationConnectorComponent]
            }], containerRef: [{
                type: ViewChild,
                args: ['containerRef', { read: ViewContainerRef }]
            }], mousemove: [{
                type: HostListener,
                args: ['mousemove', ['$event']]
            }], mousedown: [{
                type: HostListener,
                args: ['mousedown', ['$event']]
            }], mouseup: [{
                type: HostListener,
                args: ['mouseup', ['$event']]
            }] } });

class ModellerModule {
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: ModellerModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
    static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.0.4", ngImport: i0, type: ModellerModule, declarations: [ModellerSpaceComponent,
            ModellerBoxComponent,
            ConnectorItemComponent,
            IntegerFilterConnectorComponent,
            ConvertToHistogramComponent,
            RangeFilterComponent,
            StringConverterComponent,
            SplitBoxComponent,
            MathBoxComponent,
            ValueInputComponent,
            MathOperatorComponent,
            ConstOrValueComponent,
            JoinArrayToObjectBoxComponent,
            SplitInputBoxComponent,
            GenerateComponent,
            ConcatArrayBoxComponent,
            FormulaBoxComponent,
            FormulaComponent,
            GetRequestComponent], imports: [CommonModule,
            ConnectorsModule,
            InputModule,
            DropdownSelectModule,
            MenuModule,
            ButtonsModule,
            FormsModule], exports: [ModellerSpaceComponent,
            ConnectorItemComponent] });
    static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: ModellerModule, imports: [CommonModule,
            ConnectorsModule,
            InputModule,
            DropdownSelectModule,
            MenuModule,
            ButtonsModule,
            FormsModule] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: ModellerModule, decorators: [{
            type: NgModule,
            args: [{
                    declarations: [
                        ModellerSpaceComponent,
                        ModellerBoxComponent,
                        ConnectorItemComponent,
                        IntegerFilterConnectorComponent,
                        ConvertToHistogramComponent,
                        RangeFilterComponent,
                        StringConverterComponent,
                        SplitBoxComponent,
                        MathBoxComponent,
                        ValueInputComponent,
                        MathOperatorComponent,
                        ConstOrValueComponent,
                        JoinArrayToObjectBoxComponent,
                        SplitInputBoxComponent,
                        GenerateComponent,
                        ConcatArrayBoxComponent,
                        FormulaBoxComponent,
                        FormulaComponent,
                        GetRequestComponent
                    ],
                    imports: [
                        CommonModule,
                        ConnectorsModule,
                        InputModule,
                        DropdownSelectModule,
                        MenuModule,
                        ButtonsModule,
                        FormsModule
                    ],
                    exports: [
                        ModellerSpaceComponent,
                        ConnectorItemComponent
                    ]
                }]
        }] });

/**
 * Generated bundle index. Do not edit.
 */

export { ConnectorItemComponent, ModellerModule, ModellerService, ModellerSpaceComponent };
//# sourceMappingURL=obliczeniowo-elementary-modeller.mjs.map