"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.visitAll = exports.TemplateDefinition = void 0;
const bound_text_1 = require("./bound-text");
const content_1 = require("./content");
const element_1 = require("./element");
const template_1 = require("./template");
const text_1 = require("./text");
class TemplateDefinition {
    constructor(nodes, componentContext) {
        this.nodes = nodes;
        this.componentContext = componentContext;
        this.templateDefinitionMap = new Map();
        this.list = [];
        this.declIndex = 0;
        this.astVisitor = new CustomAstVisitor(() => {
            this.declIndex++;
        });
    }
    init() { }
    visit(node) { }
    visitElement(element) {
        const nodeIndex = this.declIndex++;
        let componentMeta;
        let directiveMeta;
        const result = this.componentContext.matchDirective(element);
        const directiveMetaList = result.filter((item) => {
            if (item.isComponent) {
                componentMeta = item;
            }
            return !item.isComponent;
        });
        if (directiveMetaList.length) {
            directiveMeta = {
                isComponent: false,
                listeners: directiveMetaList.map((item) => item.listeners).flat(),
                properties: directiveMetaList.map((item) => item.properties).flat(),
                inputs: directiveMetaList.map((item) => item.inputs).flat(),
                outputs: directiveMetaList.map((item) => item.outputs).flat(),
            };
        }
        const instance = new element_1.ParsedNgElement(element, this.parentNode, componentMeta, nodeIndex, directiveMeta);
        if (this.parentNode) {
            this.parentNode.appendNgNodeChild(instance);
        }
        element.inputs.forEach((item) => {
            item.value.visit(this.astVisitor);
        });
        const oldParent = this.parentNode;
        this.parentNode = instance;
        this.prepareRefsArray(element.references);
        visitAll(this, element.children);
        this.parentNode = oldParent;
        if (!this.parentNode) {
            this.list.push(instance);
        }
    }
    visitTemplate(template) {
        const nodeIndex = this.declIndex++;
        const templateInstance = new template_1.ParsedNgTemplate(template, this.parentNode, nodeIndex);
        if (this.parentNode) {
            this.parentNode.appendNgNodeChild(templateInstance);
        }
        this.prepareRefsArray(template.references);
        template.templateAttrs.forEach((item) => {
            if (typeof item.value !== 'string') {
                item.value.visit(this.astVisitor);
            }
        });
        template.inputs.forEach((item) => {
            item.value.visit(this.astVisitor);
        });
        const instance = new TemplateDefinition(template.children, this.componentContext);
        instance.parentNode = templateInstance;
        this.templateDefinitionMap.set(template, instance);
        instance.run();
        if (!this.parentNode) {
            this.list.push(templateInstance);
        }
    }
    visitContent(content) {
        const nodeIndex = this.declIndex++;
        const instance = new content_1.ParsedNgContent(content, this.parentNode, nodeIndex);
        if (this.parentNode) {
            this.parentNode.appendNgNodeChild(instance);
        }
        else {
            this.list.push(instance);
        }
    }
    visitVariable(variable) { }
    visitReference(reference) { }
    visitTextAttribute(attribute) { }
    visitBoundAttribute(attribute) { }
    visitBoundEvent(attribute) { }
    visitText(text) {
        const nodeIndex = this.declIndex++;
        const instance = new text_1.ParsedNgText(text, this.parentNode, nodeIndex);
        if (this.parentNode) {
            this.parentNode.appendNgNodeChild(instance);
        }
        else {
            this.list.push(instance);
        }
    }
    visitBoundText(text) {
        const nodeIndex = this.declIndex++;
        text.value.visit(this.astVisitor);
        const instance = new bound_text_1.ParsedNgBoundText(text, this.parentNode, nodeIndex);
        if (this.parentNode) {
            this.parentNode.appendNgNodeChild(instance);
        }
        else {
            this.list.push(instance);
        }
    }
    visitIcu(icu) { }
    run() {
        visitAll(this, this.nodes);
        return this.list;
    }
    prepareRefsArray(refs) {
        if (!refs || !refs.length) {
            return;
        }
        refs.forEach((item) => {
            this.declIndex++;
        });
    }
}
exports.TemplateDefinition = TemplateDefinition;
function visitAll(visitor, nodes) {
    for (const node of nodes) {
        node.visit(visitor);
    }
}
exports.visitAll = visitAll;
class CustomAstVisitor {
    constructor(pipeCallback) {
        this.pipeCallback = pipeCallback;
    }
    visitCall(ast) {
        ast.receiver.visit(this);
        this.visitAll(ast.args);
    }
    visitSafeKeyedRead(ast) {
        ast.receiver.visit(this);
        ast.key.visit(this);
    }
    visitImplicitReceiver(ast) { }
    visitInterpolation(ast) {
        this.visitAll(ast.expressions);
    }
    visitKeyedRead(ast) {
        ast.receiver.visit(this);
        ast.key.visit(this);
    }
    visitKeyedWrite(ast) {
        ast.receiver.visit(this);
        ast.key.visit(this);
        ast.value.visit(this);
    }
    visitLiteralArray(ast) {
        this.visitAll(ast.expressions);
    }
    visitLiteralMap(ast) {
        this.visitAll(ast.values);
    }
    visitLiteralPrimitive(ast) { }
    visitPipe(ast) {
        this.pipeCallback();
    }
    visitPrefixNot(ast) {
        ast.expression.visit(this);
    }
    visitNonNullAssert(ast) {
        ast.expression.visit(this);
    }
    visitPropertyRead(ast) {
        ast.receiver.visit(this);
    }
    visitPropertyWrite(ast) { }
    visitQuote(ast) { }
    visitSafePropertyRead(ast) { }
    visitBinary(ast) {
        ast.left.visit(this);
        ast.right.visit(this);
    }
    visitChain(ast) {
        this.visitAll(ast.expressions);
    }
    visitConditional(ast) {
        ast.condition.visit(this);
        ast.trueExp.visit(this);
        ast.falseExp.visit(this);
    }
    visit(ast) { }
    visitAll(asts) {
        for (let i = 0; i < asts.length; ++i) {
            const original = asts[i];
            original.visit(this);
        }
    }
}
