import { inject, Injector } from '@angular/core';
import { LAYOUT_COMPONENT_TRANSFORM } from '@anglr/dynamic/layout';
import { RelationsChangeDetector, RelationsComponentManager, RelationsDebugger, RelationsManager, RelationsProcessor } from '@anglr/dynamic/relations';
import { LOGGER } from '@anglr/common';
/**
 * Service that handles storing, obtaining of placeholder configuration, also correct rendering of placeholder or placeholder container
 */
export class PlaceholderHandler {
    /**
     * Gets id of attached component
     */
    get id() {
        var _a;
        return ((_a = this.ɵid) !== null && _a !== void 0 ? _a : (this.ɵid = this.injector.get(this.componentWithIdType).id));
    }
    /**
     * Gets indication whether is this handler attached to custom component
     */
    get isCustomComponent() {
        return !this.ɵisPlaceholder;
    }
    /**
     * Gets indication whether is this handler attached to placeholder
     */
    get isPlaceholder() {
        return this.ɵisPlaceholder;
    }
    /**
     * Gets nearest handler for custom component
     */
    get nearestCustomComponent() {
        // eslint-disable-next-line @typescript-eslint/no-this-alias
        let handler = this;
        do {
            if (handler.isCustomComponent) {
                return handler;
            }
        } while ((handler = handler.parent));
        return null;
    }
    /**
     * Gets nearest handler for custom component that is in design mode
     */
    get nearestDesignCustomComponent() {
        // eslint-disable-next-line @typescript-eslint/no-this-alias
        let handler = this;
        do {
            if (handler.isCustomComponent && handler.designMode) {
                return handler;
            }
        } while ((handler = handler.parent));
        return null;
    }
    //######################### public properties #########################
    /**
     * Gets instance of parent placeholder handler
     */
    get parent() {
        return this.ɵparent;
    }
    /**
     * Gets indication whether is attached component in design mode
     */
    get designMode() {
        var _a;
        return ((_a = this.ɵdesignMode) !== null && _a !== void 0 ? _a : (this.ɵdesignMode = this.ɵisPlaceholder ?
            !!this.injector.get(LAYOUT_COMPONENT_TRANSFORM, null, { optional: true }) :
            !!this.injector.get(LAYOUT_COMPONENT_TRANSFORM, null, { skipSelf: true, optional: true, })));
    }
    /**
     * Gets indication whether display placeholder container or just placeholder
     */
    get placeholderContainer() {
        return !(!this.parent || (this.parent.isPlaceholder && this.parent.designMode));
    }
    /**
     * Gets layout designer component transform function
     */
    get layoutDesignerComponentTransform() {
        var _a, _b, _c;
        //current transform
        const transform = this.injector.get(LAYOUT_COMPONENT_TRANSFORM, null, { skipSelf: true, optional: true });
        //current or parent custom component transform
        const result = (_c = transform !== null && transform !== void 0 ? transform : (_b = (_a = this.findRelatedCustomComponentHandler()) === null || _a === void 0 ? void 0 : _a.injector) === null || _b === void 0 ? void 0 : _b.get(LAYOUT_COMPONENT_TRANSFORM, null, { skipSelf: true, optional: true })) !== null && _c !== void 0 ? _c : null;
        return result;
    }
    /**
     * Relations component manager instance that is used for placeholders
     */
    get relationsComponentManager() {
        var _a, _b;
        return (_b = (_a = this.getParentCustomComponentHandler()) === null || _a === void 0 ? void 0 : _a.injector.get(RelationsComponentManager, undefined, { skipSelf: true })) !== null && _b !== void 0 ? _b : null;
    }
    /**
     * Relations processor instance that is used for placeholders
     */
    get relationsProcessor() {
        var _a, _b;
        return (_b = (_a = this.getParentCustomComponentHandler()) === null || _a === void 0 ? void 0 : _a.injector.get(RelationsProcessor, undefined, { skipSelf: true })) !== null && _b !== void 0 ? _b : null;
    }
    /**
     * Relations change detector instance that is used for placeholders
     */
    get relationsChangeDetector() {
        var _a, _b;
        return (_b = (_a = this.getParentCustomComponentHandler()) === null || _a === void 0 ? void 0 : _a.injector.get(RelationsChangeDetector, undefined, { skipSelf: true })) !== null && _b !== void 0 ? _b : null;
    }
    /**
     * Relations debugger instance that is used for placeholders
     */
    get relationsDebugger() {
        var _a, _b;
        return (_b = (_a = this.getParentCustomComponentHandler()) === null || _a === void 0 ? void 0 : _a.injector.get(RelationsDebugger, undefined, { skipSelf: true })) !== null && _b !== void 0 ? _b : null;
    }
    /**
     * Relations manager instance that is used for placeholders
     */
    get relationsManager() {
        var _a, _b;
        return (_b = (_a = this.getParentCustomComponentHandler()) === null || _a === void 0 ? void 0 : _a.injector.get(RelationsManager, undefined, { skipSelf: true })) !== null && _b !== void 0 ? _b : null;
    }
    //######################### constructor #########################
    constructor(componentWithIdType, customComponent) {
        this.componentWithIdType = componentWithIdType;
        this.customComponent = customComponent;
        /**
         * Instance of parent placeholder handler
         */
        this.ɵparent = inject(PlaceholderHandler, { optional: true, skipSelf: true, });
        /**
         * Injector that is assigned with placeholder handler
         */
        this.injector = inject(Injector);
        /**
         * Instance of logger used for logging
         */
        this.logger = inject(LOGGER);
        this.ɵisPlaceholder = !this.customComponent;
    }
    //######################### public methods #########################
    /**
     * Gets options for placeholder using its id
     * @param id - Id of placeholder for which are options obtained
     */
    getOptions(id) {
        var _a, _b, _c;
        //is placeholder
        if (this.isPlaceholder) {
            if (!this.parent) {
                return null;
            }
            return this.parent.getOptions(id);
        }
        if (this.isCustomComponent && ((_c = (_b = (_a = this.customComponent) === null || _a === void 0 ? void 0 : _a.options) === null || _b === void 0 ? void 0 : _b.placeholderContainers) === null || _c === void 0 ? void 0 : _c[id])) {
            return this.customComponent.options.placeholderContainers[id];
        }
        if (!this.parent) {
            return null;
        }
        return this.parent.getOptions(id);
    }
    /**
     * Initialize options for placeholder container
     */
    initOptions() {
        var _a, _b;
        var _c;
        const custom = this.nearestDesignCustomComponent;
        if (!(custom === null || custom === void 0 ? void 0 : custom.designMode) || !custom.customComponent) {
            this.logger.error('PlaceholderHandler: closes parent custom component should be in editation mode!');
            return;
        }
        if (!custom.customComponent.options) {
            this.logger.error('PlaceholderHandler: missing custom component options!');
            return;
        }
        //if options does not exists create new one
        if (!((_a = custom.customComponent.options.placeholderContainers) === null || _a === void 0 ? void 0 : _a[this.id])) {
            const containerId = `placeholderContainer-${custom.id}-${this.id}`;
            (_b = (_c = custom.customComponent.options).placeholderContainers) !== null && _b !== void 0 ? _b : (_c.placeholderContainers = {});
            custom.customComponent.options.placeholderContainers[this.id] =
                {
                    id: containerId,
                    name: 'placeholderContainer',
                    package: 'custom-components',
                    displayName: containerId,
                    options: {},
                };
        }
    }
    //######################### protected methods #########################
    /**
     * Finds if there is any related handler with attached custom component
     */
    findRelatedCustomComponentHandler() {
        let placeholders = 0;
        let customComponents = 0;
        // eslint-disable-next-line @typescript-eslint/no-this-alias
        let handler = this;
        if (!handler.parent) {
            return null;
        }
        do {
            if (handler.parent.isCustomComponent && handler.parent.designMode) {
                if (placeholders == customComponents) {
                    return handler.parent;
                }
                return null;
            }
            if (handler.parent.isCustomComponent) {
                customComponents++;
            }
            else {
                placeholders++;
            }
        } while ((handler = handler.parent));
        return null;
    }
    /**
     * Gets handler, which is attached to custom component which owns this placeholder container
     */
    getParentCustomComponentHandler() {
        var _a, _b, _c;
        // eslint-disable-next-line @typescript-eslint/no-this-alias
        let handler = this;
        if (!handler.parent) {
            throw new Error('PlaceholderHandler: parent must be present to work with relations!');
        }
        do {
            //skip placeholder
            if (handler.isPlaceholder) {
                continue;
            }
            if ((_c = (_b = (_a = handler.customComponent) === null || _a === void 0 ? void 0 : _a.options) === null || _b === void 0 ? void 0 : _b.placeholderContainers) === null || _c === void 0 ? void 0 : _c[this.id]) {
                return handler;
            }
        } while ((handler = handler.parent));
        this.logger.error('PlaceholderHandler: unable to find owning custom component for {{@id}}', { id: this.id });
        return null;
    }
}
//# sourceMappingURL=placeholderHandler.service.js.map