const _scratch_array = [];

/**
 *
 * @param {number} a
 * @param {number} b
 * @param {number[]} lookup
 * @param {number[]} data
 * @returns {number}
 */
function compare_decals(a, b, lookup, data) {
    if (a === b) {
        return 0;
    }

    const a_encoded = lookup[a];
    const b_encoded = lookup[b];

    // mask out bottom 2 type bits
    const a_address = a_encoded & 0xFFFFFFF8;
    const b_address = b_encoded & 0xFFFFFFF8;

    const a_priority = data[a_address + 20];
    const b_priority = data[b_address + 20];

    let diff = b_priority - a_priority;

    if (diff !== 0) {
        return diff;
    }


    const a_id = data[a_address + 21];
    const b_id = data[b_address + 21];

    // data order is explicit and stable, we use that as a secondary comparison criteria
    return b_id - a_id;
}

/**
 * Decals need to be drawn in a specific order to achieve correct blending, for this they need to be sorted
 * @param {number[]|Uint8ClampedArray|Uint8Array|Uint32Array} lookup
 * @param {number[]|Float32Array} data
 * @param {number} offset
 * @param {number} count
 */
export function sort_decal_data(lookup, data, offset, count) {
    const stack = _scratch_array;

    stack[0] = offset;
    stack[1] = offset + count - 1;

    let stackPointer = 2;
    let i, j;

    while (stackPointer > 0) {
        stackPointer -= 2;

        const right = stack[stackPointer + 1];
        const left = stack[stackPointer];

        i = left;
        j = right;

        const pivotIndex = (left + right) >> 1;

        /* partition */
        while (i <= j) {

            while (compare_decals(i, pivotIndex, lookup, data) > 0) {
                i++;
            }

            while (compare_decals(j, pivotIndex, lookup, data) < 0) {
                j--;
            }

            if (i <= j) {

                if (i !== j) {
                    //do swap
                    const swap = lookup[i];
                    lookup[i] = lookup[j]
                    lookup[j] = swap;
                }

                i++;
                j--;
            }
        }

        /* recursion */
        if (left < j) {
            stack[stackPointer++] = left;
            stack[stackPointer++] = j;
        }
        if (i < right) {
            stack[stackPointer++] = i;
            stack[stackPointer++] = right;
        }
    }
}
