(function (factory) {
    if (typeof module === "object" && typeof module.exports === "object") {
        var v = factory(require, exports);
        if (v !== undefined) module.exports = v;
    }
    else if (typeof define === "function" && define.amd) {
        define(["require", "exports", "../web/core/AtomUI", "./AtomBinder"], factory);
    }
})(function (require, exports) {
    "use strict";
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.AtomBridge = exports.AtomElementBridge = exports.BaseElementBridge = void 0;
    const AtomUI_1 = require("../web/core/AtomUI");
    const AtomBinder_1 = require("./AtomBinder");
    class BaseElementBridge {
        refreshInherited(target, name, fieldName) {
            AtomBinder_1.AtomBinder.refreshValue(target, name);
            if (!fieldName) {
                fieldName = "m" + name[0].toUpperCase() + name.substr(1);
            }
            if (!target.element) {
                return;
            }
            this.visitDescendents(target.element, (e, ac) => {
                if (ac) {
                    if (ac[fieldName] === undefined) {
                        this.refreshInherited(ac, name, fieldName);
                    }
                    return false;
                }
                return true;
            });
        }
        createNode(target, node, 
        // tslint:disable-next-line: ban-types
        binder, 
        // tslint:disable-next-line: ban-types
        xNodeClass, 
        // tslint:disable-next-line: ban-types
        creator) {
            throw new Error("Method not implemented.");
        }
    }
    exports.BaseElementBridge = BaseElementBridge;
    class AtomElementBridge extends BaseElementBridge {
        addEventHandler(element, name, handler, capture) {
            element.addEventListener(name, handler, capture);
            return {
                dispose: () => {
                    element.removeEventListener(name, handler, capture);
                }
            };
        }
        atomParent(element, climbUp = true) {
            const eAny = element;
            if (eAny.atomControl) {
                return eAny.atomControl;
            }
            if (!climbUp) {
                return null;
            }
            if (!element.parentNode) {
                return null;
            }
            return this.atomParent(this.elementParent(element));
        }
        elementParent(element) {
            const eAny = element;
            const lp = eAny._logicalParent;
            if (lp) {
                return lp;
            }
            return element.parentElement;
        }
        templateParent(element) {
            if (!element) {
                return null;
            }
            const eAny = element;
            if (eAny._templateParent) {
                return this.atomParent(element);
            }
            const parent = this.elementParent(element);
            if (!parent) {
                return null;
            }
            return this.templateParent(parent);
        }
        visitDescendents(element, action) {
            const en = new AtomUI_1.ChildEnumerator(element);
            while (en.next()) {
                const iterator = en.current;
                const eAny = iterator;
                const ac = eAny ? eAny.atomControl : undefined;
                if (!action(iterator, ac)) {
                    continue;
                }
                this.visitDescendents(iterator, action);
            }
        }
        dispose(element) {
            const eAny = element;
            eAny.atomControl = undefined;
            eAny.innerHTML = "";
            delete eAny.atomControl;
        }
        appendChild(parent, child) {
            parent.appendChild(child);
        }
        setValue(element, name, value) {
            element[name] = value;
        }
        getValue(element, name) {
            return element[name];
        }
        watchProperty(element, name, events, f) {
            if (events.indexOf("change") === -1) {
                events.push("change");
            }
            const l = (e) => {
                const e1 = element;
                const v = e1.type === "checkbox" ? e1.checked : e1.value;
                f(v);
            };
            for (const iterator of events) {
                element.addEventListener(iterator, l, false);
            }
            return {
                dispose: () => {
                    for (const iterator of events) {
                        element.removeEventListener(iterator, l, false);
                    }
                }
            };
        }
        attachControl(element, control) {
            element.atomControl = control;
        }
        create(type) {
            return document.createElement(type);
        }
        loadContent(element, text) {
            throw new Error("Not supported");
        }
        findChild(element, name) {
            throw new Error("Not supported");
        }
        close(element, success, error) {
            throw new Error("Not supported");
        }
        toTemplate(element, creator) {
            const templateNode = element;
            const name = templateNode.name;
            if (typeof name === "string") {
                element = ((bx, n) => class extends bx {
                    create() {
                        this.render(n);
                    }
                })(creator, templateNode.children[0]);
            }
            else {
                element = ((base, n) => class extends base {
                    create() {
                        this.render(n);
                    }
                })(name, templateNode.children[0]);
            }
            return element;
        }
        createNode(target, node, 
        // tslint:disable-next-line: ban-types
        binder, 
        // tslint:disable-next-line: ban-types
        xNodeClass, 
        // tslint:disable-next-line: ban-types
        creator) {
            let parent = null;
            const app = target.app;
            let e = null;
            const nn = node.attributes ? node.attributes.for : undefined;
            if (typeof node.name === "string") {
                // it is simple node..
                e = document.createElement(node.name);
                parent = e;
                if (nn) {
                    delete node.attributes.for;
                }
            }
            else {
                if (nn) {
                    target = new node.name(app, document.createElement(nn));
                    delete node.attributes.for;
                }
                target = new node.name(app);
                e = target.element;
                parent = target;
                // target.append(child);
                // const firstChild = node.children ? node.children[0] : null;
                // if (firstChild) {
                // 	const n = this.createNode(child, firstChild, binder, xNodeClass, creator);
                // 	child.append(n.atomControl || n);
                // }
                // return child.element;
            }
            const a = node.attributes;
            if (a) {
                for (const key in a) {
                    if (a.hasOwnProperty(key)) {
                        let element = a[key];
                        if (element instanceof binder) {
                            if (/^event/.test(key)) {
                                let ev = key.substr(5);
                                if (ev.startsWith("-")) {
                                    ev = ev.split("-").map((s) => s[0].toLowerCase() + s.substr(1)).join("");
                                }
                                else {
                                    ev = ev[0].toLowerCase() + ev.substr(1);
                                }
                                element.setupFunction(ev, element, target, e);
                            }
                            else {
                                element.setupFunction(key, element, target, e);
                            }
                        }
                        else {
                            // this is template...
                            if (element instanceof xNodeClass) {
                                element = this.toTemplate(element, creator);
                            }
                            target.setLocalValue(e, key, element);
                        }
                    }
                }
            }
            const children = node.children;
            if (children) {
                for (const iterator of children) {
                    if (typeof iterator === "string") {
                        e.appendChild(document.createTextNode(iterator));
                        continue;
                    }
                    const t = iterator.attributes ? iterator.attributes.template : null;
                    if (t) {
                        const tx = this.toTemplate(iterator, creator);
                        target[t] = tx;
                        continue;
                    }
                    if (typeof iterator.name === "string") {
                        e.appendChild(this.createNode(target, iterator, binder, xNodeClass, creator));
                        continue;
                    }
                    const child = this.createNode(target, iterator, binder, xNodeClass, creator);
                    if (parent.element && parent.element.atomControl === parent) {
                        parent.append(child.atomControl || child);
                    }
                    else {
                        parent.appendChild(child);
                    }
                }
            }
            return e;
        }
    }
    exports.AtomElementBridge = AtomElementBridge;
    class AtomBridge {
        static createNode(iterator, app) {
            if (typeof iterator.name === "string" || iterator.name.factory) {
                return { element: AtomBridge.instance.create(iterator.name, iterator, app) };
            }
            const fx = iterator.attributes ? iterator.attributes.for : undefined;
            const c = new iterator.name(app, fx ? AtomBridge.instance.create(fx, iterator, app) : undefined);
            return { element: c.element, control: c };
        }
        static toTemplate(app, n, creator) {
            if (n.isTemplate) {
                const t = AtomBridge.toTemplate(app, n.children[0], creator);
                return AtomBridge.instance.create(n.name.toString(), t, app);
            }
            const bridge = AtomBridge.instance;
            let fx;
            let en;
            if (typeof n.name === "function") {
                fx = n.name;
                en = (n.attributes && n.attributes.for) ? n.attributes.for : undefined;
            }
            else {
                fx = bridge.controlFactory;
                en = n.name;
            }
            return class Template extends fx {
                constructor(a, e1) {
                    super(a || app, e1 || (en ? bridge.create(en, null, app) : undefined));
                    // tslint:disable-next-line: variable-name
                    this._creator = fx;
                }
                create() {
                    super.create();
                    this.render(n, null, creator);
                }
            };
        }
        static refreshInherited(target, name, fieldName) {
            if (AtomBridge.instance.refreshInherited) {
                AtomBridge.instance.refreshInherited(target, name, fieldName);
                return;
            }
            AtomBinder_1.AtomBinder.refreshValue(target, name);
            if (!fieldName) {
                fieldName = "m" + name[0].toUpperCase() + name.substr(1);
            }
            if (!target.element) {
                return;
            }
            AtomBridge.instance.visitDescendents(target.element, (e, ac) => {
                if (ac) {
                    if (ac[fieldName] === undefined) {
                        AtomBridge.refreshInherited(ac, name, fieldName);
                    }
                    return false;
                }
                return true;
            });
        }
    }
    exports.AtomBridge = AtomBridge;
    const globalNS = (typeof window !== "undefined" ? window : global);
    globalNS.AtomBridge = AtomBridge;
    if (typeof window !== "undefined") {
        AtomBridge.instance = new AtomElementBridge();
        AtomBridge.platform = "web";
    }
});
//# sourceMappingURL=AtomBridge.js.map