/**
 * @dyna-grid/core - Advanced Data Grid / Data Table supporting Javascript / Web Components
 * @version v1.0.5
 * @link 
 * @license 
 */
var __extends = (this && this.__extends) || (function () {
    var extendStatics = function (d, b) {
        extendStatics = Object.setPrototypeOf ||
            ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
            function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
        return extendStatics(d, b);
    };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
import { Autowired, PostConstruct, PreConstruct } from "../context/context";
import { BeanStub } from "../context/beanStub";
import { NumberSequence } from "../utils";
import { isNodeOrElement, copyNodeList, iterateNamedNodeMap, loadTemplate, setVisible, setDisplayed, addCssClass, removeCssClass, addOrRemoveCssClass } from '../utils/dom';
import { forEach } from '../utils/array';
import { getFunctionName } from '../utils/function';
import { TooltipFeature } from "./tooltipFeature";
var compIdSequence = new NumberSequence();
var Component = /** @class */ (function (_super) {
    __extends(Component, _super);
    function Component(template) {
        var _this = _super.call(this) || this;
        _this.annotatedGuiListeners = [];
        // if false, then CSS class "dy-hidden" is applied, which sets "display: none"
        _this.displayed = true;
        // if false, then CSS class "dy-invisible" is applied, which sets "visibility: hidden"
        _this.visible = true;
        // unique id for this row component. this is used for getting a reference to the HTML dom.
        // we cannot use the RowNode id as this is not unique (due to animation, old rows can be lying
        // around as we create a new rowComp instance for the same row node).
        _this.compId = compIdSequence.next();
        // to minimise DOM hits, we only apply CSS classes if they have changed. as addding a CSS class that is already
        // there, or removing one that wasn't present, all takes CPU.
        _this.cssClassStates = {};
        if (template) {
            _this.setTemplate(template);
        }
        return _this;
    }
    Component.prototype.preConstructOnComponent = function () {
        this.usingBrowserTooltips = this.gridOptionsWrapper.isEnableBrowserTooltips();
    };
    Component.prototype.getCompId = function () {
        return this.compId;
    };
    Component.prototype.getTooltipParams = function () {
        return {
            value: this.tooltipText,
            location: 'UNKNOWN'
        };
    };
    Component.prototype.setTooltip = function (newTooltipText) {
        var _this = this;
        var removeTooltip = function () {
            if (_this.usingBrowserTooltips) {
                _this.getGui().removeAttribute('title');
            }
            else {
                _this.tooltipFeature = _this.destroyBean(_this.tooltipFeature);
            }
        };
        var addTooltip = function () {
            if (_this.usingBrowserTooltips) {
                _this.getGui().setAttribute('title', _this.tooltipText);
            }
            else {
                _this.tooltipFeature = _this.createBean(new TooltipFeature(_this));
            }
        };
        if (this.tooltipText != newTooltipText) {
            if (this.tooltipText) {
                removeTooltip();
            }
            this.tooltipText = newTooltipText;
            if (this.tooltipText) {
                addTooltip();
            }
        }
    };
    // for registered components only, eg creates DyCheckbox instance from dy-checkbox HTML tag
    Component.prototype.createChildComponentsFromTags = function (parentNode, paramsMap) {
        var _this = this;
        // we MUST take a copy of the list first, as the 'swapComponentForNode' adds comments into the DOM
        // which messes up the traversal order of the children.
        var childNodeList = copyNodeList(parentNode.childNodes);
        forEach(childNodeList, function (childNode) {
            if (!(childNode instanceof HTMLElement)) {
                return;
            }
            var childComp = _this.createComponentFromElement(childNode, function (comp) {
                // copy over all attributes, including css classes, so any attributes user put on the tag
                // wll be carried across
                _this.copyAttributesFromNode(childNode, comp.getGui());
            }, paramsMap);
            if (childComp) {
                if (childComp.addItems && childNode.children.length) {
                    _this.createChildComponentsFromTags(childNode, paramsMap);
                    // converting from HTMLCollection to Array
                    var items = Array.prototype.slice.call(childNode.children);
                    childComp.addItems(items);
                }
                // replace the tag (eg dy-checkbox) with the proper HTMLElement (eg 'div') in the dom
                _this.swapComponentForNode(childComp, parentNode, childNode);
            }
            else if (childNode.childNodes) {
                _this.createChildComponentsFromTags(childNode, paramsMap);
            }
        });
    };
    Component.prototype.createComponentFromElement = function (element, afterPreCreateCallback, paramsMap) {
        var key = element.nodeName;
        var componentParams = paramsMap ? paramsMap[element.getAttribute('ref')] : undefined;
        var ComponentClass = this.dyStackComponentsRegistry.getComponentClass(key);
        if (ComponentClass) {
            var newComponent = new ComponentClass(componentParams);
            this.createBean(newComponent, null, afterPreCreateCallback);
            return newComponent;
        }
        return null;
    };
    Component.prototype.copyAttributesFromNode = function (source, dest) {
        iterateNamedNodeMap(source.attributes, function (name, value) { return dest.setAttribute(name, value); });
    };
    Component.prototype.swapComponentForNode = function (newComponent, parentNode, childNode) {
        var eComponent = newComponent.getGui();
        parentNode.replaceChild(eComponent, childNode);
        parentNode.insertBefore(document.createComment(childNode.nodeName), eComponent);
        this.addDestroyFunc(this.destroyBean.bind(this, newComponent));
        this.swapInComponentForQuerySelectors(newComponent, childNode);
    };
    Component.prototype.swapInComponentForQuerySelectors = function (newComponent, childNode) {
        var thisNoType = this;
        this.iterateOverQuerySelectors(function (querySelector) {
            if (thisNoType[querySelector.attributeName] === childNode) {
                thisNoType[querySelector.attributeName] = newComponent;
            }
        });
    };
    Component.prototype.iterateOverQuerySelectors = function (action) {
        var thisPrototype = Object.getPrototypeOf(this);
        while (thisPrototype != null) {
            var metaData = thisPrototype.__dyComponentMetaData;
            var currentProtoName = getFunctionName(thisPrototype.constructor);
            if (metaData && metaData[currentProtoName] && metaData[currentProtoName].querySelectors) {
                forEach(metaData[currentProtoName].querySelectors, function (querySelector) { return action(querySelector); });
            }
            thisPrototype = Object.getPrototypeOf(thisPrototype);
        }
    };
    Component.prototype.setTemplate = function (template, paramsMap) {
        var eGui = loadTemplate(template);
        this.setTemplateFromElement(eGui, paramsMap);
    };
    Component.prototype.setTemplateFromElement = function (element, paramsMap) {
        this.eGui = element;
        this.eGui.__dyComponent = this;
        this.addAnnotatedGuiEventListeners();
        this.wireQuerySelectors();
        // context will not be available when user sets template in constructor
        if (!!this.getContext()) {
            this.createChildComponentsFromTags(this.getGui(), paramsMap);
        }
    };
    Component.prototype.createChildComponentsPreConstruct = function () {
        // ui exists if user sets template in constructor. when this happens, we have to wait for the context
        // to be autoWired first before we can create child components.
        if (!!this.getGui()) {
            this.createChildComponentsFromTags(this.getGui());
        }
    };
    Component.prototype.wireQuerySelectors = function () {
        var _this = this;
        if (!this.eGui) {
            return;
        }
        var thisNoType = this;
        this.iterateOverQuerySelectors(function (querySelector) {
            var resultOfQuery = _this.eGui.querySelector(querySelector.querySelector);
            if (resultOfQuery) {
                thisNoType[querySelector.attributeName] = resultOfQuery.__dyComponent || resultOfQuery;
            }
            else {
                // put debug msg in here if query selector fails???
            }
        });
    };
    Component.prototype.addAnnotatedGuiEventListeners = function () {
        var _this = this;
        this.removeAnnotatedGuiEventListeners();
        if (!this.eGui) {
            return;
        }
        var listenerMethods = this.getDyComponentMetaData('guiListenerMethods');
        if (!listenerMethods) {
            return;
        }
        if (!this.annotatedGuiListeners) {
            this.annotatedGuiListeners = [];
        }
        listenerMethods.forEach(function (meta) {
            var element = _this.getRefElement(meta.ref);
            if (!element) {
                return;
            }
            var listener = _this[meta.methodName].bind(_this);
            element.addEventListener(meta.eventName, listener);
            _this.annotatedGuiListeners.push({ eventName: meta.eventName, listener: listener, element: element });
        });
    };
    Component.prototype.addAnnotatedGridEventListeners = function () {
        var _this = this;
        var listenerMetas = this.getDyComponentMetaData('gridListenerMethods');
        if (!listenerMetas) {
            return;
        }
        listenerMetas.forEach(function (meta) {
            var listener = _this[meta.methodName].bind(_this);
            _this.addManagedListener(_this.eventService, meta.eventName, listener);
        });
    };
    Component.prototype.getDyComponentMetaData = function (key) {
        var res = [];
        var thisProto = Object.getPrototypeOf(this);
        while (thisProto != null) {
            var metaData = thisProto.__dyComponentMetaData;
            var currentProtoName = getFunctionName(thisProto.constructor);
            if (metaData && metaData[currentProtoName] && metaData[currentProtoName][key]) {
                res = res.concat(metaData[currentProtoName][key]);
            }
            thisProto = Object.getPrototypeOf(thisProto);
        }
        return res;
    };
    Component.prototype.removeAnnotatedGuiEventListeners = function () {
        if (!this.annotatedGuiListeners) {
            return;
        }
        forEach(this.annotatedGuiListeners, function (e) {
            e.element.removeEventListener(e.eventName, e.listener);
        });
        this.annotatedGuiListeners = [];
    };
    Component.prototype.getGui = function () {
        return this.eGui;
    };
    Component.prototype.getFocusableElement = function () {
        return this.eGui;
    };
    Component.prototype.setParentComponent = function (component) {
        this.parentComponent = component;
    };
    Component.prototype.getParentComponent = function () {
        return this.parentComponent;
    };
    // this method is for older code, that wants to provide the gui element,
    // it is not intended for this to be in dy-Stack
    Component.prototype.setGui = function (eGui) {
        this.eGui = eGui;
    };
    Component.prototype.queryForHtmlElement = function (cssSelector) {
        return this.eGui.querySelector(cssSelector);
    };
    Component.prototype.queryForHtmlInputElement = function (cssSelector) {
        return this.eGui.querySelector(cssSelector);
    };
    Component.prototype.appendChild = function (newChild, container) {
        if (!container) {
            container = this.eGui;
        }
        if (newChild == null) {
            return;
        }
        if (isNodeOrElement(newChild)) {
            container.appendChild(newChild);
        }
        else {
            var childComponent = newChild;
            container.appendChild(childComponent.getGui());
            this.addDestroyFunc(this.destroyBean.bind(this, childComponent));
        }
    };
    Component.prototype.isDisplayed = function () {
        return this.displayed;
    };
    Component.prototype.setVisible = function (visible) {
        if (visible !== this.visible) {
            this.visible = visible;
            setVisible(this.eGui, visible);
        }
    };
    Component.prototype.setDisplayed = function (displayed) {
        if (displayed !== this.displayed) {
            this.displayed = displayed;
            setDisplayed(this.eGui, displayed);
            var event_1 = {
                type: Component.EVENT_DISPLAYED_CHANGED,
                visible: this.displayed
            };
            this.dispatchEvent(event_1);
        }
    };
    Component.prototype.destroy = function () {
        this.removeAnnotatedGuiEventListeners();
        if (this.tooltipFeature) {
            this.tooltipFeature = this.destroyBean(this.tooltipFeature);
        }
        _super.prototype.destroy.call(this);
    };
    Component.prototype.addGuiEventListener = function (event, listener) {
        var _this = this;
        this.eGui.addEventListener(event, listener);
        this.addDestroyFunc(function () { return _this.eGui.removeEventListener(event, listener); });
    };
    Component.prototype.addCssClass = function (className) {
        var updateNeeded = this.cssClassStates[className] !== true;
        if (updateNeeded) {
            addCssClass(this.eGui, className);
            this.cssClassStates[className] = true;
        }
    };
    Component.prototype.removeCssClass = function (className) {
        var updateNeeded = this.cssClassStates[className] !== false;
        if (updateNeeded) {
            removeCssClass(this.eGui, className);
            this.cssClassStates[className] = false;
        }
    };
    Component.prototype.addOrRemoveCssClass = function (className, addOrRemove) {
        var updateNeeded = this.cssClassStates[className] !== addOrRemove;
        if (updateNeeded) {
            addOrRemoveCssClass(this.eGui, className, addOrRemove);
            this.cssClassStates[className] = addOrRemove;
        }
    };
    Component.prototype.getAttribute = function (key) {
        var eGui = this.eGui;
        return eGui ? eGui.getAttribute(key) : null;
    };
    Component.prototype.getRefElement = function (refName) {
        return this.queryForHtmlElement("[ref=\"" + refName + "\"]");
    };
    Component.EVENT_DISPLAYED_CHANGED = 'displayedChanged';
    __decorate([
        Autowired('dyStackComponentsRegistry')
    ], Component.prototype, "dyStackComponentsRegistry", void 0);
    __decorate([
        PreConstruct
    ], Component.prototype, "preConstructOnComponent", null);
    __decorate([
        PreConstruct
    ], Component.prototype, "createChildComponentsPreConstruct", null);
    __decorate([
        PostConstruct
    ], Component.prototype, "addAnnotatedGridEventListeners", null);
    return Component;
}(BeanStub));
export { Component };
