import { Logger as BaseLogger } from "./Logger";
const Logger = BaseLogger.createSubLogger("Updater");
/**
 * Updates articles inside of the gfx scene
 *
 * A single generation consists of either positionally unrelated elements (root elements to be specific) or an elements children + right neighbor
 * Articles of one generation will be updated in parallel
 *
 * @param {UpdateSceneParams} params
 * @returns {Promise<void>} A list of all articles which have been added to the scene
 */
export const updateArticles = async ({ snapshot, articles, loadGeometry, executeParentActions, executeNeighborActions, deleteArticleAndChildren, updateArticlePosition, }) => {
    const promises = [];
    const updateTree = (snapshot, comIds, level, parentPromise) => {
        for (const comId of comIds) {
            // every article that has been changed requires a gfx update regardless of later changes
            let requiresGfxUpdate = articles.indexOf(comId) > -1;
            // the snapshotted original node
            const node = snapshot.getNode(comId);
            const updatePromise = parentPromise
                .then(async () => {
                // whenever the parent has been updated
                // get the connection info adapted to the post parent update scene
                const postParentUpdateConnectionInfo = snapshot.getNewConnectionInfo(comId);
                // check for a valid connection info and a level of larger than 0
                if (level > 0 &&
                    postParentUpdateConnectionInfo !== "none" &&
                    node.snapPoint.type === "family") {
                    // every article beyond level 0 has to have some kind of relation with the parent. if a connection is missing -> the parent has been deleted or the point is invalid
                    if (postParentUpdateConnectionInfo === "missing") {
                        Logger.error(`Did not find previous attach point for ${comId}`);
                        return deleteArticleAndChildren(comId);
                    }
                }
                // update this article using parent actions
                if (typeof postParentUpdateConnectionInfo === "object" &&
                    postParentUpdateConnectionInfo.parentPoint
                        .componentId !== undefined) {
                    const didChange = await executeParentActions(postParentUpdateConnectionInfo.parentPoint
                        .componentId, comId);
                    // if the configuration updated as a result of the action execution -> the gfx has to be updateed regardless of initial value
                    requiresGfxUpdate = requiresGfxUpdate || didChange;
                }
                // update ths article using neighbor actions
                if (typeof postParentUpdateConnectionInfo === "object") {
                    const didChange = await executeNeighborActions(comId);
                    requiresGfxUpdate = requiresGfxUpdate || didChange;
                }
                let postUpdateConnectionInfo = postParentUpdateConnectionInfo;
                // update the geometry if neccessary
                if (requiresGfxUpdate) {
                    try {
                        await loadGeometry(comId);
                        postUpdateConnectionInfo = snapshot.getNewConnectionInfo(comId);
                    }
                    catch (err) {
                        throw err;
                    }
                }
                // if there was a connection and a previous gfx representation -> update the article's position according to the snap point
                if (typeof postUpdateConnectionInfo === "object") {
                    updateArticlePosition(postUpdateConnectionInfo.parentComId, postUpdateConnectionInfo.ownComId, postUpdateConnectionInfo.parentPoint, postUpdateConnectionInfo.ownPoint);
                }
            })
                .catch(err => Logger.error(err));
            // add this promise to the list of all promises
            promises.push(updatePromise);
            // if an element has children -> update the children
            if (node && node.children && node.children.length > 0) {
                updateTree(snapshot, node.children, level + 1, updatePromise);
            }
        }
    };
    const entryRoots = snapshot.getRootElements();
    // start updating the tree starting with the root elements
    updateTree(snapshot, entryRoots, 0, Promise.resolve());
    await Promise.all(promises);
};
