"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.findRoot = exports.refreshParent = exports.setHeapNode = exports.addHeapNode = exports.removeHeapNode = exports.readHeap = exports.parentHeap = exports.toArray = exports.traverseHeap = void 0;
function traverseHeap(heap, callback) {
    const { value, children } = heap;
    callback(value);
    for (const child of children) {
        traverseHeap(child, callback);
    }
}
exports.traverseHeap = traverseHeap;
function toArray(heap) {
    const array = [];
    traverseHeap(heap, (value) => {
        array.push(value);
    });
    return array;
}
exports.toArray = toArray;
function parentHeap(heap, parent = null) {
    const { value, children } = heap;
    const _children = [];
    const _heap = {
        value,
        children: _children,
        parent,
    };
    for (const child of children) {
        const _child = parentHeap(child, _heap);
        _children.push(_child);
    }
    return _heap;
}
exports.parentHeap = parentHeap;
function readHeap(heap) {
    const { value, children } = heap;
    const _children = [];
    const _heap = {
        value,
        children: _children,
    };
    for (const child of children) {
        if (child) {
            const _child = readHeap(child);
            _children.push(_child);
        }
    }
    return _heap;
}
exports.readHeap = readHeap;
function removeHeapNode(heap, predicate) {
    const { value, parent, children } = heap;
    const [first, second] = children;
    heap.parent = null;
    heap.children = [];
    if (parent) {
        const i = +(parent.children[1] === heap);
        if (first && second) {
            first.parent = null;
            second.parent = null;
            if (predicate(first.value, second.value)) {
                parent.children[i] = first;
                first.parent = parent;
                addHeapNode(first, second, predicate);
            }
            else {
                parent.children[i] = second;
                second.parent = parent;
                addHeapNode(second, first, predicate);
            }
        }
        else if (first) {
            parent.children[i] = first;
            first.parent = parent;
        }
        else if (second) {
            parent.children[i] = second;
            second.parent = parent;
        }
        else {
            parent.children[i] = undefined;
        }
        return findRoot(parent);
    }
    else {
        if (first && second) {
            if (predicate(first.value, second.value)) {
                first.parent = null;
                addHeapNode(first, second, predicate);
                return first;
            }
            else {
                second.parent = null;
                addHeapNode(second, first, predicate);
                return second;
            }
        }
        else if (first) {
            first.parent = null;
            return first;
        }
        else if (second) {
            second.parent = null;
            return second;
        }
        else {
            return null;
        }
    }
}
exports.removeHeapNode = removeHeapNode;
function addHeapNode(root, child, predicate) {
    if (root === null) {
        return child;
    }
    const { value, parent, children } = root;
    if (predicate(value, child.value)) {
        const [first, second] = children;
        if (first && second) {
            if (predicate(first.value, second.value)) {
                addHeapNode(first, child, predicate);
            }
            else {
                addHeapNode(second, child, predicate);
            }
        }
        else if (first) {
            children[1] = child;
            child.parent = root;
        }
        else if (second) {
            children[0] = child;
            child.parent = root;
        }
        else {
            children[0] = child;
            child.parent = root;
        }
    }
    else {
        addHeapNode(child, root, predicate);
        if (parent) {
            const i = +(parent.children[1] === root);
            parent.children[i] = undefined;
            addHeapNode(parent, child, predicate);
        }
    }
    return findRoot(root);
}
exports.addHeapNode = addHeapNode;
function setHeapNode(heap, newValue, predicate) {
    const { parent, children } = heap;
    heap.value = newValue;
    const [first, second] = children;
    if (first && second) {
        const p0 = predicate(newValue, first.value);
        const p1 = predicate(newValue, second.value);
        if (p0 && p1) {
            refreshParent(heap, predicate);
        }
        else {
            removeHeapNode(heap, predicate);
            if (p0) {
                addHeapNode(second, heap, predicate);
            }
            else if (p1) {
                addHeapNode(first, heap, predicate);
            }
            else {
                if (predicate(first.value, second.value)) {
                    addHeapNode(first, heap, predicate);
                }
                else {
                    addHeapNode(second, heap, predicate);
                }
            }
        }
    }
    else if (first) {
        if (predicate(newValue, first.value)) {
            refreshParent(heap, predicate);
        }
        else {
            removeHeapNode(heap, predicate);
            addHeapNode(first, heap, predicate);
            refreshParent(first, predicate);
        }
    }
    else if (second) {
        if (predicate(newValue, second.value)) {
            refreshParent(heap, predicate);
        }
        else {
            removeHeapNode(heap, predicate);
            addHeapNode(second, heap, predicate);
            refreshParent(second, predicate);
        }
    }
    else {
        refreshParent(heap, predicate);
    }
    return findRoot(heap);
}
exports.setHeapNode = setHeapNode;
function refreshParent(heap, predicate) {
    const { parent } = heap;
    if (parent) {
        heap.parent = null;
        const i = +(parent.children[1] === heap);
        parent.children[i] = undefined;
        addHeapNode(parent, heap, predicate);
    }
    else {
        //
    }
}
exports.refreshParent = refreshParent;
function findRoot(node) {
    if (node.parent) {
        return findRoot(node.parent);
    }
    else {
        return node;
    }
}
exports.findRoot = findRoot;
//# sourceMappingURL=Heap.js.map