/**
 * @license
 * Copyright Google LLC All Rights Reserved.
 *
 * Use of this source code is governed by an MIT-style license that can be
 * found in the LICENSE file at https://angular.io/license
 */
import { validateMatchingNode, validateNodeExists } from '../../hydration/error_handling';
import { locateNextRNode, siblingAfter } from '../../hydration/node_lookup_utils';
import { getNgContainerSize, markRNodeAsClaimedByHydration, setSegmentHead } from '../../hydration/utils';
import { assertEqual, assertIndexInRange, assertNumber } from '../../util/assert';
import { assertHasParent } from '../assert';
import { attachPatchData } from '../context_discovery';
import { registerPostOrderHooks } from '../hooks';
import { isContentQueryHost, isDirectiveHost } from '../interfaces/type_checks';
import { HEADER_OFFSET, HYDRATION, RENDERER } from '../interfaces/view';
import { assertTNodeType } from '../node_assert';
import { appendChild, createCommentNode } from '../node_manipulation';
import { getBindingIndex, getCurrentTNode, getLView, getTView, isCurrentTNodeParent, isInSkipHydrationBlock, lastNodeWasCreated, setCurrentTNode, setCurrentTNodeAsNotParent, wasLastNodeCreated } from '../state';
import { computeStaticStyling } from '../styling/static_styling';
import { getConstant } from '../util/view_utils';
import { createDirectivesInstances, executeContentQueries, getOrCreateTNode, resolveDirectives, saveResolvedLocalsInData } from './shared';
function elementContainerStartFirstCreatePass(index, tView, lView, attrsIndex, localRefsIndex) {
    ngDevMode && ngDevMode.firstCreatePass++;
    const tViewConsts = tView.consts;
    const attrs = getConstant(tViewConsts, attrsIndex);
    const tNode = getOrCreateTNode(tView, index, 8 /* TNodeType.ElementContainer */, 'ng-container', attrs);
    // While ng-container doesn't necessarily support styling, we use the style context to identify
    // and execute directives on the ng-container.
    if (attrs !== null) {
        computeStaticStyling(tNode, attrs, true);
    }
    const localRefs = getConstant(tViewConsts, localRefsIndex);
    resolveDirectives(tView, lView, tNode, localRefs);
    if (tView.queries !== null) {
        tView.queries.elementStart(tView, tNode);
    }
    return tNode;
}
/**
 * Creates a logical container for other nodes (<ng-container>) backed by a comment node in the DOM.
 * The instruction must later be followed by `elementContainerEnd()` call.
 *
 * @param index Index of the element in the LView array
 * @param attrsIndex Index of the container attributes in the `consts` array.
 * @param localRefsIndex Index of the container's local references in the `consts` array.
 * @returns This function returns itself so that it may be chained.
 *
 * Even if this instruction accepts a set of attributes no actual attribute values are propagated to
 * the DOM (as a comment node can't have attributes). Attributes are here only for directive
 * matching purposes and setting initial inputs of directives.
 *
 * @codeGenApi
 */
export function ɵɵelementContainerStart(index, attrsIndex, localRefsIndex) {
    const lView = getLView();
    const tView = getTView();
    const adjustedIndex = index + HEADER_OFFSET;
    ngDevMode && assertIndexInRange(lView, adjustedIndex);
    ngDevMode &&
        assertEqual(getBindingIndex(), tView.bindingStartIndex, 'element containers should be created before any bindings');
    const tNode = tView.firstCreatePass ?
        elementContainerStartFirstCreatePass(adjustedIndex, tView, lView, attrsIndex, localRefsIndex) :
        tView.data[adjustedIndex];
    setCurrentTNode(tNode, true);
    const comment = _locateOrCreateElementContainerNode(tView, lView, tNode, index);
    lView[adjustedIndex] = comment;
    if (wasLastNodeCreated()) {
        appendChild(tView, lView, comment, tNode);
    }
    attachPatchData(comment, lView);
    if (isDirectiveHost(tNode)) {
        createDirectivesInstances(tView, lView, tNode);
        executeContentQueries(tView, tNode, lView);
    }
    if (localRefsIndex != null) {
        saveResolvedLocalsInData(lView, tNode);
    }
    return ɵɵelementContainerStart;
}
/**
 * Mark the end of the <ng-container>.
 * @returns This function returns itself so that it may be chained.
 *
 * @codeGenApi
 */
export function ɵɵelementContainerEnd() {
    let currentTNode = getCurrentTNode();
    const tView = getTView();
    if (isCurrentTNodeParent()) {
        setCurrentTNodeAsNotParent();
    }
    else {
        ngDevMode && assertHasParent(currentTNode);
        currentTNode = currentTNode.parent;
        setCurrentTNode(currentTNode, false);
    }
    ngDevMode && assertTNodeType(currentTNode, 8 /* TNodeType.ElementContainer */);
    if (tView.firstCreatePass) {
        registerPostOrderHooks(tView, currentTNode);
        if (isContentQueryHost(currentTNode)) {
            tView.queries.elementEnd(currentTNode);
        }
    }
    return ɵɵelementContainerEnd;
}
/**
 * Creates an empty logical container using {@link elementContainerStart}
 * and {@link elementContainerEnd}
 *
 * @param index Index of the element in the LView array
 * @param attrsIndex Index of the container attributes in the `consts` array.
 * @param localRefsIndex Index of the container's local references in the `consts` array.
 * @returns This function returns itself so that it may be chained.
 *
 * @codeGenApi
 */
export function ɵɵelementContainer(index, attrsIndex, localRefsIndex) {
    ɵɵelementContainerStart(index, attrsIndex, localRefsIndex);
    ɵɵelementContainerEnd();
    return ɵɵelementContainer;
}
let _locateOrCreateElementContainerNode = (tView, lView, tNode, index) => {
    lastNodeWasCreated(true);
    return createCommentNode(lView[RENDERER], ngDevMode ? 'ng-container' : '');
};
/**
 * Enables hydration code path (to lookup existing elements in DOM)
 * in addition to the regular creation mode of comment nodes that
 * represent <ng-container>'s anchor.
 */
function locateOrCreateElementContainerNode(tView, lView, tNode, index) {
    let comment;
    const hydrationInfo = lView[HYDRATION];
    const isNodeCreationMode = !hydrationInfo || isInSkipHydrationBlock();
    lastNodeWasCreated(isNodeCreationMode);
    // Regular creation mode.
    if (isNodeCreationMode) {
        return createCommentNode(lView[RENDERER], ngDevMode ? 'ng-container' : '');
    }
    // Hydration mode, looking up existing elements in DOM.
    const currentRNode = locateNextRNode(hydrationInfo, tView, lView, tNode);
    ngDevMode && validateNodeExists(currentRNode, lView, tNode);
    const ngContainerSize = getNgContainerSize(hydrationInfo, index);
    ngDevMode &&
        assertNumber(ngContainerSize, 'Unexpected state: hydrating an <ng-container>, ' +
            'but no hydration info is available.');
    setSegmentHead(hydrationInfo, index, currentRNode);
    comment = siblingAfter(ngContainerSize, currentRNode);
    if (ngDevMode) {
        validateMatchingNode(comment, Node.COMMENT_NODE, null, lView, tNode);
        markRNodeAsClaimedByHydration(comment);
    }
    return comment;
}
export function enableLocateOrCreateElementContainerNodeImpl() {
    _locateOrCreateElementContainerNode = locateOrCreateElementContainerNode;
}
//# sourceMappingURL=data:application/json;base64,[encoded data, 16880 characters]