"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.appendChild = appendChild;
exports.appendChildren = appendChildren;
exports.instanceChild = instanceChild;
exports.pushChild = pushChild;
exports.insertChild = insertChild;
exports.hasChild = hasChild;
exports.pullChild = pullChild;
exports.removeChild = removeChild;
exports.refRoot = refRoot;
exports.refChild = refChild;
exports.refChildren = refChildren;
exports.refSlot = refSlot;
exports.registerParentRoot = registerParentRoot;
exports.unregisterParentRoot = unregisterParentRoot;
exports.reorderRoot = reorderRoot;
exports.reorderParentRoot = reorderParentRoot;
exports.unregisterRoot = unregisterRoot;
exports.registerRoot = registerRoot;
exports.appendParentChild = appendParentChild;
exports.removeParentChild = removeParentChild;
exports.animate = animate;
exports.cancelAnimation = cancelAnimation;
exports.stopPropagation = stopPropagation;
exports.attachText = attachText;
exports.attachDropTarget = attachDropTarget;
exports.detach = detach;
const ChildOutOfBoundError_1 = require("../exception/ChildOutOfBoundError");
const evaluateDataValue_1 = require("../spec/evaluateDataValue");
const globalUrl_1 = require("../spec/globalUrl");
const resolveDataValue_1 = require("../spec/resolveDataValue");
const array_1 = require("../util/array");
function _appendChild(component, children, Class) {
    return pushChild(component, children, Class);
}
function appendChild(component, children, Class, emit = true) {
    const [i, child] = _appendChild(component, children, Class);
    const { __bundle } = child.constructor;
    emit && component.emit('append_child', __bundle, child, []);
    return i;
}
function appendChildren(component, children, Classes) {
    for (const Class of Classes) {
        _appendChild(component, children, Class);
    }
    const bundles = Classes.map((c) => c.__bundle);
    component.emit('append_children', bundles, []);
    return children.length;
}
function instanceChild(component, Class) {
    const system = component.__system;
    const unit = new Class(system);
    const { input = {}, output = {}, memory = { input: {}, output: {}, memory: {} }, } = Class.__bundle.unit;
    for (const name in input) {
        const { data } = input[name];
        if (data !== undefined) {
            const dataRef = (0, evaluateDataValue_1.evaluateDataValue)(data, system.specs, system.classes);
            const data_ = (0, resolveDataValue_1.resolveDataRef)(dataRef, system.specs, system.classes);
            unit.pushInput(name, data_);
        }
    }
    // unit.restore(memory)
    if (component.paused() && !unit.paused()) {
        unit.pause();
    }
    else if (!component.paused() && unit.paused()) {
        unit.play();
    }
    return unit;
}
function pushChild(component, children, Class) {
    const child = instanceChild(component, Class);
    children.push(child);
    const i = children.length - 1;
    return [i, child];
}
function insertChild(component, children, Class, at) {
    const unit = instanceChild(component, Class);
    (0, array_1.insert)(children, unit, at);
    const { __bundle: bundle } = Class;
    component.emit('insert_child', bundle, at, []);
}
function hasChild(element, children, at) {
    const has = at >= 0 && at < children.length;
    return has;
}
function pullChild(element, children, at) {
    const has = hasChild(element, children, at);
    if (!has) {
        throw new ChildOutOfBoundError_1.ChildOutOfBound();
    }
    const [unit] = children.splice(at, 1);
    return unit;
}
function removeChild(element, children, at, emit = true) {
    const child = pullChild(element, children, at);
    emit && element.emit('remove_child', at, []);
    emit && element.emit(`remove_child_at_${at}`, at);
    return child;
}
function refRoot(element, root, at) {
    return root[at];
}
function refChild(element, children, at) {
    return children[at];
}
function refChildren(element, children) {
    return children;
}
function refSlot(element, slotName, slot) {
    const subComponentId = slot[slotName];
    if (subComponentId) {
        return element.getSubComponent(subComponentId);
    }
    else {
        return element;
    }
}
function registerParentRoot(component, parentRoot, subComponentId, child, slotName, at = undefined, emit = true) {
    if (at === undefined) {
        (0, array_1.push)(parentRoot, child);
    }
    else {
        (0, array_1.insert)(parentRoot, child, at);
    }
    const slot = component.refSlot(slotName);
    slot.appendParentChild(component, 'default');
    emit &&
        component.emit('register_parent_root', child, subComponentId, slotName);
}
function unregisterParentRoot(component, parentRoot, subComponentId, child, emit) {
    const at = parentRoot.indexOf(child);
    parentRoot.splice(at, 1);
    emit && component.emit('unregister_parent_root', child, subComponentId);
}
function reorderRoot(component, root, child, to, emit) {
    const currentIndex = root.indexOf(child);
    if (currentIndex === -1) {
        throw new Error('root not found');
    }
    root.splice(currentIndex, 1);
    (0, array_1.insert)(root, child, to);
    emit && component.emit('reorder_root', component, to);
}
function reorderParentRoot(component, parentRoot, child, to, emit) {
    const currentIndex = parentRoot.indexOf(child);
    if (currentIndex === -1) {
        throw new Error('root not found');
    }
    parentRoot.splice(currentIndex, 1);
    (0, array_1.insert)(parentRoot, child, to);
    emit && component.emit('reorder_parent_root', component, to);
}
function unregisterRoot(component, root, child, subComponentId, emit) {
    const at = root.indexOf(child);
    root.splice(at, 1);
    emit && component.emit('unregister_root', child, subComponentId);
}
function registerRoot(component, root, child, subComponentId, emit) {
    root.push(child);
    emit && component.emit('register_root', child, subComponentId);
}
function appendParentChild(component, parentChild, child, slotName, emit) {
    const slot = component.refSlot(slotName);
    if (component === slot) {
        parentChild.push(child);
        emit && component.emit('append_parent_child', component, slotName);
    }
    else {
        slot.appendParentChild(child, 'default', emit);
    }
}
function removeParentChild(component, parentRoot, child, emit) {
    const at = parentRoot.indexOf(child);
    parentRoot.splice(at, 1);
    emit && component.emit('remove_parent_child', component);
}
function animate(component, animations, keyframes, opt) {
    animations.push({ keyframes, opt });
    component.emit('call', {
        method: 'animate',
        data: [keyframes, opt],
    });
}
function cancelAnimation(component, animations, id) {
    const i = animations.findIndex((animation) => {
        return animation.opt.id === id;
    });
    animations.splice(i, 1);
    component.emit('call', {
        method: 'cancelAnimation',
        data: [id],
    });
}
function stopPropagation(component, stopPropagationCount, name) {
    stopPropagationCount[name] = stopPropagationCount[name] ?? 0;
    stopPropagationCount[name]++;
    if (stopPropagationCount[name] === 1) {
        component.emit('call', { method: 'stopPropagation', data: [name] });
    }
    return () => {
        stopPropagationCount[name]--;
        if (stopPropagationCount[name] === 0) {
            delete stopPropagationCount[name];
            component.emit('call', { method: 'cancelStopPropagation', data: [name] });
        }
    };
}
function attachText(component, attachTextArray, type, text) {
    const entry = [type, text];
    (0, array_1.push)(attachTextArray, entry);
    component.emit('call', { method: 'attachText', data: [type, text] });
    return () => {
        (0, array_1.remove)(attachTextArray, entry);
        component.emit('call', { method: 'detachText', data: [type] });
    };
}
function attachDropTarget(component, attachTextDropTargetArray) {
    const entry = [];
    (0, array_1.push)(attachTextDropTargetArray, entry);
    if (attachTextDropTargetArray)
        component.emit('call', { method: 'attachDropTarget', data: [] });
    return () => {
        (0, array_1.remove)(attachTextDropTargetArray, entry);
        if (attachTextDropTargetArray.length === 0) {
            component.emit('call', { method: 'detachDropTarget', data: [] });
        }
    };
}
function detach(component, detachTo, host, opt) {
    const hostUrl = (0, globalUrl_1.globalUrl)(host.__global_id);
    detachTo.current = { host: hostUrl, opt };
    component.emit('call', { method: 'detach', data: [hostUrl, opt] });
    return () => {
        component.emit('call', {
            method: 'attach',
            data: [opt],
        });
    };
}
//# sourceMappingURL=method.js.map