// track_topology.cpp — see the header.

#include "core/capture/track_topology.h"

#include <cstddef>

namespace reasampler::capture {

std::vector<int> directChildIndices(const std::vector<int>& folderDepths,
                                    int parentIndex) {
    std::vector<int> children;
    const int count = static_cast<int>(folderDepths.size());
    if (parentIndex < 0 || parentIndex >= count) return children;
    if (folderDepths[static_cast<std::size_t>(parentIndex)] != 1) return children;

    // Depth relative to the parent: 1 immediately after it (inside its folder), and
    // 0 once the folder closes. Only tracks sitting at relative depth 1 are direct
    // children; a child that opens its own folder pushes the level to 2, which is
    // what excludes its descendants.
    int level = 1;
    for (int i = parentIndex + 1; i < count && level > 0; ++i) {
        if (level == 1) children.push_back(i);
        level += folderDepths[static_cast<std::size_t>(i)];
    }
    return children;
}

SiblingPlacement siblingPlacement(const std::vector<int>& folderDepths, int srcIndex) {
    const int count = static_cast<int>(folderDepths.size());
    if (count == 0) return SiblingPlacement{};

    const int src = srcIndex < 0 ? 0 : (srcIndex >= count ? count - 1 : srcIndex);

    // levels[i] is track i's absolute nesting depth; levels[count] is the depth the
    // list closes at (0 in a well-formed project). Negative is unrepresentable, so a
    // malformed over-closing delta clamps here rather than propagating.
    std::vector<int> levels(static_cast<std::size_t>(count) + 1, 0);
    for (int i = 0; i < count; ++i) {
        const int next = levels[static_cast<std::size_t>(i)] +
                         folderDepths[static_cast<std::size_t>(i)];
        levels[static_cast<std::size_t>(i) + 1] = next < 0 ? 0 : next;
    }

    const int L = levels[static_cast<std::size_t>(src)];

    int p = src + 1;
    if (folderDepths[static_cast<std::size_t>(src)] >= 1) {
        p = count;  // an unterminated folder swallows the rest of the list
        for (int j = src + 1; j <= count; ++j) {
            if (levels[static_cast<std::size_t>(j)] == L) { p = j; break; }
        }
    }

    SiblingPlacement out;
    out.insertIndex    = p;
    out.precedingIndex = p - 1;
    out.precedingDepth = L - levels[static_cast<std::size_t>(p - 1)];
    out.newDepth       = levels[static_cast<std::size_t>(p)] - L;
    return out;
}

}  // namespace reasampler::capture
